From 5ac079df5ce0160e1a8485a92f32fb9072406a2f Mon Sep 17 00:00:00 2001 From: mkm <727897186@qq.com> Date: Wed, 10 May 2023 13:38:51 +0800 Subject: [PATCH] init --- .example.env | 1 + .gitignore | 11 + .travis.yml | 42 + .version | 3 + LICENSE.txt | 32 + README.md | 52 + app/.htaccess | 1 + app/AppService.php | 32 + app/ExceptionHandle.php | 86 + app/Request.php | 190 + app/command/ClearCacheAttachment.php | 56 + app/command/ClearMerchantData.php | 66 + app/command/ClearRedundancy.php | 41 + app/command/FormatMenuPath.php | 57 + app/command/VersionUpdate.php | 174 + app/command/changeHotTop.php | 55 + app/command/clearCache.php | 75 + app/command/resetImagePath.php | 196 + app/command/resetPassword.php | 68 + app/command/updateAuth.php | 171 + app/command/updateSpu.php | 67 + app/common.php | 1156 ++++ app/common/dao/BaseDao.php | 310 + app/common/dao/article/ArticleCategoryDao.php | 143 + app/common/dao/article/ArticleContentDao.php | 32 + app/common/dao/article/ArticleDao.php | 192 + .../dao/community/CommunityCategoryDao.php | 28 + app/common/dao/community/CommunityDao.php | 127 + .../dao/community/CommunityReplyDao.php | 60 + .../dao/community/CommunityTopicDao.php | 40 + app/common/dao/delivery/DeliveryOrderDao.php | 23 + .../dao/delivery/DeliveryStationDao.php | 23 + app/common/dao/store/CityAreaDao.php | 67 + app/common/dao/store/ExcelDao.php | 78 + app/common/dao/store/GuaranteeDao.php | 25 + app/common/dao/store/GuaranteeTemplateDao.php | 24 + app/common/dao/store/GuaranteeValueDao.php | 34 + app/common/dao/store/PriceRuleDao.php | 50 + app/common/dao/store/StoreActivityDao.php | 38 + app/common/dao/store/StoreAttrTemplateDao.php | 127 + .../dao/store/StoreBrandCategoryDao.php | 68 + app/common/dao/store/StoreBrandDao.php | 72 + app/common/dao/store/StoreCategoryDao.php | 99 + app/common/dao/store/StorePrinterDao.php | 26 + .../dao/store/StoreSeckillActiveDao.php | 143 + app/common/dao/store/StoreSeckillTimeDao.php | 112 + .../store/broadcast/BroadcastAssistantDao.php | 46 + .../dao/store/broadcast/BroadcastGoodsDao.php | 133 + .../dao/store/broadcast/BroadcastRoomDao.php | 156 + .../store/broadcast/BroadcastRoomGoodsDao.php | 69 + .../dao/store/coupon/StoreCouponDao.php | 342 + .../store/coupon/StoreCouponIssueUserDao.php | 55 + .../store/coupon/StoreCouponProductDao.php | 88 + .../dao/store/coupon/StoreCouponSendDao.php | 47 + .../dao/store/coupon/StoreCouponUserDao.php | 124 + .../store/order/MerchantReconciliationDao.php | 57 + .../order/MerchantReconciliationOrderDao.php | 34 + .../dao/store/order/PresellOrderDao.php | 64 + app/common/dao/store/order/StoreCartDao.php | 160 + .../dao/store/order/StoreCartDao.php.bak | 160 + .../dao/store/order/StoreGroupOrderDao.php | 95 + app/common/dao/store/order/StoreImportDao.php | 33 + .../store/order/StoreImportDeliveryDao.php | 33 + app/common/dao/store/order/StoreOrderDao.php | 737 +++ .../dao/store/order/StoreOrderProductDao.php | 145 + .../order/StoreOrderProfitsharingDao.php | 61 + .../dao/store/order/StoreOrderReceiptDao.php | 100 + .../dao/store/order/StoreOrderStatusDao.php | 71 + .../dao/store/order/StoreRefundOrderDao.php | 161 + .../dao/store/order/StoreRefundProductDao.php | 51 + .../dao/store/order/StoreRefundStatusDao.php | 32 + .../dao/store/parameter/ParameterDao.php | 32 + .../store/parameter/ParameterTemplateDao.php | 26 + .../dao/store/parameter/ParameterValueDao.php | 32 + .../dao/store/product/ProductAssistDao.php | 160 + .../dao/store/product/ProductAssistSetDao.php | 67 + .../dao/store/product/ProductAssistSkuDao.php | 45 + .../store/product/ProductAssistUserDao.php | 33 + .../dao/store/product/ProductAttrDao.php | 47 + .../dao/store/product/ProductAttrValueDao.php | 279 + .../dao/store/product/ProductCateDao.php | 58 + .../dao/store/product/ProductContentDao.php | 38 + .../dao/store/product/ProductCopyDao.php | 47 + app/common/dao/store/product/ProductDao.php | 627 ++ .../store/product/ProductGroupBuyingDao.php | 53 + .../dao/store/product/ProductGroupDao.php | 162 + .../dao/store/product/ProductGroupSkuDao.php | 38 + .../dao/store/product/ProductGroupUserDao.php | 41 + .../dao/store/product/ProductLabelDao.php | 23 + .../dao/store/product/ProductPresellDao.php | 203 + .../store/product/ProductPresellSkuDao.php | 85 + .../dao/store/product/ProductReplyDao.php | 177 + .../dao/store/product/ProductSkuDao.php | 45 + .../dao/store/product/ProductTakeDao.php | 32 + app/common/dao/store/product/SpuDao.php | 207 + app/common/dao/store/product/SpuDao.php.bak | 207 + .../dao/store/product/StoreDiscountDao.php | 56 + .../store/product/StoreDiscountProductDao.php | 33 + .../dao/store/service/StoreServiceDao.php | 199 + .../dao/store/service/StoreServiceLogDao.php | 183 + .../store/service/StoreServiceReplyDao.php | 56 + .../dao/store/service/StoreServiceUserDao.php | 60 + app/common/dao/store/shipping/CityDao.php | 30 + app/common/dao/store/shipping/ExpressDao.php | 72 + .../dao/store/shipping/ExpressPartnerDao.php | 30 + .../store/shipping/ShippingTemplateDao.php | 94 + .../shipping/ShippingTemplateFreeDao.php | 72 + .../shipping/ShippingTemplateRegionDao.php | 72 + .../ShippingTemplateUndeliveryDao.php | 60 + app/common/dao/system/CacheDao.php | 79 + app/common/dao/system/ExtendDao.php | 53 + app/common/dao/system/RelevanceDao.php | 49 + app/common/dao/system/admin/AdminDao.php | 117 + app/common/dao/system/admin/LogDao.php | 60 + .../attachment/AttachmentCategoryDao.php | 183 + .../dao/system/attachment/AttachmentDao.php | 140 + .../system/config/SystemConfigClassifyDao.php | 176 + .../dao/system/config/SystemConfigDao.php | 117 + .../system/config/SystemConfigValueDao.php | 115 + app/common/dao/system/diy/DiyDao.php | 41 + app/common/dao/system/diy/PageCategoryDao.php | 28 + app/common/dao/system/diy/PageLinkDao.php | 27 + .../dao/system/financial/FinancialDao.php | 82 + app/common/dao/system/groupData/GroupDao.php | 114 + .../dao/system/groupData/GroupDataDao.php | 184 + app/common/dao/system/menu/MenuDao.php | 395 ++ app/common/dao/system/menu/RoleDao.php | 106 + .../system/merchant/FinancialRecordDao.php | 114 + .../dao/system/merchant/MerchantAdminDao.php | 218 + .../system/merchant/MerchantAppymentsDao.php | 51 + .../system/merchant/MerchantCategoryDao.php | 82 + .../dao/system/merchant/MerchantDao.php | 298 + .../dao/system/merchant/MerchantDao.php.bak | 294 + .../system/merchant/MerchantIntentionDao.php | 53 + .../dao/system/merchant/MerchantTypeDao.php | 72 + .../system/notice/SystemNoticeConfigDao.php | 66 + .../dao/system/notice/SystemNoticeDao.php | 36 + .../dao/system/notice/SystemNoticeLogDao.php | 81 + app/common/dao/system/serve/ServeMealDao.php | 26 + app/common/dao/system/serve/ServeOrderDao.php | 68 + app/common/dao/system/sms/SmsRecordDao.php | 89 + app/common/dao/user/FeedbackCateoryDao.php | 42 + app/common/dao/user/FeedbackDao.php | 80 + app/common/dao/user/LabelRuleDao.php | 38 + app/common/dao/user/MemberInterestsDao.php | 25 + app/common/dao/user/UserAddressDao.php | 48 + app/common/dao/user/UserBillDao.php | 302 + app/common/dao/user/UserBrokerageDao.php | 46 + app/common/dao/user/UserDao.php | 357 ++ app/common/dao/user/UserExtractDao.php | 56 + app/common/dao/user/UserGroupDao.php | 62 + app/common/dao/user/UserHistoryDao.php | 77 + app/common/dao/user/UserLabelDao.php | 108 + app/common/dao/user/UserMerchantDao.php | 121 + app/common/dao/user/UserOrderDao.php | 68 + app/common/dao/user/UserReceiptDao.php | 52 + app/common/dao/user/UserRechargeDao.php | 90 + app/common/dao/user/UserRelationDao.php | 129 + app/common/dao/user/UserSignDao.php | 27 + app/common/dao/user/UserSpreadLogDao.php | 39 + app/common/dao/user/UserVisitDao.php | 217 + app/common/dao/wechat/RoutineQrcodeDao.php | 108 + app/common/dao/wechat/TemplateMessageDao.php | 45 + app/common/dao/wechat/WechatNewsDao.php | 72 + app/common/dao/wechat/WechatQrcodeDao.php | 87 + app/common/dao/wechat/WechatReplyDao.php | 101 + app/common/dao/wechat/WechatUserDao.php | 178 + app/common/middleware/AdminAuthMiddleware.php | 90 + .../middleware/AdminTokenMiddleware.php | 105 + .../middleware/AllowOriginMiddleware.php | 58 + app/common/middleware/BaseMiddleware.php | 56 + app/common/middleware/BlockerMiddleware.php | 59 + .../middleware/CheckSiteOpenMiddleware.php | 31 + app/common/middleware/InstallMiddleware.php | 35 + app/common/middleware/LogMiddleware.php | 36 + .../middleware/MerchantAuthMiddleware.php | 95 + .../MerchantCheckBaseInfoMiddleware.php | 56 + .../middleware/MerchantServerMiddleware.php | 57 + .../middleware/MerchantTokenMiddleware.php | 121 + .../middleware/RequestLockMiddleware.php | 35 + .../middleware/ServiceTokenMiddleware.php | 110 + app/common/middleware/UserTokenMiddleware.php | 105 + .../middleware/VisitProductMiddleware.php | 55 + app/common/model/BaseModel.php | 74 + app/common/model/article/Article.php | 65 + app/common/model/article/ArticleCategory.php | 41 + app/common/model/article/ArticleContent.php | 41 + app/common/model/community/Community.php | 174 + .../model/community/CommunityCategory.php | 68 + app/common/model/community/CommunityReply.php | 108 + app/common/model/community/CommunityTopic.php | 75 + app/common/model/delivery/DeliveryOrder.php | 106 + app/common/model/delivery/DeliveryStation.php | 87 + app/common/model/store/CityArea.php | 46 + app/common/model/store/Excel.php | 76 + app/common/model/store/GeoArea.php | 31 + app/common/model/store/Guarantee.php | 63 + app/common/model/store/GuaranteeTemplate.php | 73 + app/common/model/store/GuaranteeValue.php | 54 + app/common/model/store/PriceRule.php | 39 + app/common/model/store/StoreActivity.php | 109 + app/common/model/store/StoreAttrTemplate.php | 69 + app/common/model/store/StoreBrand.php | 46 + app/common/model/store/StoreBrandCategory.php | 52 + app/common/model/store/StoreCategory.php | 98 + app/common/model/store/StorePrinter.php | 43 + app/common/model/store/StoreSeckillActive.php | 46 + app/common/model/store/StoreSeckillTime.php | 69 + .../store/broadcast/BroadcastAssistant.php | 59 + .../model/store/broadcast/BroadcastGoods.php | 59 + .../model/store/broadcast/BroadcastRoom.php | 58 + .../store/broadcast/BroadcastRoomGoods.php | 41 + app/common/model/store/coupon/StoreCoupon.php | 105 + .../store/coupon/StoreCouponIssueUser.php | 42 + .../model/store/coupon/StoreCouponProduct.php | 47 + .../model/store/coupon/StoreCouponSend.php | 61 + .../model/store/coupon/StoreCouponUser.php | 69 + .../store/order/MerchantReconciliation.php | 56 + .../order/MerchantReconciliationOrder.php | 38 + app/common/model/store/order/PresellOrder.php | 98 + app/common/model/store/order/StoreCart.php | 340 + .../model/store/order/StoreCart.php.bak | 335 + .../model/store/order/StoreGroupOrder.php | 107 + app/common/model/store/order/StoreImport.php | 51 + .../model/store/order/StoreImportDelivery.php | 46 + app/common/model/store/order/StoreOrder.php | 180 + .../model/store/order/StoreOrderProduct.php | 80 + .../store/order/StoreOrderProfitsharing.php | 82 + .../model/store/order/StoreOrderReceipt.php | 68 + .../model/store/order/StoreOrderStatus.php | 47 + .../model/store/order/StoreRefundOrder.php | 88 + .../model/store/order/StoreRefundProduct.php | 41 + .../model/store/order/StoreRefundStatus.php | 31 + .../model/store/parameter/Parameter.php | 36 + .../store/parameter/ParameterTemplate.php | 85 + .../model/store/parameter/ParameterValue.php | 35 + app/common/model/store/product/Product.php | 556 ++ .../model/store/product/ProductAssist.php | 161 + .../model/store/product/ProductAssistSet.php | 158 + .../model/store/product/ProductAssistSku.php | 60 + .../model/store/product/ProductAssistUser.php | 78 + .../model/store/product/ProductAttr.php | 63 + .../model/store/product/ProductAttrValue.php | 108 + .../model/store/product/ProductCate.php | 51 + .../model/store/product/ProductContent.php | 45 + .../model/store/product/ProductCopy.php | 57 + .../model/store/product/ProductGroup.php | 156 + .../store/product/ProductGroupBuying.php | 97 + .../model/store/product/ProductGroupSku.php | 67 + .../model/store/product/ProductGroupUser.php | 80 + .../model/store/product/ProductLabel.php | 58 + .../model/store/product/ProductPresell.php | 157 + .../model/store/product/ProductPresellSku.php | 78 + .../model/store/product/ProductReply.php | 89 + app/common/model/store/product/ProductSku.php | 62 + .../model/store/product/ProductTake.php | 76 + app/common/model/store/product/Spu.php | 239 + app/common/model/store/product/Spu.php.bak | 233 + .../store/product/StoreDiscountProduct.php | 43 + .../model/store/product/StoreDiscounts.php | 106 + .../model/store/service/StoreService.php | 43 + .../model/store/service/StoreServiceLog.php | 88 + .../model/store/service/StoreServiceReply.php | 37 + .../model/store/service/StoreServiceUser.php | 61 + app/common/model/store/shipping/City.php | 41 + app/common/model/store/shipping/Express.php | 46 + .../model/store/shipping/ExpressPartner.php | 52 + .../model/store/shipping/ShippingTemplate.php | 102 + .../store/shipping/ShippingTemplateFree.php | 68 + .../store/shipping/ShippingTemplateRegion.php | 67 + .../shipping/ShippingTemplateUndelivery.php | 68 + app/common/model/system/Cache.php | 70 + app/common/model/system/Extend.php | 48 + app/common/model/system/Relevance.php | 109 + app/common/model/system/admin/Admin.php | 79 + app/common/model/system/admin/Log.php | 41 + .../model/system/attachment/Attachment.php | 49 + .../system/attachment/AttachmentCategory.php | 40 + app/common/model/system/auth/Menu.php | 52 + app/common/model/system/auth/Role.php | 68 + .../model/system/config/SystemConfig.php | 58 + .../system/config/SystemConfigClassify.php | 79 + .../model/system/config/SystemConfigValue.php | 68 + app/common/model/system/diy/Diy.php | 55 + app/common/model/system/diy/PageCategory.php | 47 + app/common/model/system/diy/PageLink.php | 47 + .../model/system/financial/Financial.php | 94 + .../model/system/groupData/SystemGroup.php | 68 + .../system/groupData/SystemGroupData.php | 57 + .../model/system/merchant/FinancialRecord.php | 53 + app/common/model/system/merchant/Merchant.php | 234 + .../model/system/merchant/Merchant.php.bak | 234 + .../model/system/merchant/MerchantAdmin.php | 76 + .../system/merchant/MerchantApplyments.php | 76 + .../system/merchant/MerchantCategory.php | 47 + .../system/merchant/MerchantIntention.php | 58 + .../model/system/merchant/MerchantType.php | 38 + .../model/system/notice/SystemNotice.php | 32 + .../system/notice/SystemNoticeConfig.php | 73 + .../model/system/notice/SystemNoticeLog.php | 57 + app/common/model/system/serve/ServeMeal.php | 50 + app/common/model/system/serve/ServeOrder.php | 84 + app/common/model/system/sms/SmsRecord.php | 41 + app/common/model/user/FeedBackCategory.php | 30 + app/common/model/user/Feedback.php | 55 + app/common/model/user/LabelRule.php | 36 + app/common/model/user/MemberInterests.php | 61 + app/common/model/user/User.php | 326 + app/common/model/user/UserAddress.php | 47 + app/common/model/user/UserBill.php | 47 + app/common/model/user/UserBrokerage.php | 51 + app/common/model/user/UserExtract.php | 46 + app/common/model/user/UserGroup.php | 41 + app/common/model/user/UserHistory.php | 72 + app/common/model/user/UserLabel.php | 41 + app/common/model/user/UserMerchant.php | 79 + app/common/model/user/UserOrder.php | 36 + app/common/model/user/UserReceipt.php | 67 + app/common/model/user/UserRecharge.php | 71 + app/common/model/user/UserRelation.php | 48 + app/common/model/user/UserSign.php | 46 + app/common/model/user/UserSpreadLog.php | 35 + app/common/model/user/UserVisit.php | 42 + app/common/model/wechat/RoutineQrcode.php | 31 + app/common/model/wechat/TemplateMessage.php | 31 + app/common/model/wechat/WechatNews.php | 81 + app/common/model/wechat/WechatQrcode.php | 57 + app/common/model/wechat/WechatReply.php | 69 + app/common/model/wechat/WechatUser.php | 41 + app/common/repositories/BaseRepository.php | 35 + .../article/ArticleCategoryRepository.php | 118 + .../article/ArticleContentRepository.php | 26 + .../article/ArticleRepository.php | 79 + .../community/CommunityCategoryRepository.php | 112 + .../community/CommunityReplyRepository.php | 204 + .../community/CommunityRepository.php | 510 ++ .../community/CommunityTopicRepository.php | 129 + .../delivery/DeliveryOrderRepository.php | 508 ++ .../delivery/DeliveryStationRepository.php | 236 + .../repositories/store/CityAreaRepository.php | 63 + .../repositories/store/ExcelRepository.php | 110 + .../store/GuaranteeRepository.php | 134 + .../store/GuaranteeTemplateRepository.php | 161 + .../store/GuaranteeValueRepository.php | 34 + .../repositories/store/IntegralRepository.php | 48 + .../store/MerchantTakeRepository.php | 38 + .../store/PriceRuleRepository.php | 89 + .../store/StoreActivityRepository.php | 189 + .../store/StoreAttrTemplateRepository.php | 124 + .../store/StoreBrandCategoryRepository.php | 102 + .../store/StoreBrandRepository.php | 128 + .../store/StoreCategoryRepository.php | 156 + .../store/StoreCategoryRepository.php.bak | 140 + .../store/StorePrinterRepository.php | 122 + .../store/StoreSeckillActiveRepository.php | 50 + .../store/StoreSeckillTimeRepository.php | 138 + .../BroadcastAssistantRepository.php | 72 + .../broadcast/BroadcastGoodsRepository.php | 337 + .../BroadcastRoomGoodsRepository.php | 33 + .../broadcast/BroadcastRoomRepository.php | 500 ++ .../coupon/StoreCouponIssueUserRepository.php | 53 + .../coupon/StoreCouponProductRepository.php | 49 + .../store/coupon/StoreCouponRepository.php | 665 ++ .../coupon/StoreCouponSendRepository.php | 105 + .../coupon/StoreCouponUserRepository.php | 108 + .../MerchantReconciliationOrderRepository.php | 29 + .../MerchantReconciliationRepository.php | 316 + .../store/order/PresellOrderRepository.php | 358 ++ .../store/order/StoreCartRepository.php | 130 + .../store/order/StoreCartRepository.php.bak | 130 + .../store/order/StoreGroupOrderRepository.php | 179 + .../order/StoreImportDeliveryRepository.php | 37 + .../store/order/StoreImportRepository.php | 51 + .../order/StoreOrderCreateRepository.php | 1360 ++++ .../order/StoreOrderCreateRepository.php.bak | 1360 ++++ .../order/StoreOrderProductRepository.php | 48 + .../StoreOrderProfitsharingRepository.php | 104 + .../order/StoreOrderReceiptRepository.php | 223 + .../store/order/StoreOrderRepository.php | 2407 +++++++ .../store/order/StoreOrderRepository.php.bak | 2280 +++++++ .../store/order/StoreOrderSplitRepository.php | 228 + .../order/StoreOrderStatusRepository.php | 174 + .../order/StoreRefundOrderRepository.php | 1576 +++++ .../order/StoreRefundProductRepository.php | 37 + .../order/StoreRefundStatusRepository.php | 72 + .../store/parameter/ParameterRepository.php | 80 + .../parameter/ParameterTemplateRepository.php | 175 + .../parameter/ParameterValueRepository.php | 56 + .../store/product/ProductAssistRepository.php | 513 ++ .../product/ProductAssistSetRepository.php | 291 + .../product/ProductAssistSkuRepository.php | 25 + .../product/ProductAssistUserRepository.php | 34 + .../store/product/ProductAttrRepository.php | 34 + .../product/ProductAttrValueRepository.php | 84 + .../store/product/ProductCateRepository.php | 34 + .../product/ProductContentRepository.php | 34 + .../store/product/ProductCopyRepository.php | 333 + .../product/ProductGroupBuyingRepository.php | 349 ++ .../store/product/ProductGroupRepository.php | 497 ++ .../product/ProductGroupSkuRepository.php | 34 + .../product/ProductGroupUserRepository.php | 114 + .../store/product/ProductLabelRepository.php | 134 + .../product/ProductPresellRepository.php | 546 ++ .../product/ProductPresellSkuRepository.php | 25 + .../store/product/ProductReplyRepository.php | 276 + .../store/product/ProductRepository.php | 2216 +++++++ .../store/product/ProductRepository.php.bak | 2215 +++++++ .../store/product/ProductSkuRepository.php | 46 + .../store/product/ProductTakeRepository.php | 24 + .../store/product/SpuRepository.php | 532 ++ .../store/product/SpuRepository.php.bak | 531 ++ .../StoreDiscountProductRepository.php | 25 + .../store/product/StoreDiscountRepository.php | 285 + .../service/StoreServiceLogRepository.php | 251 + .../service/StoreServiceReplyRepository.php | 53 + .../store/service/StoreServiceRepository.php | 268 + .../service/StoreServiceUserRepository.php | 144 + .../store/shipping/CityRepository.php | 39 + .../shipping/ExpressPartnerRepository.php | 34 + .../store/shipping/ExpressRepository.php | 250 + .../ShippingTemplateFreeRepository.php | 75 + .../ShippingTemplateRegionRepository.php | 77 + .../shipping/ShippingTemplateRepository.php | 270 + .../ShippingTemplateUndeliveRepository.php | 64 + .../repositories/system/CacheRepository.php | 276 + .../repositories/system/ExtendRepository.php | 54 + .../system/RelevanceRepository.php | 276 + .../system/admin/AdminLogRepository.php | 106 + .../system/admin/AdminRepository.php | 327 + .../AttachmentCategoryRepository.php | 172 + .../attachment/AttachmentRepository.php | 121 + .../system/auth/MenuRepository.php | 343 + .../system/auth/RoleRepository.php | 135 + .../config/ConfigClassifyRepository.php | 142 + .../system/config/ConfigRepository.php | 475 ++ .../system/config/ConfigValueRepository.php | 165 + .../repositories/system/diy/DiyRepository.php | 253 + .../system/diy/PageCategoryRepository.php | 88 + .../system/diy/PageLinkRepository.php | 86 + .../system/financial/FinancialRepository.php | 689 +++ .../system/groupData/GroupDataRepository.php | 386 ++ .../system/groupData/GroupRepository.php | 214 + .../merchant/FinancialRecordRepository.php | 639 ++ .../merchant/MerchantAdminRepository.php | 382 ++ .../merchant/MerchantApplymentsRepository.php | 570 ++ .../merchant/MerchantCategoryRepository.php | 121 + .../merchant/MerchantIntentionRepository.php | 187 + .../MerchantIntentionRepository.php.bak | 166 + .../system/merchant/MerchantRepository.php | 646 ++ .../merchant/MerchantRepository.php.bak | 621 ++ .../merchant/MerchantTypeRepository.php | 143 + .../notice/SystemNoticeConfigRepository.php | 278 + .../notice/SystemNoticeLogRepository.php | 42 + .../system/notice/SystemNoticeRepository.php | 79 + .../system/serve/ServeMealRepository.php | 90 + .../system/serve/ServeOrderRepository.php | 234 + .../system/sms/SmsRecordRepository.php | 73 + .../user/FeedBackCategoryRepository.php | 62 + .../repositories/user/FeedbackRepository.php | 75 + .../repositories/user/LabelRuleRepository.php | 144 + .../user/MemberinterestsRepository.php | 149 + .../user/UserAddressRepository.php | 120 + .../repositories/user/UserBillRepository.php | 266 + .../user/UserBrokerageRepository.php | 259 + .../user/UserExtractRepository.php | 195 + .../repositories/user/UserGroupRepository.php | 100 + .../user/UserHistoryRepository.php | 124 + .../repositories/user/UserLabelRepository.php | 100 + .../user/UserMerchantRepository.php | 131 + .../repositories/user/UserOrderRepository.php | 171 + .../user/UserReceiptRepository.php | 47 + .../user/UserRechargeRepository.php | 133 + .../user/UserRelationRepository.php | 257 + .../repositories/user/UserRepository.php | 1475 +++++ .../repositories/user/UserSignRepository.php | 209 + .../user/UserSpreadLogRepository.php | 39 + .../repositories/user/UserVisitRepository.php | 80 + .../repositories/wechat/CustomTemplate.php | 22 + .../wechat/RoutineQrcodeRepository.php | 71 + .../wechat/TemplateMessageRepository.php | 239 + .../wechat/WechatNewsRepository.php | 111 + .../wechat/WechatQrcodeRepository.php | 131 + .../wechat/WechatReplyRepository.php | 256 + .../wechat/WechatUserRepository.php | 331 + app/controller/Install.php | 854 +++ app/controller/View.php | 37 + app/controller/WechatNotice.php | 43 + app/controller/admin/Common.php | 447 ++ app/controller/admin/article/Article.php | 148 + .../admin/article/ArticleCategory.php | 194 + app/controller/admin/community/Community.php | 131 + .../admin/community/CommunityCategory.php | 137 + .../admin/community/CommunityReply.php | 86 + .../admin/community/CommunityTopic.php | 141 + .../admin/delivery/DeliveryOrder.php | 49 + .../admin/delivery/DeliveryStation.php | 107 + app/controller/admin/order/Order.php | 204 + .../admin/order/OrderProfitsharing.php | 68 + app/controller/admin/order/Reconciliation.php | 92 + app/controller/admin/order/RefundOrder.php | 85 + .../admin/parameter/ParameterTemplate.php | 147 + app/controller/admin/store/BroadcastGoods.php | 91 + app/controller/admin/store/BroadcastRoom.php | 140 + app/controller/admin/store/CityArea.php | 103 + app/controller/admin/store/Coupon.php | 272 + app/controller/admin/store/Discounts.php | 59 + app/controller/admin/store/Express.php | 201 + app/controller/admin/store/Guarantee.php | 119 + app/controller/admin/store/PriceRule.php | 84 + app/controller/admin/store/ProductLabel.php | 100 + app/controller/admin/store/StoreBrand.php | 140 + .../admin/store/StoreBrandCategory.php | 136 + app/controller/admin/store/StoreCategory.php | 249 + app/controller/admin/store/StoreProduct.php | 303 + .../admin/store/StoreProductAssist.php | 138 + .../admin/store/StoreProductAssistSet.php | 67 + .../admin/store/StoreProductGroup.php | 132 + .../admin/store/StoreProductGroupBuying.php | 64 + .../admin/store/StoreProductPresell.php | 130 + .../admin/store/StoreProductReply.php | 162 + .../admin/store/StoreProductSeckill.php | 174 + app/controller/admin/store/StoreSeckill.php | 155 + app/controller/admin/store/StoreService.php | 84 + .../admin/store/marketing/StoreAtmosphere.php | 176 + .../admin/store/marketing/StoreBorder.php | 170 + app/controller/admin/system/Cache.php | 88 + app/controller/admin/system/admin/Admin.php | 264 + .../admin/system/admin/AdminLog.php | 48 + app/controller/admin/system/admin/Login.php | 118 + .../admin/system/attachment/Attachment.php | 188 + .../system/attachment/AttachmentCategory.php | 166 + app/controller/admin/system/auth/Menu.php | 207 + app/controller/admin/system/auth/Role.php | 174 + app/controller/admin/system/config/Config.php | 338 + .../admin/system/config/ConfigClassify.php | 219 + .../admin/system/config/ConfigOthers.php | 250 + .../admin/system/config/ConfigValue.php | 66 + app/controller/admin/system/diy/Diy.php | 317 + .../admin/system/diy/PageCategroy.php | 104 + app/controller/admin/system/diy/PageLink.php | 147 + .../admin/system/diy/VisualConfig.php | 40 + .../admin/system/financial/Financial.php | 157 + .../admin/system/groupData/Group.php | 166 + .../admin/system/groupData/GroupData.php | 175 + .../admin/system/merchant/FinancialRecord.php | 153 + .../admin/system/merchant/Merchant.php | 311 + .../admin/system/merchant/Merchant.php.bak | 300 + .../admin/system/merchant/MerchantAdmin.php | 85 + .../system/merchant/MerchantApplyments.php | 80 + .../system/merchant/MerchantCategory.php | 161 + .../system/merchant/MerchantIntention.php | 119 + .../admin/system/merchant/MerchantMargin.php | 77 + .../admin/system/merchant/MerchantType.php | 104 + .../admin/system/notice/SystemNotice.php | 72 + .../system/notice/SystemNoticeConfig.php | 150 + .../admin/system/safety/Database.php | 157 + app/controller/admin/system/serve/Config.php | 85 + app/controller/admin/system/serve/Export.php | 81 + app/controller/admin/system/serve/Login.php | 117 + app/controller/admin/system/serve/Serve.php | 256 + app/controller/admin/system/serve/Sms.php | 94 + .../admin/system/service/StoreService.php | 252 + app/controller/admin/system/sms/Sms.php | 212 + app/controller/admin/system/sms/SmsPay.php | 97 + .../admin/system/sms/SmsTemplate.php | 144 + app/controller/admin/user/FeedBack.php | 102 + .../admin/user/FeedBackCategory.php | 124 + app/controller/admin/user/MemberInterests.php | 124 + app/controller/admin/user/Svip.php | 194 + app/controller/admin/user/User.php | 594 ++ app/controller/admin/user/UserBill.php | 53 + app/controller/admin/user/UserBrokerage.php | 126 + app/controller/admin/user/UserExtract.php | 82 + app/controller/admin/user/UserGroup.php | 152 + app/controller/admin/user/UserIntegral.php | 91 + app/controller/admin/user/UserLabel.php | 160 + app/controller/admin/user/UserRecharge.php | 47 + .../admin/wechat/TemplateMessage.php | 195 + app/controller/admin/wechat/WechatGroup.php | 113 + app/controller/admin/wechat/WechatMenu.php | 63 + app/controller/admin/wechat/WechatNews.php | 104 + app/controller/admin/wechat/WechatReply.php | 204 + app/controller/admin/wechat/WechatTag.php | 112 + app/controller/admin/wechat/WechatUser.php | 181 + app/controller/api/Auth.php | 721 +++ app/controller/api/Common.php | 494 ++ app/controller/api/Common.php.bak | 477 ++ app/controller/api/Wechat.php | 28 + app/controller/api/article/Article.php | 61 + .../api/article/ArticleCategory.php | 48 + app/controller/api/community/Community.php | 428 ++ .../api/community/CommunityCategory.php | 51 + .../api/community/CommunityReply.php | 124 + .../api/server/ShippingTemplate.php | 136 + app/controller/api/server/StoreCategory.php | 170 + app/controller/api/server/StoreOrder.php | 342 + app/controller/api/server/StoreOrder.php.bak | 336 + app/controller/api/server/StoreProduct.php | 211 + .../api/server/StoreProduct.php.bak | 206 + .../api/server/StoreProductAttrTemplate.php | 96 + .../api/server/StoreRefundOrder.php | 99 + .../api/store/broadcast/BroadcastRoom.php | 47 + .../api/store/merchant/Merchant.php | 317 + .../api/store/merchant/Merchant.php.bak | 122 + .../api/store/merchant/MerchantIntention.php | 152 + .../store/merchant/MerchantIntention.php.bak | 139 + .../api/store/order/PresellOrder.php | 65 + app/controller/api/store/order/StoreCart.php | 270 + .../api/store/order/StoreCart.php.bak | 271 + .../api/store/order/StoreMicropayOrder.php | 179 + app/controller/api/store/order/StoreOrder.php | 299 + .../api/store/order/StoreOrder.php.bak | 298 + .../api/store/order/StoreOrderVerify.php | 49 + .../api/store/order/StoreRefundOrder.php | 216 + .../api/store/product/Discounts.php | 55 + .../api/store/product/StoreBrand.php | 49 + .../api/store/product/StoreCategory.php | 74 + .../api/store/product/StoreCoupon.php | 153 + .../api/store/product/StoreMicro.php | 57 + .../api/store/product/StoreProduct.php | 197 + .../api/store/product/StoreProduct.php.bak | 196 + .../api/store/product/StoreProductAssist.php | 50 + .../store/product/StoreProductAssistSet.php | 116 + .../api/store/product/StoreProductGroup.php | 87 + .../api/store/product/StoreProductPresell.php | 57 + .../api/store/product/StoreProductSeckill.php | 86 + .../api/store/product/StoreReply.php | 79 + app/controller/api/store/product/StoreSpu.php | 288 + app/controller/api/store/service/Service.php | 207 + app/controller/api/user/Admin.php | 247 + app/controller/api/user/FeedBackCategory.php | 34 + app/controller/api/user/Feedback.php | 67 + app/controller/api/user/Member.php | 40 + app/controller/api/user/Svip.php | 168 + app/controller/api/user/User.php | 531 ++ app/controller/api/user/UserAddress.php | 155 + app/controller/api/user/UserExtract.php | 77 + app/controller/api/user/UserHistory.php | 70 + app/controller/api/user/UserReceipt.php | 123 + app/controller/api/user/UserRecharge.php | 87 + app/controller/api/user/UserRelation.php | 123 + app/controller/api/user/UserSign.php | 66 + app/controller/merchant/Common.php | 282 + app/controller/merchant/store/Excel.php | 80 + .../merchant/store/StoreAttrTemplate.php | 134 + app/controller/merchant/store/StoreImport.php | 141 + .../merchant/store/StoreImport.php.bak | 120 + .../merchant/store/StorePrinter.php | 122 + .../merchant/store/StoreProductReply.php | 42 + .../store/broadcast/BroadcastAssistant.php | 84 + .../store/broadcast/BroadcastGoods.php | 118 + .../store/broadcast/BroadcastRoom.php | 196 + .../merchant/store/coupon/Coupon.php | 239 + .../merchant/store/coupon/CouponSend.php | 37 + .../merchant/store/delivery/DeliveryOrder.php | 75 + .../store/delivery/DeliveryStation.php | 193 + .../store/guarantee/GuaranteeTemplate.php | 134 + app/controller/merchant/store/order/Order.php | 458 ++ .../merchant/store/order/OrderReceipt.php | 139 + .../merchant/store/order/Reconciliation.php | 74 + .../merchant/store/order/RefundOrder.php | 212 + .../merchant/store/product/Discounts.php | 133 + .../merchant/store/product/Product.php | 395 ++ .../merchant/store/product/Product.php.bak | 381 ++ .../merchant/store/product/ProductAssist.php | 167 + .../store/product/ProductAssistSet.php | 70 + .../merchant/store/product/ProductCopy.php | 90 + .../merchant/store/product/ProductGroup.php | 155 + .../store/product/ProductGroupBuying.php | 66 + .../merchant/store/product/ProductLabel.php | 109 + .../merchant/store/product/ProductPresell.php | 177 + .../merchant/store/product/ProductSeckill.php | 266 + .../merchant/store/service/StoreService.php | 292 + .../store/service/StoreServiceReply.php | 92 + .../merchant/store/shipping/City.php | 75 + .../store/shipping/ShippingTemplate.php | 137 + .../store/shipping/ShippingTemplateFree.php | 49 + .../store/shipping/ShippingTemplateRegion.php | 49 + .../shipping/ShippingTemplateUndelive.php | 49 + app/controller/merchant/system/Merchant.php | 201 + .../merchant/system/MerchantApplyments.php | 137 + .../merchant/system/admin/Login.php | 121 + .../merchant/system/admin/MerchantAdmin.php | 288 + app/controller/merchant/system/auth/Role.php | 155 + .../merchant/system/financial/Financial.php | 171 + .../system/notice/SystemNoticeLog.php | 80 + .../merchant/system/serve/Config.php | 89 + .../merchant/system/serve/Serve.php | 85 + app/controller/merchant/user/LabelRule.php | 97 + app/controller/merchant/user/User.php | 38 + app/controller/merchant/user/UserIntegral.php | 71 + app/controller/merchant/user/UserMerchant.php | 119 + app/controller/service/Common.php | 41 + app/controller/service/Login.php | 132 + app/controller/service/Service.php | 105 + app/event.php | 70 + app/event.php.bak | 67 + app/middleware.php | 20 + app/provider.php | 21 + app/service.php | 20 + app/validate/admin/AdminEditValidate.php | 28 + app/validate/admin/AdminValidate.php | 52 + .../admin/ArticleCategoryValidate.php | 31 + app/validate/admin/ArticleValidate.php | 31 + .../admin/AttachmentCategoryValidate.php | 29 + app/validate/admin/AttachmentValidate.php | 28 + app/validate/admin/CommunityTopicValidate.php | 29 + app/validate/admin/ConfigClassifyValidate.php | 32 + app/validate/admin/ConfigValidate.php | 35 + app/validate/admin/CrmebServeValidata.php | 54 + app/validate/admin/ExpressValidata.php | 49 + app/validate/admin/GroupDataValidate.php | 27 + app/validate/admin/GroupValidate.php | 31 + .../admin/GuaranteeTemplateValidate.php | 27 + app/validate/admin/GuaranteeValidate.php | 28 + app/validate/admin/IntegralConfigValidate.php | 31 + app/validate/admin/LoginValidate.php | 27 + app/validate/admin/MealValidata.php | 53 + app/validate/admin/MenuValidate.php | 38 + .../admin/MerchantCategoryValidate.php | 27 + app/validate/admin/MerchantTypeValidate.php | 30 + app/validate/admin/MerchantValidate.php | 66 + .../admin/ParameterTemplateValidate.php | 28 + app/validate/admin/PriceRuleValidate.php | 29 + app/validate/admin/ProductLabelValidate.php | 28 + app/validate/admin/RoleValidate.php | 28 + app/validate/admin/SmsRegisterValidate.php | 45 + app/validate/admin/StoreActivityValidate.php | 36 + .../admin/StoreBrandCategoryValidate.php | 29 + app/validate/admin/StoreBrandValidate.php | 30 + app/validate/admin/StoreCategoryValidate.php | 30 + .../admin/StoreProductReplyValidate.php | 33 + app/validate/admin/StoreSeckillValidate.php | 28 + .../admin/SystemNoticeConfigValidate.php | 33 + app/validate/admin/SystemNoticeValidate.php | 31 + .../admin/TemplateMessageValidate.php | 28 + app/validate/admin/UserBrokerageValidate.php | 56 + app/validate/admin/UserGroupValidate.php | 26 + app/validate/admin/UserLabelValidate.php | 26 + app/validate/admin/UserNowMoneyValidate.php | 27 + app/validate/admin/UserValidate.php | 61 + app/validate/admin/WechatNewsValidate.php | 51 + app/validate/admin/WechatReplyValidate.php | 52 + app/validate/api/BackGoodsValidate.php | 30 + app/validate/api/ChangePasswordValidate.php | 28 + app/validate/api/CommunityValidate.php | 28 + app/validate/api/FeedbackValidate.php | 36 + .../api/MerchantIntentionValidate.php | 31 + .../api/OrderVirtualFieldValidate.php | 103 + app/validate/api/ProductReplyValidate.php | 34 + app/validate/api/StoreCartValidate.php | 27 + app/validate/api/StoreRefundOrderValidate.php | 33 + app/validate/api/UserAddressValidate.php | 41 + app/validate/api/UserAuthValidate.php | 44 + app/validate/api/UserBaseInfoValidate.php | 30 + app/validate/api/UserExtractValidate.php | 31 + app/validate/api/UserReceiptValidate.php | 34 + .../merchant/BroadcastGoodsValidate.php | 35 + .../merchant/BroadcastRoomValidate.php | 52 + .../merchant/DeliveryStationValidate.php | 45 + app/validate/merchant/LabelRuleValidate.php | 33 + .../merchant/MerchantApplymentsValidate.php | 297 + .../MerchantFinancialAccountValidate.php | 50 + .../merchant/MerchantTakeValidate.php | 31 + .../merchant/MerchantUpdateValidate.php | 40 + .../merchant/ServiceReplyValidate.php | 42 + .../merchant/ShippingTemplateValidate.php | 70 + .../merchant/StoreAttrTemplateValidate.php | 27 + .../merchant/StoreCouponSendValidate.php | 29 + app/validate/merchant/StoreCouponValidate.php | 49 + .../merchant/StoreDiscountsValidate.php | 35 + .../merchant/StoreProductAdminValidate.php | 29 + .../merchant/StoreProductAssistValidate.php | 49 + .../merchant/StoreProductGroupValidate.php | 34 + .../merchant/StoreProductPresellValidate.php | 52 + .../merchant/StoreProductValidate.php | 83 + .../merchant/StoreProductValidate.php.bak | 83 + .../merchant/StoreSeckillProductValidate.php | 72 + .../merchant/StoreServiceValidate.php | 52 + app/view/install/step1.html | 119 + app/view/install/step2.html | 157 + app/view/install/step3.html | 234 + app/view/install/step4.html | 77 + app/view/install/step5.html | 53 + app/view/mobile/view.html | 23 + app/webscoket/Manager.php | 234 + app/webscoket/Ping.php | 108 + app/webscoket/SwooleWorkerStart.php | 96 + app/webscoket/handler/AdminHandler.php | 98 + app/webscoket/handler/MerchantHandler.php | 108 + app/webscoket/handler/ServiceHandler.php | 201 + app/webscoket/handler/UserHandler.php | 325 + backup/.gitignore | 2 + cert_crmeb.key | 1 + cert_public.pam | 6 + composer.json | 81 + composer.lock | 5503 +++++++++++++++++ config/admin.php | 30 + config/ajcaptcha.php | 56 + config/app.php | 47 + config/cache.php | 62 + config/console.php | 41 + config/cookie.php | 28 + config/crmeb.php | Bin 0 -> 4560 bytes config/database.php | 73 + config/delivery.php | 24 + config/filesystem.php | 34 + config/lang.php | 35 + config/log.php | 56 + config/middleware.php | 18 + config/notice.php | 119 + config/qrcode.php | 15 + config/queue.php | 38 + config/route.php | 55 + config/session.php | 29 + config/sms.php | 144 + config/swoole.php | 116 + config/template.php | 76 + config/trace.php | 20 + config/upload.php | 40 + config/view.php | 35 + crmeb/basic/BaseAuth.php | Bin 0 -> 89208 bytes crmeb/basic/BaseController.php | Bin 0 -> 27824 bytes crmeb/basic/BaseManager.php | Bin 0 -> 46408 bytes crmeb/basic/BaseMessage.php | Bin 0 -> 23104 bytes crmeb/basic/BaseStorage.php | Bin 0 -> 9768 bytes crmeb/basic/BaseUpload.php | Bin 0 -> 48176 bytes crmeb/exceptions/AuthException.php | 25 + crmeb/exceptions/SmsException.php | 22 + crmeb/exceptions/UploadException.php | 35 + crmeb/exceptions/UploadFailException.php | 26 + crmeb/exceptions/WechatException.php | 23 + crmeb/interfaces/DeliveryInterface.php | 31 + crmeb/interfaces/JobInterface.php | 22 + crmeb/interfaces/ListenerInterface.php | 20 + crmeb/interfaces/MiddlewareInterface.php | 23 + crmeb/interfaces/RouteParserInterface.php | 20 + crmeb/interfaces/VersionUpdateInterface.php | 41 + crmeb/jobs/ApplyBroadcastGoodsJob.php | 50 + crmeb/jobs/AutoChangeStatusActivityJob.php | 53 + crmeb/jobs/AutoUserPosterJob.php | 43 + crmeb/jobs/BatchDeliveryJob.php | 37 + crmeb/jobs/CancelGroupBuyingJob.php | 38 + crmeb/jobs/CancelGroupOrderJob.php | 58 + crmeb/jobs/ChangeMerchantStatusJob.php | 42 + crmeb/jobs/ChangeSpuStatusJob.php | 44 + crmeb/jobs/CheckProductExtensionJob.php | 39 + crmeb/jobs/CheckProductPresellJob.php | 40 + crmeb/jobs/ClearCacheJob.php | 40 + crmeb/jobs/ClearMerchantStoreJob.php | 37 + crmeb/jobs/ClearUserIntegralJob.php | 56 + crmeb/jobs/CloseSvipCouponJob.php | 40 + crmeb/jobs/CloseUserSvipJob.php | 40 + crmeb/jobs/ExpressSyncJob.php | 37 + crmeb/jobs/GauaranteeCountJob.php | 37 + crmeb/jobs/ImportSpreadsheetExcelJob.php | 37 + crmeb/jobs/MerchantSendCouponJob.php | 68 + crmeb/jobs/OrderProfitsharingJob.php | 43 + crmeb/jobs/OrderReplyJob.php | 80 + crmeb/jobs/PayGiveCouponJob.php | 44 + crmeb/jobs/ProductImportJob.php | 27 + crmeb/jobs/SendNewPeopleCouponJob.php | 49 + crmeb/jobs/SendNewsJob.php | 45 + crmeb/jobs/SendSmsJob.php | 58 + crmeb/jobs/SendSvipCouponJob.php | 44 + crmeb/jobs/SendTemplateMessageJob.php | 46 + crmeb/jobs/SpreadsheetExcelJob.php | 38 + crmeb/jobs/SupplyChainOrderBrokerAgeJob.php | 148 + crmeb/jobs/SyncProductTopJob.php | 79 + crmeb/jobs/TestJob.php | 34 + crmeb/jobs/UpdateProductReplyJob.php | 50 + crmeb/jobs/UserBrokerageLevelJob.php | 53 + crmeb/jobs/UserHistoryJob.php | 39 + crmeb/listens/AuthCancelActivityListen.php | 38 + .../listens/AuthCancelPresellOrderListen.php | 40 + crmeb/listens/AuthTakeOrderListen.php | 47 + crmeb/listens/AutoCancelGroupOrderListen.php | 43 + crmeb/listens/AutoCheckCouponListen.php | 30 + crmeb/listens/AutoClearIntegralListen.php | 96 + .../listens/AutoOrderProfitsharingListen.php | 37 + crmeb/listens/AutoOrderReplyListen.php | 42 + crmeb/listens/AutoSendPayOrderSmsListen.php | 42 + crmeb/listens/AutoUnLockBrokerageListen.php | 51 + crmeb/listens/AutoUnLockIntegralListen.php | 53 + .../listens/AutoUnlockMerchantMoneyListen.php | 42 + crmeb/listens/CloseUserSvipListen.php | 30 + crmeb/listens/CreateTimerListen.php | 31 + crmeb/listens/ExcelFileDelListen.php | 38 + crmeb/listens/GuaranteeCountListen.php | 32 + crmeb/listens/InitSwooleLockListen.php | 33 + .../listens/MerchantApplyMentsCheckListen.php | 40 + .../listens/ProductGroupStatusCheckListen.php | 35 + crmeb/listens/ProductPresellStatusListen.php | 46 + crmeb/listens/QueueListen.php | 34 + crmeb/listens/RefundOrderAgreeListen.php | 41 + crmeb/listens/SeckillTImeCheckListen.php | 44 + crmeb/listens/SendSvipCouponListen.php | 45 + crmeb/listens/SumCountListen.php | 29 + crmeb/listens/SwooleTaskListen.php | 209 + crmeb/listens/SwooleWorkerExitListen.php | 26 + crmeb/listens/SyncBroadcastStatusListen.php | 54 + crmeb/listens/SyncHotRankingListen.php | 39 + crmeb/listens/SyncSmsResultCodeListen.php | 42 + crmeb/listens/SyncSpreadStatusListen.php | 32 + crmeb/listens/pay/MealSuccessListen.php | 26 + .../pay/OrderMicroPaySuccessListen.php | 39 + crmeb/listens/pay/OrderPaySuccessListen.php | 40 + crmeb/listens/pay/PresellPaySuccessListen.php | 37 + crmeb/listens/pay/UserOrderSuccessListen.php | 28 + .../listens/pay/UserRechargeSuccessListen.php | 28 + crmeb/services/AccessTokenServeService.php | 173 + crmeb/services/AlipayService.php | 148 + crmeb/services/ApiResponseService.php | 133 + crmeb/services/BaseExpress.php | 72 + crmeb/services/BaseProduct.php | 62 + crmeb/services/BaseSmss.php | 107 + crmeb/services/BlockPuzzleCaptchaService.php | 59 + crmeb/services/CacheService.php | 168 + crmeb/services/CombinePayService.php | 77 + crmeb/services/CopyCommand.php | 149 + crmeb/services/CopyProductService.php | 542 ++ crmeb/services/CrmebServeServices.php | 143 + crmeb/services/DeliverySevices.php | 49 + crmeb/services/DownloadImageService.php | 101 + crmeb/services/ExcelService.php | 759 +++ crmeb/services/ExpressService.php | 123 + crmeb/services/FileService.php | 1024 +++ crmeb/services/HttpService.php | 138 + crmeb/services/ImageWaterMarkService.php | 53 + crmeb/services/JwtTokenService.php | 87 + crmeb/services/LockService.php | 52 + crmeb/services/MiniProgramService.php | 583 ++ crmeb/services/MysqlBackupService.php | 521 ++ crmeb/services/PayService.php | 100 + crmeb/services/PaymentService.php | 29 + crmeb/services/PrinterService.php | 64 + crmeb/services/QrcodeService.php | 192 + crmeb/services/RedisCacheService.php | 64 + crmeb/services/RoutineTemplateService.php | 48 + crmeb/services/SmsService.php | 299 + crmeb/services/SpreadsheetExcelService.php | 386 ++ crmeb/services/SwooleTaskService.php | 160 + crmeb/services/TimerService.php | 31 + crmeb/services/UpdateAuthInit.php | 173 + crmeb/services/UploadService.php | 85 + crmeb/services/VicWordService.php | 37 + crmeb/services/WechatService.php | 1072 ++++ crmeb/services/WechatService.php.bak | 1044 ++++ .../services/WechatTemplateMessageService.php | 759 +++ crmeb/services/WechatUserGroupService.php | 114 + crmeb/services/WechatUserTagService.php | 119 + crmeb/services/YunxinSmsService.php | 439 ++ crmeb/services/alipay/AlipayNotify.php | 43 + crmeb/services/delivery/Delivery.php | 34 + crmeb/services/delivery/storage/Dada.php | 319 + crmeb/services/delivery/storage/Uupt.php | 309 + crmeb/services/easywechat/BaseClient.php | 309 + crmeb/services/easywechat/batches/Client.php | 50 + .../easywechat/batches/ServiceProvider.php | 33 + .../services/easywechat/broadcast/Client.php | 462 ++ .../easywechat/broadcast/ServiceProvider.php | 29 + .../easywechat/certficates/Client.php | 50 + .../certficates/ServiceProvider.php | 33 + .../services/easywechat/combinePay/Client.php | 265 + .../easywechat/combinePay/ServiceProvider.php | 33 + crmeb/services/easywechat/merchant/Client.php | 206 + .../easywechat/merchant/ServiceProvider.php | 33 + .../easywechat/miniPayment/Client.php | 101 + .../miniPayment/ServiceProvider.php | 52 + .../easywechat/msgseccheck/Client.php | 113 + .../msgseccheck/ServiceProvider.php | 33 + crmeb/services/easywechat/pay/Client.php | 201 + .../easywechat/pay/ServiceProvider.php | 33 + crmeb/services/easywechat/storePay/Client.php | 59 + .../easywechat/storePay/ServiceProvider.php | 33 + .../easywechat/subscribe/ProgramProvider.php | 40 + .../easywechat/subscribe/ProgramSubscribe.php | 285 + crmeb/services/express/Express.php | 62 + crmeb/services/express/storage/Express.php | 175 + crmeb/services/printer/AccessToken.php | 174 + crmeb/services/printer/Printer.php | 73 + crmeb/services/printer/storage/YiLianYun.php | 118 + crmeb/services/product/Product.php | 63 + crmeb/services/product/storage/Copy.php | 58 + crmeb/services/serve/Serve.php | 64 + crmeb/services/serve/storage/Crmeb.php | 174 + crmeb/services/sms/Sms.php | 66 + crmeb/services/sms/storage/Aliyun.php | 117 + crmeb/services/sms/storage/Yunxin.php | 282 + crmeb/services/template/Template.php | 42 + crmeb/services/template/storage/Subscribe.php | 85 + crmeb/services/template/storage/Wechat.php | 121 + crmeb/services/upload/Upload.php | 44 + .../services/upload/client/UploadManager.php | 71 + crmeb/services/upload/storage/Cos.php | 390 ++ crmeb/services/upload/storage/Local.php | 375 ++ crmeb/services/upload/storage/Obs.php | 267 + crmeb/services/upload/storage/Oss.php | 268 + crmeb/services/upload/storage/Qiniu.php | 237 + crmeb/services/upload/storage/Us3.php | 253 + crmeb/traits/CategoresDao.php | 251 + crmeb/traits/CategoresRepository.php | 226 + crmeb/traits/ErrorTrait.php | 49 + crmeb/traits/Macro.php | 73 + crmeb/utils/ApiErrorCode.php | 124 + crmeb/utils/Start.php | 110 + extend/.gitignore | 4 + think | 10 + 1008 files changed, 139052 insertions(+) create mode 100644 .example.env create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 .version create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 app/.htaccess create mode 100644 app/AppService.php create mode 100644 app/ExceptionHandle.php create mode 100644 app/Request.php create mode 100644 app/command/ClearCacheAttachment.php create mode 100644 app/command/ClearMerchantData.php create mode 100644 app/command/ClearRedundancy.php create mode 100644 app/command/FormatMenuPath.php create mode 100644 app/command/VersionUpdate.php create mode 100644 app/command/changeHotTop.php create mode 100644 app/command/clearCache.php create mode 100644 app/command/resetImagePath.php create mode 100644 app/command/resetPassword.php create mode 100644 app/command/updateAuth.php create mode 100644 app/command/updateSpu.php create mode 100644 app/common.php create mode 100644 app/common/dao/BaseDao.php create mode 100644 app/common/dao/article/ArticleCategoryDao.php create mode 100644 app/common/dao/article/ArticleContentDao.php create mode 100644 app/common/dao/article/ArticleDao.php create mode 100644 app/common/dao/community/CommunityCategoryDao.php create mode 100644 app/common/dao/community/CommunityDao.php create mode 100644 app/common/dao/community/CommunityReplyDao.php create mode 100644 app/common/dao/community/CommunityTopicDao.php create mode 100644 app/common/dao/delivery/DeliveryOrderDao.php create mode 100644 app/common/dao/delivery/DeliveryStationDao.php create mode 100644 app/common/dao/store/CityAreaDao.php create mode 100644 app/common/dao/store/ExcelDao.php create mode 100644 app/common/dao/store/GuaranteeDao.php create mode 100644 app/common/dao/store/GuaranteeTemplateDao.php create mode 100644 app/common/dao/store/GuaranteeValueDao.php create mode 100644 app/common/dao/store/PriceRuleDao.php create mode 100644 app/common/dao/store/StoreActivityDao.php create mode 100644 app/common/dao/store/StoreAttrTemplateDao.php create mode 100644 app/common/dao/store/StoreBrandCategoryDao.php create mode 100644 app/common/dao/store/StoreBrandDao.php create mode 100644 app/common/dao/store/StoreCategoryDao.php create mode 100644 app/common/dao/store/StorePrinterDao.php create mode 100644 app/common/dao/store/StoreSeckillActiveDao.php create mode 100644 app/common/dao/store/StoreSeckillTimeDao.php create mode 100644 app/common/dao/store/broadcast/BroadcastAssistantDao.php create mode 100644 app/common/dao/store/broadcast/BroadcastGoodsDao.php create mode 100644 app/common/dao/store/broadcast/BroadcastRoomDao.php create mode 100644 app/common/dao/store/broadcast/BroadcastRoomGoodsDao.php create mode 100644 app/common/dao/store/coupon/StoreCouponDao.php create mode 100644 app/common/dao/store/coupon/StoreCouponIssueUserDao.php create mode 100644 app/common/dao/store/coupon/StoreCouponProductDao.php create mode 100644 app/common/dao/store/coupon/StoreCouponSendDao.php create mode 100644 app/common/dao/store/coupon/StoreCouponUserDao.php create mode 100644 app/common/dao/store/order/MerchantReconciliationDao.php create mode 100644 app/common/dao/store/order/MerchantReconciliationOrderDao.php create mode 100644 app/common/dao/store/order/PresellOrderDao.php create mode 100644 app/common/dao/store/order/StoreCartDao.php create mode 100644 app/common/dao/store/order/StoreCartDao.php.bak create mode 100644 app/common/dao/store/order/StoreGroupOrderDao.php create mode 100644 app/common/dao/store/order/StoreImportDao.php create mode 100644 app/common/dao/store/order/StoreImportDeliveryDao.php create mode 100644 app/common/dao/store/order/StoreOrderDao.php create mode 100644 app/common/dao/store/order/StoreOrderProductDao.php create mode 100644 app/common/dao/store/order/StoreOrderProfitsharingDao.php create mode 100644 app/common/dao/store/order/StoreOrderReceiptDao.php create mode 100644 app/common/dao/store/order/StoreOrderStatusDao.php create mode 100644 app/common/dao/store/order/StoreRefundOrderDao.php create mode 100644 app/common/dao/store/order/StoreRefundProductDao.php create mode 100644 app/common/dao/store/order/StoreRefundStatusDao.php create mode 100644 app/common/dao/store/parameter/ParameterDao.php create mode 100644 app/common/dao/store/parameter/ParameterTemplateDao.php create mode 100644 app/common/dao/store/parameter/ParameterValueDao.php create mode 100644 app/common/dao/store/product/ProductAssistDao.php create mode 100644 app/common/dao/store/product/ProductAssistSetDao.php create mode 100644 app/common/dao/store/product/ProductAssistSkuDao.php create mode 100644 app/common/dao/store/product/ProductAssistUserDao.php create mode 100644 app/common/dao/store/product/ProductAttrDao.php create mode 100644 app/common/dao/store/product/ProductAttrValueDao.php create mode 100644 app/common/dao/store/product/ProductCateDao.php create mode 100644 app/common/dao/store/product/ProductContentDao.php create mode 100644 app/common/dao/store/product/ProductCopyDao.php create mode 100644 app/common/dao/store/product/ProductDao.php create mode 100644 app/common/dao/store/product/ProductGroupBuyingDao.php create mode 100644 app/common/dao/store/product/ProductGroupDao.php create mode 100644 app/common/dao/store/product/ProductGroupSkuDao.php create mode 100644 app/common/dao/store/product/ProductGroupUserDao.php create mode 100644 app/common/dao/store/product/ProductLabelDao.php create mode 100644 app/common/dao/store/product/ProductPresellDao.php create mode 100644 app/common/dao/store/product/ProductPresellSkuDao.php create mode 100644 app/common/dao/store/product/ProductReplyDao.php create mode 100644 app/common/dao/store/product/ProductSkuDao.php create mode 100644 app/common/dao/store/product/ProductTakeDao.php create mode 100644 app/common/dao/store/product/SpuDao.php create mode 100644 app/common/dao/store/product/SpuDao.php.bak create mode 100644 app/common/dao/store/product/StoreDiscountDao.php create mode 100644 app/common/dao/store/product/StoreDiscountProductDao.php create mode 100644 app/common/dao/store/service/StoreServiceDao.php create mode 100644 app/common/dao/store/service/StoreServiceLogDao.php create mode 100644 app/common/dao/store/service/StoreServiceReplyDao.php create mode 100644 app/common/dao/store/service/StoreServiceUserDao.php create mode 100644 app/common/dao/store/shipping/CityDao.php create mode 100644 app/common/dao/store/shipping/ExpressDao.php create mode 100644 app/common/dao/store/shipping/ExpressPartnerDao.php create mode 100644 app/common/dao/store/shipping/ShippingTemplateDao.php create mode 100644 app/common/dao/store/shipping/ShippingTemplateFreeDao.php create mode 100644 app/common/dao/store/shipping/ShippingTemplateRegionDao.php create mode 100644 app/common/dao/store/shipping/ShippingTemplateUndeliveryDao.php create mode 100644 app/common/dao/system/CacheDao.php create mode 100644 app/common/dao/system/ExtendDao.php create mode 100644 app/common/dao/system/RelevanceDao.php create mode 100644 app/common/dao/system/admin/AdminDao.php create mode 100644 app/common/dao/system/admin/LogDao.php create mode 100644 app/common/dao/system/attachment/AttachmentCategoryDao.php create mode 100644 app/common/dao/system/attachment/AttachmentDao.php create mode 100644 app/common/dao/system/config/SystemConfigClassifyDao.php create mode 100644 app/common/dao/system/config/SystemConfigDao.php create mode 100644 app/common/dao/system/config/SystemConfigValueDao.php create mode 100644 app/common/dao/system/diy/DiyDao.php create mode 100644 app/common/dao/system/diy/PageCategoryDao.php create mode 100644 app/common/dao/system/diy/PageLinkDao.php create mode 100644 app/common/dao/system/financial/FinancialDao.php create mode 100644 app/common/dao/system/groupData/GroupDao.php create mode 100644 app/common/dao/system/groupData/GroupDataDao.php create mode 100644 app/common/dao/system/menu/MenuDao.php create mode 100644 app/common/dao/system/menu/RoleDao.php create mode 100644 app/common/dao/system/merchant/FinancialRecordDao.php create mode 100644 app/common/dao/system/merchant/MerchantAdminDao.php create mode 100644 app/common/dao/system/merchant/MerchantAppymentsDao.php create mode 100644 app/common/dao/system/merchant/MerchantCategoryDao.php create mode 100644 app/common/dao/system/merchant/MerchantDao.php create mode 100644 app/common/dao/system/merchant/MerchantDao.php.bak create mode 100644 app/common/dao/system/merchant/MerchantIntentionDao.php create mode 100644 app/common/dao/system/merchant/MerchantTypeDao.php create mode 100644 app/common/dao/system/notice/SystemNoticeConfigDao.php create mode 100644 app/common/dao/system/notice/SystemNoticeDao.php create mode 100644 app/common/dao/system/notice/SystemNoticeLogDao.php create mode 100644 app/common/dao/system/serve/ServeMealDao.php create mode 100644 app/common/dao/system/serve/ServeOrderDao.php create mode 100644 app/common/dao/system/sms/SmsRecordDao.php create mode 100644 app/common/dao/user/FeedbackCateoryDao.php create mode 100644 app/common/dao/user/FeedbackDao.php create mode 100644 app/common/dao/user/LabelRuleDao.php create mode 100644 app/common/dao/user/MemberInterestsDao.php create mode 100644 app/common/dao/user/UserAddressDao.php create mode 100644 app/common/dao/user/UserBillDao.php create mode 100644 app/common/dao/user/UserBrokerageDao.php create mode 100644 app/common/dao/user/UserDao.php create mode 100644 app/common/dao/user/UserExtractDao.php create mode 100644 app/common/dao/user/UserGroupDao.php create mode 100644 app/common/dao/user/UserHistoryDao.php create mode 100644 app/common/dao/user/UserLabelDao.php create mode 100644 app/common/dao/user/UserMerchantDao.php create mode 100644 app/common/dao/user/UserOrderDao.php create mode 100644 app/common/dao/user/UserReceiptDao.php create mode 100644 app/common/dao/user/UserRechargeDao.php create mode 100644 app/common/dao/user/UserRelationDao.php create mode 100644 app/common/dao/user/UserSignDao.php create mode 100644 app/common/dao/user/UserSpreadLogDao.php create mode 100644 app/common/dao/user/UserVisitDao.php create mode 100644 app/common/dao/wechat/RoutineQrcodeDao.php create mode 100644 app/common/dao/wechat/TemplateMessageDao.php create mode 100644 app/common/dao/wechat/WechatNewsDao.php create mode 100644 app/common/dao/wechat/WechatQrcodeDao.php create mode 100644 app/common/dao/wechat/WechatReplyDao.php create mode 100644 app/common/dao/wechat/WechatUserDao.php create mode 100644 app/common/middleware/AdminAuthMiddleware.php create mode 100644 app/common/middleware/AdminTokenMiddleware.php create mode 100644 app/common/middleware/AllowOriginMiddleware.php create mode 100644 app/common/middleware/BaseMiddleware.php create mode 100644 app/common/middleware/BlockerMiddleware.php create mode 100644 app/common/middleware/CheckSiteOpenMiddleware.php create mode 100644 app/common/middleware/InstallMiddleware.php create mode 100644 app/common/middleware/LogMiddleware.php create mode 100644 app/common/middleware/MerchantAuthMiddleware.php create mode 100644 app/common/middleware/MerchantCheckBaseInfoMiddleware.php create mode 100644 app/common/middleware/MerchantServerMiddleware.php create mode 100644 app/common/middleware/MerchantTokenMiddleware.php create mode 100644 app/common/middleware/RequestLockMiddleware.php create mode 100644 app/common/middleware/ServiceTokenMiddleware.php create mode 100644 app/common/middleware/UserTokenMiddleware.php create mode 100644 app/common/middleware/VisitProductMiddleware.php create mode 100644 app/common/model/BaseModel.php create mode 100644 app/common/model/article/Article.php create mode 100644 app/common/model/article/ArticleCategory.php create mode 100644 app/common/model/article/ArticleContent.php create mode 100644 app/common/model/community/Community.php create mode 100644 app/common/model/community/CommunityCategory.php create mode 100644 app/common/model/community/CommunityReply.php create mode 100644 app/common/model/community/CommunityTopic.php create mode 100644 app/common/model/delivery/DeliveryOrder.php create mode 100644 app/common/model/delivery/DeliveryStation.php create mode 100644 app/common/model/store/CityArea.php create mode 100644 app/common/model/store/Excel.php create mode 100644 app/common/model/store/GeoArea.php create mode 100644 app/common/model/store/Guarantee.php create mode 100644 app/common/model/store/GuaranteeTemplate.php create mode 100644 app/common/model/store/GuaranteeValue.php create mode 100644 app/common/model/store/PriceRule.php create mode 100644 app/common/model/store/StoreActivity.php create mode 100644 app/common/model/store/StoreAttrTemplate.php create mode 100644 app/common/model/store/StoreBrand.php create mode 100644 app/common/model/store/StoreBrandCategory.php create mode 100644 app/common/model/store/StoreCategory.php create mode 100644 app/common/model/store/StorePrinter.php create mode 100644 app/common/model/store/StoreSeckillActive.php create mode 100644 app/common/model/store/StoreSeckillTime.php create mode 100644 app/common/model/store/broadcast/BroadcastAssistant.php create mode 100644 app/common/model/store/broadcast/BroadcastGoods.php create mode 100644 app/common/model/store/broadcast/BroadcastRoom.php create mode 100644 app/common/model/store/broadcast/BroadcastRoomGoods.php create mode 100644 app/common/model/store/coupon/StoreCoupon.php create mode 100644 app/common/model/store/coupon/StoreCouponIssueUser.php create mode 100644 app/common/model/store/coupon/StoreCouponProduct.php create mode 100644 app/common/model/store/coupon/StoreCouponSend.php create mode 100644 app/common/model/store/coupon/StoreCouponUser.php create mode 100644 app/common/model/store/order/MerchantReconciliation.php create mode 100644 app/common/model/store/order/MerchantReconciliationOrder.php create mode 100644 app/common/model/store/order/PresellOrder.php create mode 100644 app/common/model/store/order/StoreCart.php create mode 100644 app/common/model/store/order/StoreCart.php.bak create mode 100644 app/common/model/store/order/StoreGroupOrder.php create mode 100644 app/common/model/store/order/StoreImport.php create mode 100644 app/common/model/store/order/StoreImportDelivery.php create mode 100644 app/common/model/store/order/StoreOrder.php create mode 100644 app/common/model/store/order/StoreOrderProduct.php create mode 100644 app/common/model/store/order/StoreOrderProfitsharing.php create mode 100644 app/common/model/store/order/StoreOrderReceipt.php create mode 100644 app/common/model/store/order/StoreOrderStatus.php create mode 100644 app/common/model/store/order/StoreRefundOrder.php create mode 100644 app/common/model/store/order/StoreRefundProduct.php create mode 100644 app/common/model/store/order/StoreRefundStatus.php create mode 100644 app/common/model/store/parameter/Parameter.php create mode 100644 app/common/model/store/parameter/ParameterTemplate.php create mode 100644 app/common/model/store/parameter/ParameterValue.php create mode 100644 app/common/model/store/product/Product.php create mode 100644 app/common/model/store/product/ProductAssist.php create mode 100644 app/common/model/store/product/ProductAssistSet.php create mode 100644 app/common/model/store/product/ProductAssistSku.php create mode 100644 app/common/model/store/product/ProductAssistUser.php create mode 100644 app/common/model/store/product/ProductAttr.php create mode 100644 app/common/model/store/product/ProductAttrValue.php create mode 100644 app/common/model/store/product/ProductCate.php create mode 100644 app/common/model/store/product/ProductContent.php create mode 100644 app/common/model/store/product/ProductCopy.php create mode 100644 app/common/model/store/product/ProductGroup.php create mode 100644 app/common/model/store/product/ProductGroupBuying.php create mode 100644 app/common/model/store/product/ProductGroupSku.php create mode 100644 app/common/model/store/product/ProductGroupUser.php create mode 100644 app/common/model/store/product/ProductLabel.php create mode 100644 app/common/model/store/product/ProductPresell.php create mode 100644 app/common/model/store/product/ProductPresellSku.php create mode 100644 app/common/model/store/product/ProductReply.php create mode 100644 app/common/model/store/product/ProductSku.php create mode 100644 app/common/model/store/product/ProductTake.php create mode 100644 app/common/model/store/product/Spu.php create mode 100644 app/common/model/store/product/Spu.php.bak create mode 100644 app/common/model/store/product/StoreDiscountProduct.php create mode 100644 app/common/model/store/product/StoreDiscounts.php create mode 100644 app/common/model/store/service/StoreService.php create mode 100644 app/common/model/store/service/StoreServiceLog.php create mode 100644 app/common/model/store/service/StoreServiceReply.php create mode 100644 app/common/model/store/service/StoreServiceUser.php create mode 100644 app/common/model/store/shipping/City.php create mode 100644 app/common/model/store/shipping/Express.php create mode 100644 app/common/model/store/shipping/ExpressPartner.php create mode 100644 app/common/model/store/shipping/ShippingTemplate.php create mode 100644 app/common/model/store/shipping/ShippingTemplateFree.php create mode 100644 app/common/model/store/shipping/ShippingTemplateRegion.php create mode 100644 app/common/model/store/shipping/ShippingTemplateUndelivery.php create mode 100644 app/common/model/system/Cache.php create mode 100644 app/common/model/system/Extend.php create mode 100644 app/common/model/system/Relevance.php create mode 100644 app/common/model/system/admin/Admin.php create mode 100644 app/common/model/system/admin/Log.php create mode 100644 app/common/model/system/attachment/Attachment.php create mode 100644 app/common/model/system/attachment/AttachmentCategory.php create mode 100644 app/common/model/system/auth/Menu.php create mode 100644 app/common/model/system/auth/Role.php create mode 100644 app/common/model/system/config/SystemConfig.php create mode 100644 app/common/model/system/config/SystemConfigClassify.php create mode 100644 app/common/model/system/config/SystemConfigValue.php create mode 100644 app/common/model/system/diy/Diy.php create mode 100644 app/common/model/system/diy/PageCategory.php create mode 100644 app/common/model/system/diy/PageLink.php create mode 100644 app/common/model/system/financial/Financial.php create mode 100644 app/common/model/system/groupData/SystemGroup.php create mode 100644 app/common/model/system/groupData/SystemGroupData.php create mode 100644 app/common/model/system/merchant/FinancialRecord.php create mode 100644 app/common/model/system/merchant/Merchant.php create mode 100644 app/common/model/system/merchant/Merchant.php.bak create mode 100644 app/common/model/system/merchant/MerchantAdmin.php create mode 100644 app/common/model/system/merchant/MerchantApplyments.php create mode 100644 app/common/model/system/merchant/MerchantCategory.php create mode 100644 app/common/model/system/merchant/MerchantIntention.php create mode 100644 app/common/model/system/merchant/MerchantType.php create mode 100644 app/common/model/system/notice/SystemNotice.php create mode 100644 app/common/model/system/notice/SystemNoticeConfig.php create mode 100644 app/common/model/system/notice/SystemNoticeLog.php create mode 100644 app/common/model/system/serve/ServeMeal.php create mode 100644 app/common/model/system/serve/ServeOrder.php create mode 100644 app/common/model/system/sms/SmsRecord.php create mode 100644 app/common/model/user/FeedBackCategory.php create mode 100644 app/common/model/user/Feedback.php create mode 100644 app/common/model/user/LabelRule.php create mode 100644 app/common/model/user/MemberInterests.php create mode 100644 app/common/model/user/User.php create mode 100644 app/common/model/user/UserAddress.php create mode 100644 app/common/model/user/UserBill.php create mode 100644 app/common/model/user/UserBrokerage.php create mode 100644 app/common/model/user/UserExtract.php create mode 100644 app/common/model/user/UserGroup.php create mode 100644 app/common/model/user/UserHistory.php create mode 100644 app/common/model/user/UserLabel.php create mode 100644 app/common/model/user/UserMerchant.php create mode 100644 app/common/model/user/UserOrder.php create mode 100644 app/common/model/user/UserReceipt.php create mode 100644 app/common/model/user/UserRecharge.php create mode 100644 app/common/model/user/UserRelation.php create mode 100644 app/common/model/user/UserSign.php create mode 100644 app/common/model/user/UserSpreadLog.php create mode 100644 app/common/model/user/UserVisit.php create mode 100644 app/common/model/wechat/RoutineQrcode.php create mode 100644 app/common/model/wechat/TemplateMessage.php create mode 100644 app/common/model/wechat/WechatNews.php create mode 100644 app/common/model/wechat/WechatQrcode.php create mode 100644 app/common/model/wechat/WechatReply.php create mode 100644 app/common/model/wechat/WechatUser.php create mode 100644 app/common/repositories/BaseRepository.php create mode 100644 app/common/repositories/article/ArticleCategoryRepository.php create mode 100644 app/common/repositories/article/ArticleContentRepository.php create mode 100644 app/common/repositories/article/ArticleRepository.php create mode 100644 app/common/repositories/community/CommunityCategoryRepository.php create mode 100644 app/common/repositories/community/CommunityReplyRepository.php create mode 100644 app/common/repositories/community/CommunityRepository.php create mode 100644 app/common/repositories/community/CommunityTopicRepository.php create mode 100644 app/common/repositories/delivery/DeliveryOrderRepository.php create mode 100644 app/common/repositories/delivery/DeliveryStationRepository.php create mode 100644 app/common/repositories/store/CityAreaRepository.php create mode 100644 app/common/repositories/store/ExcelRepository.php create mode 100644 app/common/repositories/store/GuaranteeRepository.php create mode 100644 app/common/repositories/store/GuaranteeTemplateRepository.php create mode 100644 app/common/repositories/store/GuaranteeValueRepository.php create mode 100644 app/common/repositories/store/IntegralRepository.php create mode 100644 app/common/repositories/store/MerchantTakeRepository.php create mode 100644 app/common/repositories/store/PriceRuleRepository.php create mode 100644 app/common/repositories/store/StoreActivityRepository.php create mode 100644 app/common/repositories/store/StoreAttrTemplateRepository.php create mode 100644 app/common/repositories/store/StoreBrandCategoryRepository.php create mode 100644 app/common/repositories/store/StoreBrandRepository.php create mode 100644 app/common/repositories/store/StoreCategoryRepository.php create mode 100644 app/common/repositories/store/StoreCategoryRepository.php.bak create mode 100644 app/common/repositories/store/StorePrinterRepository.php create mode 100644 app/common/repositories/store/StoreSeckillActiveRepository.php create mode 100644 app/common/repositories/store/StoreSeckillTimeRepository.php create mode 100644 app/common/repositories/store/broadcast/BroadcastAssistantRepository.php create mode 100644 app/common/repositories/store/broadcast/BroadcastGoodsRepository.php create mode 100644 app/common/repositories/store/broadcast/BroadcastRoomGoodsRepository.php create mode 100644 app/common/repositories/store/broadcast/BroadcastRoomRepository.php create mode 100644 app/common/repositories/store/coupon/StoreCouponIssueUserRepository.php create mode 100644 app/common/repositories/store/coupon/StoreCouponProductRepository.php create mode 100644 app/common/repositories/store/coupon/StoreCouponRepository.php create mode 100644 app/common/repositories/store/coupon/StoreCouponSendRepository.php create mode 100644 app/common/repositories/store/coupon/StoreCouponUserRepository.php create mode 100644 app/common/repositories/store/order/MerchantReconciliationOrderRepository.php create mode 100644 app/common/repositories/store/order/MerchantReconciliationRepository.php create mode 100644 app/common/repositories/store/order/PresellOrderRepository.php create mode 100644 app/common/repositories/store/order/StoreCartRepository.php create mode 100644 app/common/repositories/store/order/StoreCartRepository.php.bak create mode 100644 app/common/repositories/store/order/StoreGroupOrderRepository.php create mode 100644 app/common/repositories/store/order/StoreImportDeliveryRepository.php create mode 100644 app/common/repositories/store/order/StoreImportRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderCreateRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderCreateRepository.php.bak create mode 100644 app/common/repositories/store/order/StoreOrderProductRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderProfitsharingRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderReceiptRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderRepository.php.bak create mode 100644 app/common/repositories/store/order/StoreOrderSplitRepository.php create mode 100644 app/common/repositories/store/order/StoreOrderStatusRepository.php create mode 100644 app/common/repositories/store/order/StoreRefundOrderRepository.php create mode 100644 app/common/repositories/store/order/StoreRefundProductRepository.php create mode 100644 app/common/repositories/store/order/StoreRefundStatusRepository.php create mode 100644 app/common/repositories/store/parameter/ParameterRepository.php create mode 100644 app/common/repositories/store/parameter/ParameterTemplateRepository.php create mode 100644 app/common/repositories/store/parameter/ParameterValueRepository.php create mode 100644 app/common/repositories/store/product/ProductAssistRepository.php create mode 100644 app/common/repositories/store/product/ProductAssistSetRepository.php create mode 100644 app/common/repositories/store/product/ProductAssistSkuRepository.php create mode 100644 app/common/repositories/store/product/ProductAssistUserRepository.php create mode 100644 app/common/repositories/store/product/ProductAttrRepository.php create mode 100644 app/common/repositories/store/product/ProductAttrValueRepository.php create mode 100644 app/common/repositories/store/product/ProductCateRepository.php create mode 100644 app/common/repositories/store/product/ProductContentRepository.php create mode 100644 app/common/repositories/store/product/ProductCopyRepository.php create mode 100644 app/common/repositories/store/product/ProductGroupBuyingRepository.php create mode 100644 app/common/repositories/store/product/ProductGroupRepository.php create mode 100644 app/common/repositories/store/product/ProductGroupSkuRepository.php create mode 100644 app/common/repositories/store/product/ProductGroupUserRepository.php create mode 100644 app/common/repositories/store/product/ProductLabelRepository.php create mode 100644 app/common/repositories/store/product/ProductPresellRepository.php create mode 100644 app/common/repositories/store/product/ProductPresellSkuRepository.php create mode 100644 app/common/repositories/store/product/ProductReplyRepository.php create mode 100644 app/common/repositories/store/product/ProductRepository.php create mode 100644 app/common/repositories/store/product/ProductRepository.php.bak create mode 100644 app/common/repositories/store/product/ProductSkuRepository.php create mode 100644 app/common/repositories/store/product/ProductTakeRepository.php create mode 100644 app/common/repositories/store/product/SpuRepository.php create mode 100644 app/common/repositories/store/product/SpuRepository.php.bak create mode 100644 app/common/repositories/store/product/StoreDiscountProductRepository.php create mode 100644 app/common/repositories/store/product/StoreDiscountRepository.php create mode 100644 app/common/repositories/store/service/StoreServiceLogRepository.php create mode 100644 app/common/repositories/store/service/StoreServiceReplyRepository.php create mode 100644 app/common/repositories/store/service/StoreServiceRepository.php create mode 100644 app/common/repositories/store/service/StoreServiceUserRepository.php create mode 100644 app/common/repositories/store/shipping/CityRepository.php create mode 100644 app/common/repositories/store/shipping/ExpressPartnerRepository.php create mode 100644 app/common/repositories/store/shipping/ExpressRepository.php create mode 100644 app/common/repositories/store/shipping/ShippingTemplateFreeRepository.php create mode 100644 app/common/repositories/store/shipping/ShippingTemplateRegionRepository.php create mode 100644 app/common/repositories/store/shipping/ShippingTemplateRepository.php create mode 100644 app/common/repositories/store/shipping/ShippingTemplateUndeliveRepository.php create mode 100644 app/common/repositories/system/CacheRepository.php create mode 100644 app/common/repositories/system/ExtendRepository.php create mode 100644 app/common/repositories/system/RelevanceRepository.php create mode 100644 app/common/repositories/system/admin/AdminLogRepository.php create mode 100644 app/common/repositories/system/admin/AdminRepository.php create mode 100644 app/common/repositories/system/attachment/AttachmentCategoryRepository.php create mode 100644 app/common/repositories/system/attachment/AttachmentRepository.php create mode 100644 app/common/repositories/system/auth/MenuRepository.php create mode 100644 app/common/repositories/system/auth/RoleRepository.php create mode 100644 app/common/repositories/system/config/ConfigClassifyRepository.php create mode 100644 app/common/repositories/system/config/ConfigRepository.php create mode 100644 app/common/repositories/system/config/ConfigValueRepository.php create mode 100644 app/common/repositories/system/diy/DiyRepository.php create mode 100644 app/common/repositories/system/diy/PageCategoryRepository.php create mode 100644 app/common/repositories/system/diy/PageLinkRepository.php create mode 100644 app/common/repositories/system/financial/FinancialRepository.php create mode 100644 app/common/repositories/system/groupData/GroupDataRepository.php create mode 100644 app/common/repositories/system/groupData/GroupRepository.php create mode 100644 app/common/repositories/system/merchant/FinancialRecordRepository.php create mode 100644 app/common/repositories/system/merchant/MerchantAdminRepository.php create mode 100644 app/common/repositories/system/merchant/MerchantApplymentsRepository.php create mode 100644 app/common/repositories/system/merchant/MerchantCategoryRepository.php create mode 100644 app/common/repositories/system/merchant/MerchantIntentionRepository.php create mode 100644 app/common/repositories/system/merchant/MerchantIntentionRepository.php.bak create mode 100644 app/common/repositories/system/merchant/MerchantRepository.php create mode 100644 app/common/repositories/system/merchant/MerchantRepository.php.bak create mode 100644 app/common/repositories/system/merchant/MerchantTypeRepository.php create mode 100644 app/common/repositories/system/notice/SystemNoticeConfigRepository.php create mode 100644 app/common/repositories/system/notice/SystemNoticeLogRepository.php create mode 100644 app/common/repositories/system/notice/SystemNoticeRepository.php create mode 100644 app/common/repositories/system/serve/ServeMealRepository.php create mode 100644 app/common/repositories/system/serve/ServeOrderRepository.php create mode 100644 app/common/repositories/system/sms/SmsRecordRepository.php create mode 100644 app/common/repositories/user/FeedBackCategoryRepository.php create mode 100644 app/common/repositories/user/FeedbackRepository.php create mode 100644 app/common/repositories/user/LabelRuleRepository.php create mode 100644 app/common/repositories/user/MemberinterestsRepository.php create mode 100644 app/common/repositories/user/UserAddressRepository.php create mode 100644 app/common/repositories/user/UserBillRepository.php create mode 100644 app/common/repositories/user/UserBrokerageRepository.php create mode 100644 app/common/repositories/user/UserExtractRepository.php create mode 100644 app/common/repositories/user/UserGroupRepository.php create mode 100644 app/common/repositories/user/UserHistoryRepository.php create mode 100644 app/common/repositories/user/UserLabelRepository.php create mode 100644 app/common/repositories/user/UserMerchantRepository.php create mode 100644 app/common/repositories/user/UserOrderRepository.php create mode 100644 app/common/repositories/user/UserReceiptRepository.php create mode 100644 app/common/repositories/user/UserRechargeRepository.php create mode 100644 app/common/repositories/user/UserRelationRepository.php create mode 100644 app/common/repositories/user/UserRepository.php create mode 100644 app/common/repositories/user/UserSignRepository.php create mode 100644 app/common/repositories/user/UserSpreadLogRepository.php create mode 100644 app/common/repositories/user/UserVisitRepository.php create mode 100644 app/common/repositories/wechat/CustomTemplate.php create mode 100644 app/common/repositories/wechat/RoutineQrcodeRepository.php create mode 100644 app/common/repositories/wechat/TemplateMessageRepository.php create mode 100644 app/common/repositories/wechat/WechatNewsRepository.php create mode 100644 app/common/repositories/wechat/WechatQrcodeRepository.php create mode 100644 app/common/repositories/wechat/WechatReplyRepository.php create mode 100644 app/common/repositories/wechat/WechatUserRepository.php create mode 100644 app/controller/Install.php create mode 100644 app/controller/View.php create mode 100644 app/controller/WechatNotice.php create mode 100644 app/controller/admin/Common.php create mode 100644 app/controller/admin/article/Article.php create mode 100644 app/controller/admin/article/ArticleCategory.php create mode 100644 app/controller/admin/community/Community.php create mode 100644 app/controller/admin/community/CommunityCategory.php create mode 100644 app/controller/admin/community/CommunityReply.php create mode 100644 app/controller/admin/community/CommunityTopic.php create mode 100644 app/controller/admin/delivery/DeliveryOrder.php create mode 100644 app/controller/admin/delivery/DeliveryStation.php create mode 100644 app/controller/admin/order/Order.php create mode 100644 app/controller/admin/order/OrderProfitsharing.php create mode 100644 app/controller/admin/order/Reconciliation.php create mode 100644 app/controller/admin/order/RefundOrder.php create mode 100644 app/controller/admin/parameter/ParameterTemplate.php create mode 100644 app/controller/admin/store/BroadcastGoods.php create mode 100644 app/controller/admin/store/BroadcastRoom.php create mode 100644 app/controller/admin/store/CityArea.php create mode 100644 app/controller/admin/store/Coupon.php create mode 100644 app/controller/admin/store/Discounts.php create mode 100644 app/controller/admin/store/Express.php create mode 100644 app/controller/admin/store/Guarantee.php create mode 100644 app/controller/admin/store/PriceRule.php create mode 100644 app/controller/admin/store/ProductLabel.php create mode 100644 app/controller/admin/store/StoreBrand.php create mode 100644 app/controller/admin/store/StoreBrandCategory.php create mode 100644 app/controller/admin/store/StoreCategory.php create mode 100644 app/controller/admin/store/StoreProduct.php create mode 100644 app/controller/admin/store/StoreProductAssist.php create mode 100644 app/controller/admin/store/StoreProductAssistSet.php create mode 100644 app/controller/admin/store/StoreProductGroup.php create mode 100644 app/controller/admin/store/StoreProductGroupBuying.php create mode 100644 app/controller/admin/store/StoreProductPresell.php create mode 100644 app/controller/admin/store/StoreProductReply.php create mode 100644 app/controller/admin/store/StoreProductSeckill.php create mode 100644 app/controller/admin/store/StoreSeckill.php create mode 100644 app/controller/admin/store/StoreService.php create mode 100644 app/controller/admin/store/marketing/StoreAtmosphere.php create mode 100644 app/controller/admin/store/marketing/StoreBorder.php create mode 100644 app/controller/admin/system/Cache.php create mode 100644 app/controller/admin/system/admin/Admin.php create mode 100644 app/controller/admin/system/admin/AdminLog.php create mode 100644 app/controller/admin/system/admin/Login.php create mode 100644 app/controller/admin/system/attachment/Attachment.php create mode 100644 app/controller/admin/system/attachment/AttachmentCategory.php create mode 100644 app/controller/admin/system/auth/Menu.php create mode 100644 app/controller/admin/system/auth/Role.php create mode 100644 app/controller/admin/system/config/Config.php create mode 100644 app/controller/admin/system/config/ConfigClassify.php create mode 100644 app/controller/admin/system/config/ConfigOthers.php create mode 100644 app/controller/admin/system/config/ConfigValue.php create mode 100644 app/controller/admin/system/diy/Diy.php create mode 100644 app/controller/admin/system/diy/PageCategroy.php create mode 100644 app/controller/admin/system/diy/PageLink.php create mode 100644 app/controller/admin/system/diy/VisualConfig.php create mode 100644 app/controller/admin/system/financial/Financial.php create mode 100644 app/controller/admin/system/groupData/Group.php create mode 100644 app/controller/admin/system/groupData/GroupData.php create mode 100644 app/controller/admin/system/merchant/FinancialRecord.php create mode 100644 app/controller/admin/system/merchant/Merchant.php create mode 100644 app/controller/admin/system/merchant/Merchant.php.bak create mode 100644 app/controller/admin/system/merchant/MerchantAdmin.php create mode 100644 app/controller/admin/system/merchant/MerchantApplyments.php create mode 100644 app/controller/admin/system/merchant/MerchantCategory.php create mode 100644 app/controller/admin/system/merchant/MerchantIntention.php create mode 100644 app/controller/admin/system/merchant/MerchantMargin.php create mode 100644 app/controller/admin/system/merchant/MerchantType.php create mode 100644 app/controller/admin/system/notice/SystemNotice.php create mode 100644 app/controller/admin/system/notice/SystemNoticeConfig.php create mode 100644 app/controller/admin/system/safety/Database.php create mode 100644 app/controller/admin/system/serve/Config.php create mode 100644 app/controller/admin/system/serve/Export.php create mode 100644 app/controller/admin/system/serve/Login.php create mode 100644 app/controller/admin/system/serve/Serve.php create mode 100644 app/controller/admin/system/serve/Sms.php create mode 100644 app/controller/admin/system/service/StoreService.php create mode 100644 app/controller/admin/system/sms/Sms.php create mode 100644 app/controller/admin/system/sms/SmsPay.php create mode 100644 app/controller/admin/system/sms/SmsTemplate.php create mode 100644 app/controller/admin/user/FeedBack.php create mode 100644 app/controller/admin/user/FeedBackCategory.php create mode 100644 app/controller/admin/user/MemberInterests.php create mode 100644 app/controller/admin/user/Svip.php create mode 100644 app/controller/admin/user/User.php create mode 100644 app/controller/admin/user/UserBill.php create mode 100644 app/controller/admin/user/UserBrokerage.php create mode 100644 app/controller/admin/user/UserExtract.php create mode 100644 app/controller/admin/user/UserGroup.php create mode 100644 app/controller/admin/user/UserIntegral.php create mode 100644 app/controller/admin/user/UserLabel.php create mode 100644 app/controller/admin/user/UserRecharge.php create mode 100644 app/controller/admin/wechat/TemplateMessage.php create mode 100644 app/controller/admin/wechat/WechatGroup.php create mode 100644 app/controller/admin/wechat/WechatMenu.php create mode 100644 app/controller/admin/wechat/WechatNews.php create mode 100644 app/controller/admin/wechat/WechatReply.php create mode 100644 app/controller/admin/wechat/WechatTag.php create mode 100644 app/controller/admin/wechat/WechatUser.php create mode 100644 app/controller/api/Auth.php create mode 100644 app/controller/api/Common.php create mode 100644 app/controller/api/Common.php.bak create mode 100644 app/controller/api/Wechat.php create mode 100644 app/controller/api/article/Article.php create mode 100644 app/controller/api/article/ArticleCategory.php create mode 100644 app/controller/api/community/Community.php create mode 100644 app/controller/api/community/CommunityCategory.php create mode 100644 app/controller/api/community/CommunityReply.php create mode 100644 app/controller/api/server/ShippingTemplate.php create mode 100644 app/controller/api/server/StoreCategory.php create mode 100644 app/controller/api/server/StoreOrder.php create mode 100644 app/controller/api/server/StoreOrder.php.bak create mode 100644 app/controller/api/server/StoreProduct.php create mode 100644 app/controller/api/server/StoreProduct.php.bak create mode 100644 app/controller/api/server/StoreProductAttrTemplate.php create mode 100644 app/controller/api/server/StoreRefundOrder.php create mode 100644 app/controller/api/store/broadcast/BroadcastRoom.php create mode 100644 app/controller/api/store/merchant/Merchant.php create mode 100644 app/controller/api/store/merchant/Merchant.php.bak create mode 100644 app/controller/api/store/merchant/MerchantIntention.php create mode 100644 app/controller/api/store/merchant/MerchantIntention.php.bak create mode 100644 app/controller/api/store/order/PresellOrder.php create mode 100644 app/controller/api/store/order/StoreCart.php create mode 100644 app/controller/api/store/order/StoreCart.php.bak create mode 100644 app/controller/api/store/order/StoreMicropayOrder.php create mode 100644 app/controller/api/store/order/StoreOrder.php create mode 100644 app/controller/api/store/order/StoreOrder.php.bak create mode 100644 app/controller/api/store/order/StoreOrderVerify.php create mode 100644 app/controller/api/store/order/StoreRefundOrder.php create mode 100644 app/controller/api/store/product/Discounts.php create mode 100644 app/controller/api/store/product/StoreBrand.php create mode 100644 app/controller/api/store/product/StoreCategory.php create mode 100644 app/controller/api/store/product/StoreCoupon.php create mode 100644 app/controller/api/store/product/StoreMicro.php create mode 100644 app/controller/api/store/product/StoreProduct.php create mode 100644 app/controller/api/store/product/StoreProduct.php.bak create mode 100644 app/controller/api/store/product/StoreProductAssist.php create mode 100644 app/controller/api/store/product/StoreProductAssistSet.php create mode 100644 app/controller/api/store/product/StoreProductGroup.php create mode 100644 app/controller/api/store/product/StoreProductPresell.php create mode 100644 app/controller/api/store/product/StoreProductSeckill.php create mode 100644 app/controller/api/store/product/StoreReply.php create mode 100644 app/controller/api/store/product/StoreSpu.php create mode 100644 app/controller/api/store/service/Service.php create mode 100644 app/controller/api/user/Admin.php create mode 100644 app/controller/api/user/FeedBackCategory.php create mode 100644 app/controller/api/user/Feedback.php create mode 100644 app/controller/api/user/Member.php create mode 100644 app/controller/api/user/Svip.php create mode 100644 app/controller/api/user/User.php create mode 100644 app/controller/api/user/UserAddress.php create mode 100644 app/controller/api/user/UserExtract.php create mode 100644 app/controller/api/user/UserHistory.php create mode 100644 app/controller/api/user/UserReceipt.php create mode 100644 app/controller/api/user/UserRecharge.php create mode 100644 app/controller/api/user/UserRelation.php create mode 100644 app/controller/api/user/UserSign.php create mode 100644 app/controller/merchant/Common.php create mode 100644 app/controller/merchant/store/Excel.php create mode 100644 app/controller/merchant/store/StoreAttrTemplate.php create mode 100644 app/controller/merchant/store/StoreImport.php create mode 100644 app/controller/merchant/store/StoreImport.php.bak create mode 100644 app/controller/merchant/store/StorePrinter.php create mode 100644 app/controller/merchant/store/StoreProductReply.php create mode 100644 app/controller/merchant/store/broadcast/BroadcastAssistant.php create mode 100644 app/controller/merchant/store/broadcast/BroadcastGoods.php create mode 100644 app/controller/merchant/store/broadcast/BroadcastRoom.php create mode 100644 app/controller/merchant/store/coupon/Coupon.php create mode 100644 app/controller/merchant/store/coupon/CouponSend.php create mode 100644 app/controller/merchant/store/delivery/DeliveryOrder.php create mode 100644 app/controller/merchant/store/delivery/DeliveryStation.php create mode 100644 app/controller/merchant/store/guarantee/GuaranteeTemplate.php create mode 100644 app/controller/merchant/store/order/Order.php create mode 100644 app/controller/merchant/store/order/OrderReceipt.php create mode 100644 app/controller/merchant/store/order/Reconciliation.php create mode 100644 app/controller/merchant/store/order/RefundOrder.php create mode 100644 app/controller/merchant/store/product/Discounts.php create mode 100644 app/controller/merchant/store/product/Product.php create mode 100644 app/controller/merchant/store/product/Product.php.bak create mode 100644 app/controller/merchant/store/product/ProductAssist.php create mode 100644 app/controller/merchant/store/product/ProductAssistSet.php create mode 100644 app/controller/merchant/store/product/ProductCopy.php create mode 100644 app/controller/merchant/store/product/ProductGroup.php create mode 100644 app/controller/merchant/store/product/ProductGroupBuying.php create mode 100644 app/controller/merchant/store/product/ProductLabel.php create mode 100644 app/controller/merchant/store/product/ProductPresell.php create mode 100644 app/controller/merchant/store/product/ProductSeckill.php create mode 100644 app/controller/merchant/store/service/StoreService.php create mode 100644 app/controller/merchant/store/service/StoreServiceReply.php create mode 100644 app/controller/merchant/store/shipping/City.php create mode 100644 app/controller/merchant/store/shipping/ShippingTemplate.php create mode 100644 app/controller/merchant/store/shipping/ShippingTemplateFree.php create mode 100644 app/controller/merchant/store/shipping/ShippingTemplateRegion.php create mode 100644 app/controller/merchant/store/shipping/ShippingTemplateUndelive.php create mode 100644 app/controller/merchant/system/Merchant.php create mode 100644 app/controller/merchant/system/MerchantApplyments.php create mode 100644 app/controller/merchant/system/admin/Login.php create mode 100644 app/controller/merchant/system/admin/MerchantAdmin.php create mode 100644 app/controller/merchant/system/auth/Role.php create mode 100644 app/controller/merchant/system/financial/Financial.php create mode 100644 app/controller/merchant/system/notice/SystemNoticeLog.php create mode 100644 app/controller/merchant/system/serve/Config.php create mode 100644 app/controller/merchant/system/serve/Serve.php create mode 100644 app/controller/merchant/user/LabelRule.php create mode 100644 app/controller/merchant/user/User.php create mode 100644 app/controller/merchant/user/UserIntegral.php create mode 100644 app/controller/merchant/user/UserMerchant.php create mode 100644 app/controller/service/Common.php create mode 100644 app/controller/service/Login.php create mode 100644 app/controller/service/Service.php create mode 100644 app/event.php create mode 100644 app/event.php.bak create mode 100644 app/middleware.php create mode 100644 app/provider.php create mode 100644 app/service.php create mode 100644 app/validate/admin/AdminEditValidate.php create mode 100644 app/validate/admin/AdminValidate.php create mode 100644 app/validate/admin/ArticleCategoryValidate.php create mode 100644 app/validate/admin/ArticleValidate.php create mode 100644 app/validate/admin/AttachmentCategoryValidate.php create mode 100644 app/validate/admin/AttachmentValidate.php create mode 100644 app/validate/admin/CommunityTopicValidate.php create mode 100644 app/validate/admin/ConfigClassifyValidate.php create mode 100644 app/validate/admin/ConfigValidate.php create mode 100644 app/validate/admin/CrmebServeValidata.php create mode 100644 app/validate/admin/ExpressValidata.php create mode 100644 app/validate/admin/GroupDataValidate.php create mode 100644 app/validate/admin/GroupValidate.php create mode 100644 app/validate/admin/GuaranteeTemplateValidate.php create mode 100644 app/validate/admin/GuaranteeValidate.php create mode 100644 app/validate/admin/IntegralConfigValidate.php create mode 100644 app/validate/admin/LoginValidate.php create mode 100644 app/validate/admin/MealValidata.php create mode 100644 app/validate/admin/MenuValidate.php create mode 100644 app/validate/admin/MerchantCategoryValidate.php create mode 100644 app/validate/admin/MerchantTypeValidate.php create mode 100644 app/validate/admin/MerchantValidate.php create mode 100644 app/validate/admin/ParameterTemplateValidate.php create mode 100644 app/validate/admin/PriceRuleValidate.php create mode 100644 app/validate/admin/ProductLabelValidate.php create mode 100644 app/validate/admin/RoleValidate.php create mode 100644 app/validate/admin/SmsRegisterValidate.php create mode 100644 app/validate/admin/StoreActivityValidate.php create mode 100644 app/validate/admin/StoreBrandCategoryValidate.php create mode 100644 app/validate/admin/StoreBrandValidate.php create mode 100644 app/validate/admin/StoreCategoryValidate.php create mode 100644 app/validate/admin/StoreProductReplyValidate.php create mode 100644 app/validate/admin/StoreSeckillValidate.php create mode 100644 app/validate/admin/SystemNoticeConfigValidate.php create mode 100644 app/validate/admin/SystemNoticeValidate.php create mode 100644 app/validate/admin/TemplateMessageValidate.php create mode 100644 app/validate/admin/UserBrokerageValidate.php create mode 100644 app/validate/admin/UserGroupValidate.php create mode 100644 app/validate/admin/UserLabelValidate.php create mode 100644 app/validate/admin/UserNowMoneyValidate.php create mode 100644 app/validate/admin/UserValidate.php create mode 100644 app/validate/admin/WechatNewsValidate.php create mode 100644 app/validate/admin/WechatReplyValidate.php create mode 100644 app/validate/api/BackGoodsValidate.php create mode 100644 app/validate/api/ChangePasswordValidate.php create mode 100644 app/validate/api/CommunityValidate.php create mode 100644 app/validate/api/FeedbackValidate.php create mode 100644 app/validate/api/MerchantIntentionValidate.php create mode 100644 app/validate/api/OrderVirtualFieldValidate.php create mode 100644 app/validate/api/ProductReplyValidate.php create mode 100644 app/validate/api/StoreCartValidate.php create mode 100644 app/validate/api/StoreRefundOrderValidate.php create mode 100644 app/validate/api/UserAddressValidate.php create mode 100644 app/validate/api/UserAuthValidate.php create mode 100644 app/validate/api/UserBaseInfoValidate.php create mode 100644 app/validate/api/UserExtractValidate.php create mode 100644 app/validate/api/UserReceiptValidate.php create mode 100644 app/validate/merchant/BroadcastGoodsValidate.php create mode 100644 app/validate/merchant/BroadcastRoomValidate.php create mode 100644 app/validate/merchant/DeliveryStationValidate.php create mode 100644 app/validate/merchant/LabelRuleValidate.php create mode 100644 app/validate/merchant/MerchantApplymentsValidate.php create mode 100644 app/validate/merchant/MerchantFinancialAccountValidate.php create mode 100644 app/validate/merchant/MerchantTakeValidate.php create mode 100644 app/validate/merchant/MerchantUpdateValidate.php create mode 100644 app/validate/merchant/ServiceReplyValidate.php create mode 100644 app/validate/merchant/ShippingTemplateValidate.php create mode 100644 app/validate/merchant/StoreAttrTemplateValidate.php create mode 100644 app/validate/merchant/StoreCouponSendValidate.php create mode 100644 app/validate/merchant/StoreCouponValidate.php create mode 100644 app/validate/merchant/StoreDiscountsValidate.php create mode 100644 app/validate/merchant/StoreProductAdminValidate.php create mode 100644 app/validate/merchant/StoreProductAssistValidate.php create mode 100644 app/validate/merchant/StoreProductGroupValidate.php create mode 100644 app/validate/merchant/StoreProductPresellValidate.php create mode 100644 app/validate/merchant/StoreProductValidate.php create mode 100644 app/validate/merchant/StoreProductValidate.php.bak create mode 100644 app/validate/merchant/StoreSeckillProductValidate.php create mode 100644 app/validate/merchant/StoreServiceValidate.php create mode 100644 app/view/install/step1.html create mode 100644 app/view/install/step2.html create mode 100644 app/view/install/step3.html create mode 100644 app/view/install/step4.html create mode 100644 app/view/install/step5.html create mode 100644 app/view/mobile/view.html create mode 100644 app/webscoket/Manager.php create mode 100644 app/webscoket/Ping.php create mode 100644 app/webscoket/SwooleWorkerStart.php create mode 100644 app/webscoket/handler/AdminHandler.php create mode 100644 app/webscoket/handler/MerchantHandler.php create mode 100644 app/webscoket/handler/ServiceHandler.php create mode 100644 app/webscoket/handler/UserHandler.php create mode 100644 backup/.gitignore create mode 100644 cert_crmeb.key create mode 100644 cert_public.pam create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/admin.php create mode 100644 config/ajcaptcha.php create mode 100644 config/app.php create mode 100644 config/cache.php create mode 100644 config/console.php create mode 100644 config/cookie.php create mode 100644 config/crmeb.php create mode 100644 config/database.php create mode 100644 config/delivery.php create mode 100644 config/filesystem.php create mode 100644 config/lang.php create mode 100644 config/log.php create mode 100644 config/middleware.php create mode 100644 config/notice.php create mode 100644 config/qrcode.php create mode 100644 config/queue.php create mode 100644 config/route.php create mode 100644 config/session.php create mode 100644 config/sms.php create mode 100644 config/swoole.php create mode 100644 config/template.php create mode 100644 config/trace.php create mode 100644 config/upload.php create mode 100644 config/view.php create mode 100644 crmeb/basic/BaseAuth.php create mode 100644 crmeb/basic/BaseController.php create mode 100644 crmeb/basic/BaseManager.php create mode 100644 crmeb/basic/BaseMessage.php create mode 100644 crmeb/basic/BaseStorage.php create mode 100644 crmeb/basic/BaseUpload.php create mode 100644 crmeb/exceptions/AuthException.php create mode 100644 crmeb/exceptions/SmsException.php create mode 100644 crmeb/exceptions/UploadException.php create mode 100644 crmeb/exceptions/UploadFailException.php create mode 100644 crmeb/exceptions/WechatException.php create mode 100644 crmeb/interfaces/DeliveryInterface.php create mode 100644 crmeb/interfaces/JobInterface.php create mode 100644 crmeb/interfaces/ListenerInterface.php create mode 100644 crmeb/interfaces/MiddlewareInterface.php create mode 100644 crmeb/interfaces/RouteParserInterface.php create mode 100644 crmeb/interfaces/VersionUpdateInterface.php create mode 100644 crmeb/jobs/ApplyBroadcastGoodsJob.php create mode 100644 crmeb/jobs/AutoChangeStatusActivityJob.php create mode 100644 crmeb/jobs/AutoUserPosterJob.php create mode 100644 crmeb/jobs/BatchDeliveryJob.php create mode 100644 crmeb/jobs/CancelGroupBuyingJob.php create mode 100644 crmeb/jobs/CancelGroupOrderJob.php create mode 100644 crmeb/jobs/ChangeMerchantStatusJob.php create mode 100644 crmeb/jobs/ChangeSpuStatusJob.php create mode 100644 crmeb/jobs/CheckProductExtensionJob.php create mode 100644 crmeb/jobs/CheckProductPresellJob.php create mode 100644 crmeb/jobs/ClearCacheJob.php create mode 100644 crmeb/jobs/ClearMerchantStoreJob.php create mode 100644 crmeb/jobs/ClearUserIntegralJob.php create mode 100644 crmeb/jobs/CloseSvipCouponJob.php create mode 100644 crmeb/jobs/CloseUserSvipJob.php create mode 100644 crmeb/jobs/ExpressSyncJob.php create mode 100644 crmeb/jobs/GauaranteeCountJob.php create mode 100644 crmeb/jobs/ImportSpreadsheetExcelJob.php create mode 100644 crmeb/jobs/MerchantSendCouponJob.php create mode 100644 crmeb/jobs/OrderProfitsharingJob.php create mode 100644 crmeb/jobs/OrderReplyJob.php create mode 100644 crmeb/jobs/PayGiveCouponJob.php create mode 100644 crmeb/jobs/ProductImportJob.php create mode 100644 crmeb/jobs/SendNewPeopleCouponJob.php create mode 100644 crmeb/jobs/SendNewsJob.php create mode 100644 crmeb/jobs/SendSmsJob.php create mode 100644 crmeb/jobs/SendSvipCouponJob.php create mode 100644 crmeb/jobs/SendTemplateMessageJob.php create mode 100644 crmeb/jobs/SpreadsheetExcelJob.php create mode 100644 crmeb/jobs/SupplyChainOrderBrokerAgeJob.php create mode 100644 crmeb/jobs/SyncProductTopJob.php create mode 100644 crmeb/jobs/TestJob.php create mode 100644 crmeb/jobs/UpdateProductReplyJob.php create mode 100644 crmeb/jobs/UserBrokerageLevelJob.php create mode 100644 crmeb/jobs/UserHistoryJob.php create mode 100644 crmeb/listens/AuthCancelActivityListen.php create mode 100644 crmeb/listens/AuthCancelPresellOrderListen.php create mode 100644 crmeb/listens/AuthTakeOrderListen.php create mode 100644 crmeb/listens/AutoCancelGroupOrderListen.php create mode 100644 crmeb/listens/AutoCheckCouponListen.php create mode 100644 crmeb/listens/AutoClearIntegralListen.php create mode 100644 crmeb/listens/AutoOrderProfitsharingListen.php create mode 100644 crmeb/listens/AutoOrderReplyListen.php create mode 100644 crmeb/listens/AutoSendPayOrderSmsListen.php create mode 100644 crmeb/listens/AutoUnLockBrokerageListen.php create mode 100644 crmeb/listens/AutoUnLockIntegralListen.php create mode 100644 crmeb/listens/AutoUnlockMerchantMoneyListen.php create mode 100644 crmeb/listens/CloseUserSvipListen.php create mode 100644 crmeb/listens/CreateTimerListen.php create mode 100644 crmeb/listens/ExcelFileDelListen.php create mode 100644 crmeb/listens/GuaranteeCountListen.php create mode 100644 crmeb/listens/InitSwooleLockListen.php create mode 100644 crmeb/listens/MerchantApplyMentsCheckListen.php create mode 100644 crmeb/listens/ProductGroupStatusCheckListen.php create mode 100644 crmeb/listens/ProductPresellStatusListen.php create mode 100644 crmeb/listens/QueueListen.php create mode 100644 crmeb/listens/RefundOrderAgreeListen.php create mode 100644 crmeb/listens/SeckillTImeCheckListen.php create mode 100644 crmeb/listens/SendSvipCouponListen.php create mode 100644 crmeb/listens/SumCountListen.php create mode 100644 crmeb/listens/SwooleTaskListen.php create mode 100644 crmeb/listens/SwooleWorkerExitListen.php create mode 100644 crmeb/listens/SyncBroadcastStatusListen.php create mode 100644 crmeb/listens/SyncHotRankingListen.php create mode 100644 crmeb/listens/SyncSmsResultCodeListen.php create mode 100644 crmeb/listens/SyncSpreadStatusListen.php create mode 100644 crmeb/listens/pay/MealSuccessListen.php create mode 100644 crmeb/listens/pay/OrderMicroPaySuccessListen.php create mode 100644 crmeb/listens/pay/OrderPaySuccessListen.php create mode 100644 crmeb/listens/pay/PresellPaySuccessListen.php create mode 100644 crmeb/listens/pay/UserOrderSuccessListen.php create mode 100644 crmeb/listens/pay/UserRechargeSuccessListen.php create mode 100644 crmeb/services/AccessTokenServeService.php create mode 100644 crmeb/services/AlipayService.php create mode 100644 crmeb/services/ApiResponseService.php create mode 100644 crmeb/services/BaseExpress.php create mode 100644 crmeb/services/BaseProduct.php create mode 100644 crmeb/services/BaseSmss.php create mode 100644 crmeb/services/BlockPuzzleCaptchaService.php create mode 100644 crmeb/services/CacheService.php create mode 100644 crmeb/services/CombinePayService.php create mode 100644 crmeb/services/CopyCommand.php create mode 100644 crmeb/services/CopyProductService.php create mode 100644 crmeb/services/CrmebServeServices.php create mode 100644 crmeb/services/DeliverySevices.php create mode 100644 crmeb/services/DownloadImageService.php create mode 100644 crmeb/services/ExcelService.php create mode 100644 crmeb/services/ExpressService.php create mode 100644 crmeb/services/FileService.php create mode 100644 crmeb/services/HttpService.php create mode 100644 crmeb/services/ImageWaterMarkService.php create mode 100644 crmeb/services/JwtTokenService.php create mode 100644 crmeb/services/LockService.php create mode 100644 crmeb/services/MiniProgramService.php create mode 100644 crmeb/services/MysqlBackupService.php create mode 100644 crmeb/services/PayService.php create mode 100644 crmeb/services/PaymentService.php create mode 100644 crmeb/services/PrinterService.php create mode 100644 crmeb/services/QrcodeService.php create mode 100644 crmeb/services/RedisCacheService.php create mode 100644 crmeb/services/RoutineTemplateService.php create mode 100644 crmeb/services/SmsService.php create mode 100644 crmeb/services/SpreadsheetExcelService.php create mode 100644 crmeb/services/SwooleTaskService.php create mode 100644 crmeb/services/TimerService.php create mode 100644 crmeb/services/UpdateAuthInit.php create mode 100644 crmeb/services/UploadService.php create mode 100644 crmeb/services/VicWordService.php create mode 100644 crmeb/services/WechatService.php create mode 100644 crmeb/services/WechatService.php.bak create mode 100644 crmeb/services/WechatTemplateMessageService.php create mode 100644 crmeb/services/WechatUserGroupService.php create mode 100644 crmeb/services/WechatUserTagService.php create mode 100644 crmeb/services/YunxinSmsService.php create mode 100644 crmeb/services/alipay/AlipayNotify.php create mode 100644 crmeb/services/delivery/Delivery.php create mode 100644 crmeb/services/delivery/storage/Dada.php create mode 100644 crmeb/services/delivery/storage/Uupt.php create mode 100644 crmeb/services/easywechat/BaseClient.php create mode 100644 crmeb/services/easywechat/batches/Client.php create mode 100644 crmeb/services/easywechat/batches/ServiceProvider.php create mode 100644 crmeb/services/easywechat/broadcast/Client.php create mode 100644 crmeb/services/easywechat/broadcast/ServiceProvider.php create mode 100644 crmeb/services/easywechat/certficates/Client.php create mode 100644 crmeb/services/easywechat/certficates/ServiceProvider.php create mode 100644 crmeb/services/easywechat/combinePay/Client.php create mode 100644 crmeb/services/easywechat/combinePay/ServiceProvider.php create mode 100644 crmeb/services/easywechat/merchant/Client.php create mode 100644 crmeb/services/easywechat/merchant/ServiceProvider.php create mode 100644 crmeb/services/easywechat/miniPayment/Client.php create mode 100644 crmeb/services/easywechat/miniPayment/ServiceProvider.php create mode 100644 crmeb/services/easywechat/msgseccheck/Client.php create mode 100644 crmeb/services/easywechat/msgseccheck/ServiceProvider.php create mode 100644 crmeb/services/easywechat/pay/Client.php create mode 100644 crmeb/services/easywechat/pay/ServiceProvider.php create mode 100644 crmeb/services/easywechat/storePay/Client.php create mode 100644 crmeb/services/easywechat/storePay/ServiceProvider.php create mode 100644 crmeb/services/easywechat/subscribe/ProgramProvider.php create mode 100644 crmeb/services/easywechat/subscribe/ProgramSubscribe.php create mode 100644 crmeb/services/express/Express.php create mode 100644 crmeb/services/express/storage/Express.php create mode 100644 crmeb/services/printer/AccessToken.php create mode 100644 crmeb/services/printer/Printer.php create mode 100644 crmeb/services/printer/storage/YiLianYun.php create mode 100644 crmeb/services/product/Product.php create mode 100644 crmeb/services/product/storage/Copy.php create mode 100644 crmeb/services/serve/Serve.php create mode 100644 crmeb/services/serve/storage/Crmeb.php create mode 100644 crmeb/services/sms/Sms.php create mode 100644 crmeb/services/sms/storage/Aliyun.php create mode 100644 crmeb/services/sms/storage/Yunxin.php create mode 100644 crmeb/services/template/Template.php create mode 100644 crmeb/services/template/storage/Subscribe.php create mode 100644 crmeb/services/template/storage/Wechat.php create mode 100644 crmeb/services/upload/Upload.php create mode 100644 crmeb/services/upload/client/UploadManager.php create mode 100644 crmeb/services/upload/storage/Cos.php create mode 100644 crmeb/services/upload/storage/Local.php create mode 100644 crmeb/services/upload/storage/Obs.php create mode 100644 crmeb/services/upload/storage/Oss.php create mode 100644 crmeb/services/upload/storage/Qiniu.php create mode 100644 crmeb/services/upload/storage/Us3.php create mode 100644 crmeb/traits/CategoresDao.php create mode 100644 crmeb/traits/CategoresRepository.php create mode 100644 crmeb/traits/ErrorTrait.php create mode 100644 crmeb/traits/Macro.php create mode 100644 crmeb/utils/ApiErrorCode.php create mode 100644 crmeb/utils/Start.php create mode 100644 extend/.gitignore create mode 100644 think diff --git a/.example.env b/.example.env new file mode 100644 index 00000000..bb322f16 --- /dev/null +++ b/.example.env @@ -0,0 +1 @@ +APP_KEY = '#APP_KEY#' APP_DEBUG = false INSTALLED = true QUEUE_NAME = default [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql HOSTNAME = '#DB_HOST#' HOSTPORT = '#DB_PORT#' USERNAME = '#DB_USER#' PASSWORD = '#DB_PWD#' DATABASE = '#DB_NAME#' PREFIX = '#DB_PREFIX#' CHARSET = utf8 DEBUG = true [LANG] default_lang = zh-cn [REDIS] REDIS_HOSTNAME = '#RB_HOST#' PORT = '#RB_PORT#' REDIS_PASSWORD = '#RB_PWD#' SELECT = '#RB_SELECT#' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5d7803d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/.idea +/.vscode +*.log +.env +.phpstorm.meta.php +.constant +install/install.lock +public/static/download/* +public/phpExcel/* +app/controller/api/Test.php +public/protocol.html diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..36f7b6f9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,42 @@ +sudo: false + +language: php + +branches: + only: + - stable + +cache: + directories: + - $HOME/.composer/cache + +before_install: + - composer self-update + +install: + - composer install --no-dev --no-interaction --ignore-platform-reqs + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip . + - composer require --update-no-dev --no-interaction "topthink/think-image:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0" + - composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0" + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip . + +script: + - php think unit + +deploy: + provider: releases + api_key: + secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw= + file: + - ThinkPHP_Core.zip + - ThinkPHP_Full.zip + skip_cleanup: true + on: + tags: true diff --git a/.version b/.version new file mode 100644 index 00000000..727e9641 --- /dev/null +++ b/.version @@ -0,0 +1,3 @@ +version=CRMEB-MER-v2.1.1 +version_code=10 +code=2.1.1 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..574a39c4 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,32 @@ + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 +版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn) +All rights reserved。 +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +Apache Licence是著名的非盈利开源组织Apache采用的协议。 +该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, +允许代码修改,再作为开源或商业软件发布。需要满足 +的条件: +1. 需要给代码的用户一份Apache Licence ; +2. 如果你修改了代码,需要在被修改的文件中说明; +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 +带有原来代码中的协议,商标,专利声明和其他原来作者规 +定需要包含的说明; +4. 如果再发布的产品中包含一个Notice文件,则在Notice文 +件中需要带有本协议内容。你可以在Notice中增加自己的 +许可,但不可以表现为对Apache Licence构成更改。 +具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..2177bc1a --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# crmeb 多商户版 + +## 开发环境 + +- mac 10.15 +- php 7.2.22 +- mysql 5.7.27 +- swoole 4.4.8 +- redis 5.0.5 + +## 参与开发人员 + +- 产品: Amy, 木子刀客 + +- 设计: xy-yyds, LXT + +- 技术: Xaboy, Qinii, 郭小萌, 张三丰 + +- 测试: 绵绵羊, 夏天 + + +## 项目依赖 + +- thinkphp +- think-swoole +- overtrue/wechat +- xaboy/form-builder + +## 运行 + +开启 +```sh +php think swoole +``` +重启 +```sh +php think swoole restart +``` +关闭 +```sh +php think swoole stop +``` + +## 参与开发人员 + +产品: Amy + +设计: xy-yyds, LXT + +技术: Qinii, 郭小萌, xaboy + +测试: 夏天, 绵绵羊, 王多鱼 diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/app/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/app/AppService.php b/app/AppService.php new file mode 100644 index 00000000..e93a6ddb --- /dev/null +++ b/app/AppService.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +declare (strict_types = 1); + +namespace app; + +use think\Service; + +/** + * 应用服务类 + */ +class AppService extends Service +{ + public function register() + { + // 服务注册 + } + + public function boot() + { + // 服务启动 + } +} diff --git a/app/ExceptionHandle.php b/app/ExceptionHandle.php new file mode 100644 index 00000000..06a506e6 --- /dev/null +++ b/app/ExceptionHandle.php @@ -0,0 +1,86 @@ + +// +---------------------------------------------------------------------- + + +namespace app; + +use think\db\exception\DataNotFoundException; +use think\db\exception\ModelNotFoundException; +use think\db\exception\PDOException; +use think\exception\ErrorException; +use think\exception\Handle; +use think\exception\HttpException; +use think\exception\HttpResponseException; +use think\exception\ValidateException; +use think\Response; +use Throwable; + +/** + * 应用异常处理类 + */ +class ExceptionHandle extends Handle +{ + /** + * 不需要记录信息(日志)的异常类列表 + * @var array + */ + protected $ignoreReport = [ + HttpException::class, + HttpResponseException::class, + ModelNotFoundException::class, + DataNotFoundException::class, + ValidateException::class, + ]; + + /** + * 记录异常信息(包括日志或者其它方式记录) + * + * @access public + * @param Throwable $exception + * @return void + */ + public function report(Throwable $exception): void + { + // 使用内置的方式记录异常日志 + parent::report($exception); + } + + /** + * Render an exception into an HTTP response. + * + * @access public + * @param \think\Request $request + * @param Throwable $e + * @return Response + */ + public function render($request, Throwable $e): Response + { + // 添加自定义异常处理机制 + $this->report($e); + // 其他错误交给系统处理 + if ($e instanceof ValidateException) + return app('json')->fail($e->getMessage()); + else if ($e instanceof DataNotFoundException) + return app('json')->fail(isDebug() ? $e->getMessage() : '数据不存在'); + else if ($e instanceof ModelNotFoundException) + return app('json')->fail(isDebug() ? $e->getMessage() : '数据不存在'); + else if ($e instanceof PDOException) + return app('json')->fail(isDebug() ? $e->getMessage() : '数据库操作失败', isDebug() ? $e->getData() : []); + else if ($e instanceof ErrorException) + return app('json')->fail(isDebug() ? $e->getMessage() : '系统错误', isDebug() ? $e->getData() : []); + else if ($e instanceof \PDOException) + return app('json')->fail(isDebug() ? $e->getMessage() : '数据库连接失败'); + else if ($e instanceof \EasyWeChat\Core\Exceptions\HttpException) + return app('json')->fail($e->getMessage()); + + return parent::render($request, $e); + } +} diff --git a/app/Request.php b/app/Request.php new file mode 100644 index 00000000..ebd9dbec --- /dev/null +++ b/app/Request.php @@ -0,0 +1,190 @@ + +// +---------------------------------------------------------------------- + + +namespace app; + +use crmeb\traits\Macro; +use think\File; +use think\file\UploadedFile; + +class Request extends \think\Request +{ + use Macro; + + protected $cache = []; + + public function __construct() + { + parent::__construct(); + $this->filter[] = function ($val) { + return is_string($val) ? trim($val) : $val; + }; + } + + public function ip(): string + { + return $this->header('remote-host') ?? parent::ip(); + } + + public function isApp() + { + return $this->header('Form-type') === 'app'; + } + + /** + * @param $db + * @param $key + * @return bool + * @author xaboy + * @day 2020/10/22 + */ + public function hasCache($db, $key) + { + return isset($this->cache[$db][$key]); + } + + /** + * @param $db + * @param $key + * @return array|mixed|string + * @author xaboy + * @day 2020/10/22 + */ + public function getCache($db, $key) + { + if (is_array($key)) { + $data = []; + foreach ($key as $v) { + $data[$v] = $this->getCache($db, $v); + } + return $data; + } + return $this->cache[$db][$key] ?? ''; + } + + /** + * @param $db + * @param $key + * @param null $value + * @author xaboy + * @day 2020/10/22 + */ + public function setCache($db, $key, $value = null) + { + if (!isset($this->cache[$db])) $this->cache[$db] = []; + if (is_array($key)) { + foreach ($key as $k => $v) { + $this->setCache($db, $k, $v); + } + return; + } + $this->cache[$db][$key] = $value; + } + + public function clearCache() + { + $this->cache = []; + } + + public function params(array $names, $filter = '') + { + $data = []; + $flag = false; + if ($filter === true) { + $filter = ''; + $flag = true; + } + foreach ($names as $name) { + if (!is_array($name)) + $data[$name] = $this->param($name, '', $filter); + else + $data[$name[0]] = $this->param($name[0], $name[1], $filter); + } + + return $flag ? array_values($data) : $data; + } + + public function merId() + { + return intval($this->hasMacro('merchantId') ? $this->merchantId() : 0); + } + + public function setOriginFile($name, $array) + { + $this->file[$name] = $array; + } + + public function getOriginFile($name) + { + return $this->file[$name] ?? null; + } + + + protected function dealUploadFile(array $files, string $name): array + { + $array = []; + foreach ($files as $key => $file) { + if (is_array($file['name'])) { + $item = []; + $keys = array_keys($file); + $count = count($file['name']); + + for ($i = 0; $i < $count; $i++) { + if ($file['error'][$i] > 0) { + if ($name == $key) { + $this->throwUploadFileError($file['error'][$i]); + } else { + continue; + } + } + + $temp['key'] = $key; + + foreach ($keys as $_key) { + $temp[$_key] = $file[$_key][$i]; + + $name = explode('.',$temp['name']); + $num = count($name); + $suffix = strtolower($name[$num - 1]); + array_pop($name); + $temp['name'] = implode('.',$name).'.'.$suffix; + } + + $item[] = new UploadedFile($temp['tmp_name'], $temp['name'], $temp['type'], $temp['error']); + } + + $array[$key] = $item; + } else { + if ($file instanceof File) { + $array[$key] = $file; + } else { + if ($file['error'] > 0) { + if ($key == $name) { + $this->throwUploadFileError($file['error']); + } else { + continue; + } + } + + $name = explode('.',$file['name']); + $num = count($name); + $suffix = strtolower($name[$num - 1]); + array_pop($name); + $file['name'] = implode('.',$name).'.'.$suffix; + + $array[$key] = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); + } + } + } + return $array; + } +} diff --git a/app/command/ClearCacheAttachment.php b/app/command/ClearCacheAttachment.php new file mode 100644 index 00000000..9f8e6556 --- /dev/null +++ b/app/command/ClearCacheAttachment.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\system\auth\MenuRepository; +use think\console\Command; +use think\console\Input; +use think\console\Output; + +/** + * Class FormatMenuPath + * @package app\command + * @author xaboy + * @day 2020/8/26 + */ +class ClearCacheAttachment extends Command +{ + /** + * @author xaboy + * @day 2020/9/21 + */ + protected function configure() + { + // 指令配置 + $this->setName('clear:attachment') + ->setDescription('clear cache attachment'); + } + + + /** + * @param Input $input + * @param Output $output + * @return int|void|null + * @author xaboy + * @day 2020/9/21 + */ + protected function execute(Input $input, Output $output) + { + $output->writeln('开始清理'); + app()->make(AttachmentRepository::class)->clearCache(); + $output->writeln('开始完毕'); + } + +} diff --git a/app/command/ClearMerchantData.php b/app/command/ClearMerchantData.php new file mode 100644 index 00000000..b9386e54 --- /dev/null +++ b/app/command/ClearMerchantData.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- + + +namespace app\command; + + +use think\console\Command; +use think\console\Input; +use think\console\Output; +use think\facade\Db; + +class ClearMerchantData extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('clear:merchant') + ->setDescription('清空数据(除系统配置以外的所有数据)'); + } + + protected function execute(Input $input, Output $output) + { + $flag = $output->confirm($input, '清空数据前务必做好数据库的备份,防止数据被误删 !!!', false); + if (!$flag) return; + $tables = Db::query('SHOW TABLES FROM ' . env('database.database', '')); + $pre = env('database.prefix', ''); + $bakTables = [ + $pre . 'page_link', + $pre . 'page_category', + $pre . 'diy', + $pre . 'city_area', + $pre . 'express', + $pre . 'system_admin', + $pre . 'system_city', + $pre . 'system_config', + $pre . 'system_config_classify', + $pre . 'system_config_value', + $pre . 'system_group', + $pre . 'system_group_data', + $pre . 'system_menu', + $pre . 'system_role', + $pre . 'template_message', + $pre . 'system_notice_config', + $pre . 'cache', + ]; + + foreach ($tables as $table) { + $name = array_values($table)[0]; + if (!in_array($name, $bakTables)) { + Db::table($name)->delete(true); + } + } + Db::table( $pre . 'cache')->whereNotIn('key','copyright_context,copyright_image,copyright_status')->delete(true); + $output->info('删除成功'); + } + +} diff --git a/app/command/ClearRedundancy.php b/app/command/ClearRedundancy.php new file mode 100644 index 00000000..6e446d03 --- /dev/null +++ b/app/command/ClearRedundancy.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\command; + + +use app\common\repositories\system\merchant\MerchantRepository; +use think\console\Command; +use think\console\Input; +use think\console\Output; +use think\facade\Log; + +class ClearRedundancy extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('clear:redundancy') + ->setDescription('已删除的商户的商品相关数据'); + } + + protected function execute(Input $input, Output $output) + { + try{ + app()->make(MerchantRepository::class)->clearRedundancy(); + }catch (\Exception $exception){ + Log::info('清除冗余错误:'.$exception->getMessage()); + } + $output->info('执行成功'); + } + +} diff --git a/app/command/FormatMenuPath.php b/app/command/FormatMenuPath.php new file mode 100644 index 00000000..1f07b2dc --- /dev/null +++ b/app/command/FormatMenuPath.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use app\common\repositories\system\auth\MenuRepository; +use think\console\Command; +use think\console\Input; +use think\console\Output; + +/** + * Class FormatMenuPath + * @package app\command + * @author xaboy + * @day 2020/8/26 + */ +class FormatMenuPath extends Command +{ + /** + * @author xaboy + * @day 2020/8/26 + */ + protected function configure() + { + // 指令配置 + $this->setName('menu:format') + ->setDescription('the format menu command'); + } + + + /** + * @param Input $input + * @param Output $output + * @return int|void|null + * @author xaboy + * @day 2020/8/26 + */ + protected function execute(Input $input, Output $output) + { + $output->writeln('开启修复'); + $menuRepository = app()->make(MenuRepository::class); + $menuRepository->formatPath(0); + $menuRepository->formatPath(1); + $output->writeln('执行成功'); + } + +} diff --git a/app/command/VersionUpdate.php b/app/command/VersionUpdate.php new file mode 100644 index 00000000..a3423fc4 --- /dev/null +++ b/app/command/VersionUpdate.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + + +namespace app\command; + + +use think\console\Command; +use think\console\Input; +use think\console\input\Option; +use think\console\Output; +use think\Exception; +use think\facade\Db; + +class VersionUpdate extends Command +{ + protected function configure() + { + $this->setName('version:update') + ->setDescription('crmeb_merchant 版本更新命令') + ->addOption('package', 'p', Option::VALUE_REQUIRED, '指定更新包的路径'); + } + + protected function execute(Input $input, Output $output) + { + $flag = $output->confirm($input, '更新之前请务必做好数据库和代码的备份,防止数据或代码在更新中被覆盖 !!!', false); + if (!$flag) return; + $flag = $output->confirm($input, '请确保swoole服务和队列服务已关闭,防止意外报错', false); + if (!$flag) return; + + $version = get_crmeb_version_code(); + ini_set('memory_limit', '-1'); + set_time_limit(0); + + $packagePath = $input->getOption('package') ?: 'auto_update.zip'; + $updateFilePath = app()->getRootPath() . ltrim($packagePath, '/= '); + $updatePath = dirname($updateFilePath); + $unzipPath = $updatePath . '/_update_runtime_' . str_replace('.', '_', $version); + if (!is_file($updateFilePath)) { + $output->warning($updateFilePath . ' 更新包不存在'); + return; + } + $zip = new \ZipArchive(); + if ($zip->open($updateFilePath) === true) { + $zip->extractTo($unzipPath); + $zip->close(); + } else { + $output->warning($updateFilePath . ' 更新包打开失败'); + return; + } + + $unlink = function () use ($unzipPath) { + @unlink($unzipPath . '/update.sql'); + @unlink($unzipPath . '/update.zip'); + @unlink($unzipPath . '/AutoUpdate.php'); + @unlink($unzipPath . '/.env'); + @unlink($unzipPath . '/.config'); + @rmdir($unzipPath); + }; + + if (!is_file($unzipPath . '/.env') && !is_file($unzipPath . '/.config')) { + $output->warning('文件不完整'); + $unlink(); + return; + } + + if (is_file($unzipPath . '/.env')) { + $env = parse_ini_file($unzipPath . '/.env', true) ?: []; + } + + if (is_file($unzipPath . '/.config')) { + $env = parse_ini_file($unzipPath . '/.config', true) ?: []; + } + if (($env['NAME'] ?? '') !== 'CRMEB-MERCHANT' || ((($env['OLD_VERSION'] ?? '') && ($env['OLD_VERSION'] ?? '') !== $version))) { + if (($env['TYPE'] ?? '') !== 'MODEL') { + $output->warning('版本号对比失败,请检查当前版本号(.version/更新包)是否被修改'); + $unlink(); + return; + } + } + + $confirm = []; + if (isset($env['confirm'])) { + $confirm = is_array($env['confirm']) ? $env['confirm'] : [$env['confirm']]; + } + foreach ($confirm as $item) { + if (!$output->confirm($input, $item, false)) { + $unlink(); + return; + } + } + $installHost = systemConfig('site_url'); + if (substr($installHost, 0, 5) == 'https'){ + $_url = str_replace('//' ,'\\\/\\\/', $installHost); + } else { + $_url = str_replace('http://' ,'http:\\\/\\\/', $installHost); + } + + if (is_file($unzipPath . '/update.sql')) { + $str = preg_replace('/--.*/i', '', file_get_contents($unzipPath . '/update.sql')); + $str = preg_replace('/\/\*.*\*\/(\;)?/i', '', $str); + $sqlList = explode(";\n", $str); + } else { + $sqlList = []; + } + $autoUpdateData = null; + if (is_file($unzipPath . '/AutoUpdate.php')) { + try { + require_once $unzipPath . '/AutoUpdate.php'; + $autoUpdateData = new \crmeb\update\AutoUpdate($input, $output); + } catch (\Throwable $e) {} + } + + if ($autoUpdateData) $autoUpdateData->autoUpdateStart(); + $output->info('开始更新'); + $pre = env('database.prefix'); + try { + Db::transaction(function () use ($pre, $output, $unzipPath, $sqlList, $autoUpdateData,$installHost,$_url) { + if ($autoUpdateData) $autoUpdateData->autoUpdateBefore(); + $count = count($sqlList); + if ($count && $autoUpdateData) { + $autoUpdateData->autoSqlBefore(); + } + foreach ($sqlList as $idx => $sql) { + $sql = trim($sql, " \xEF\xBB\xBF\r\n"); + if (!$sql) continue; + if ($pre && $pre !== 'eb_') { + $sql = str_replace('eb_', $pre, $sql); + } + $sql = str_replace('https://mer1.crmeb.net', $installHost , $sql); + $sql = str_replace('https:\\\/\\\/mer1.crmeb.net', $_url , $sql); + Db::query($sql . ';'); + if (!($idx % 50)) { + $output->info("导入中($idx/$count)"); + } + } + if ($count) { + if ($autoUpdateData) $autoUpdateData->autoSqlAfter(); + $output->info('数据库更新成功'); + } + $zip = new \ZipArchive(); + if ($zip->open($unzipPath . '/update.zip') === true) { + if ($autoUpdateData) $autoUpdateData->autoCopyBefore(); + $zip->extractTo(app()->getRootPath()); + $zip->close(); + if ($autoUpdateData) $autoUpdateData->autoCopyAfter(); + } else { + throw new Exception('更新文件覆盖失败'); + } + }); + if ($autoUpdateData) $autoUpdateData->autoUpdateAfter(); + } catch (\Throwable $e) { + $output->warning('更新失败:' . $e->getMessage()); + $unlink(); + if ($autoUpdateData) $autoUpdateData->autoUpdateFail($e); + return; + } + + $unlink(); + if ($autoUpdateData) $autoUpdateData->autoUpdateEnd(); + $output->info('版本更新成功, 请重启swoole服务和队列服务'); + + update_crmeb_compiled(); + } + +} diff --git a/app/command/changeHotTop.php b/app/command/changeHotTop.php new file mode 100644 index 00000000..57ca90c1 --- /dev/null +++ b/app/command/changeHotTop.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use crmeb\jobs\SyncProductTopJob; +use think\console\Command; +use think\console\Input; +use think\console\Output; +use think\facade\Queue; + +class changeHotTop extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('change:hotTop') + ->setDescription('清楚缓存:php think change:hotTop'); + } + + /** + * TODO + * @param Input $input + * @param Output $output + * @return int|void|null + * @author Qinii + * @day 4/24/22 + */ + protected function execute(Input $input, Output $output) + { + Queue::push(SyncProductTopJob::class,[]); + $output->writeln('执行成功'); + } + +} diff --git a/app/command/clearCache.php b/app/command/clearCache.php new file mode 100644 index 00000000..301fcaaa --- /dev/null +++ b/app/command/clearCache.php @@ -0,0 +1,75 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use Swoole\Coroutine\MySQL\Exception; +use think\console\Command; +use think\console\Input; +use think\console\input\Argument; +use think\console\input\Option; +use think\console\Output; +use think\event\RouteLoaded; +use think\facade\Cache; +use think\facade\Route; +use app\common\repositories\system\auth\MenuRepository; + +class clearCache extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('clearCache') + ->addArgument('cacheType',Argument::OPTIONAL, 'php think menu [1] / [2]') + ->setDescription('清楚缓存:php think clearCache 1'); + } + + /** + * TODO + * @param Input $input + * @param Output $output + * @return int|void|null + * @author Qinii + * @day 4/24/22 + */ + protected function execute(Input $input, Output $output) + { + $type = $input->getArgument('cacheType'); + $tag = ['sys_login_freeze','mer_login_freeze']; + $msg = ''; + switch ($type) { + case 0: + $msg = '平台登录限制'; + $tag = 'sys_login_freeze'; + break; + case 1: + $msg = '商户登录限制'; + $tag = 'mer_login_freeze'; + break; + } + Cache::tag($tag)->clear(); + $output->writeln('清楚缓存'.$msg); + } + + +} diff --git a/app/command/resetImagePath.php b/app/command/resetImagePath.php new file mode 100644 index 00000000..21381985 --- /dev/null +++ b/app/command/resetImagePath.php @@ -0,0 +1,196 @@ +setName('reset:imagePath') + ->addArgument('path', Argument::OPTIONAL, 'path:http:/crmeb.com') + ->addOption('url', null, Option::VALUE_REQUIRED, 'change:http:/crmeb1.com', '/') + ->setDescription('php think reset:imagePath http://old.com --url http://new.com'); + } + + protected function execute(Input $input, Output $output) + { + $this->path = rtrim($input->getArgument('path'), '/'); + if ($input->hasOption('url')) { + $this->change = rtrim($input->getOption('url'), '/'); + if (!$this->change) $this->change = '/'; + } + + $output->writeln('开始执行'); + foreach ($this->type as $type) { + $models = $this->switchModel($type); + + foreach ($models as $model) { + + $this->getResult($model, $type); + } + } + $output->info('执行完成'); + } + + protected function getResult($model, $type) + { + if (is_null($model)) return; + + try { + $key = $model->getPk(); + if ($key){ + $model->chunk(100, function ($data) { + foreach ($data as $item) { + $save = 0; + foreach ($this->field as $f) { + if (isset($item->$f) && !empty($item->$f)) { + $sr = $this->changeImage($item->$f); + $item->$f = $sr; + $save = 1; + } + } + if ($save) $item->save(); + } + }); + } + return; + } catch (\Exception $exception) { + Log::info('图片处理异常:' . $exception->getMessage()); + } + } + + protected function changeImage($data) + { + if (!$data) return $data; + echo PHP_EOL; + echo '替换前:'; + print_r($data); + if (is_array($data)) { + $load = implode(',', $data); + $load1 = str_replace($this->path, $this->change, $load); + $string = explode(',', $load1); + } else { + $string = str_replace($this->path, $this->change, $data); + } + echo PHP_EOL; + echo '替换后:'; + print_r($string); + echo PHP_EOL; + return $string; + } + + protected function switchModel($type) + { + $model = []; + // 商品规格 + $model[] = (new ProductAttrValue()); + // 商品规格 + $model[] = (new ProductAssistUser()); + // 商品规格 + $model[] = (new ProductGroupUser()); + // 商品 + $model[] = (new Product()); + // 直播间 + $model[] = (new BroadcastRoom()); + // 直播间商品 + $model[] = (new BroadcastGoods()); + // 服务保障 + $model[] = (new Guarantee()); + // 分类 + $model[] = (new StoreCategory()); + // 商品评价 + $model[] = (new ProductReply()); + // spu + $model[] = (new Spu()); + // 文章 + $model[] = (new Article()); + // 文章分类 + $model[] = (new ArticleCategory()); + + // 社区 + $model[] = (new Community()); + // 社区话题 + $model[] = (new CommunityTopic()); + + // 流水 + $model[] = (new Financial()); + // 会员 + $model[] = (new UserBrokerage()); + // 会员权益 + $model[] = (new MemberInterests()); + // 商户 + $model[] = (new Merchant()); + // 商户权益 + $model[] = (new MerchantIntention()); + + // 客服 + $model[] = (new StoreService()); + // 秒杀配置 + $model[] = (new StoreSeckillTime()); + // 素材 + $model[] = (new Attachment()); + // 用户 + $model[] = (new User()); + + return $model; + } +} + diff --git a/app/command/resetPassword.php b/app/command/resetPassword.php new file mode 100644 index 00000000..34edba6e --- /dev/null +++ b/app/command/resetPassword.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use app\common\repositories\system\admin\AdminRepository; +use think\console\Command; +use think\console\Input; +use think\console\input\Argument; +use think\console\Output; +use think\console\input\Option; + +class resetPassword extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('reset:password') + ->addArgument('root', Argument::OPTIONAL, 'root : admin') + ->addOption('pwd', null, Option::VALUE_REQUIRED, 'pwd : 123456') + ->setDescription('php think admin --pwd 123'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/15 + * @param Input $input + * @param Output $output + * @return int|void|null + */ + protected function execute(Input $input, Output $output) + { + $account = $input->getArgument('root'); + if ($input->hasOption('pwd')){ + $pwd = $input->getOption('pwd'); + } + $make = app()->make(AdminRepository::class); + $accountData = $make->accountByAdmin($account); + if(!$accountData) { + $output->warning('管理员账号不存在'); + }else{ + $pwd_ = $make->passwordEncode($pwd); + $accountData->pwd = $pwd_; + $accountData->save(); + $output->info('账号:'.$account.';密码已重置:'.$pwd); + } + } +} diff --git a/app/command/updateAuth.php b/app/command/updateAuth.php new file mode 100644 index 00000000..1b257556 --- /dev/null +++ b/app/command/updateAuth.php @@ -0,0 +1,171 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use Swoole\Coroutine\MySQL\Exception; +use think\console\Command; +use think\console\Input; +use think\console\input\Argument; +use think\console\input\Option; +use think\console\Output; +use think\event\RouteLoaded; +use think\facade\Route; +use app\common\repositories\system\auth\MenuRepository; + +class updateAuth extends Command +{ + protected $k = []; + protected $kv =[]; + + protected function configure() + { + // 指令配置 + $this->setName('setAuth') + ->addArgument('prompt',Argument::OPTIONAL, 'php think menu [s] / [e]') + ->setDescription('使用方法: `php think menu` , 可选传参数 s 只显示成功信息'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/15 + * @param Input $input + * @param Output $output + * @return int|void|null + */ + protected function execute(Input $input, Output $output) + { + $prompt = $input->getArgument('prompt'); + $output->writeln('开始执行'); + $output->writeln('<----------------'); + $output->writeln('开始平台权限'); + $sys = $this->routeList('sys',$prompt); + + $output->writeln('开始商户权限'); + + $mer = $this->routeList('mer',$prompt); + $output->writeln('<----------------'); + $output->writeln('平台执行成功,合计: '. $sys .'条 , 商户执行成功,合计: '. $mer .'条'); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/15 + * @param string|null $dir + * @return mixed + */ + public function routeList($type, $prompt) + { + $this->k = []; + $this->kv = []; + $this->app->route->setTestMode(true); + $this->app->route->clear(); + $path = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR; + + if ($type == 'sys') + include $path . 'admin.php'; +// include $path . 'admin/config.php'; + if ($type == 'mer') + include $path . 'merchant.php'; + //触发路由载入完成事件 + $this->app->event->trigger(RouteLoaded::class); + $routeList = $this->app->route->getRuleList(); + $resp = []; + + foreach ($routeList as $k => $item) { + if ($item['option'] && isset($item['option']['_auth']) && $item['option']['_auth']) { + if (!(strpos($item['name'], '/') !== false) && !(strpos($item['name'], '@') !== false)) { + if (isset($item['option']['_init'])) { + $route = (new $item['option']['_init'][0]())->create($item, $item['option']['_init'][1]); + } else { + $route = [$item]; + } + if ($route) { + foreach ($route as $one) { + if (!isset($one['option']['_name'])) $one['option']['_name'] = $one['name']; + $this->menu($one['option']['_path'] ?? '', $one['option'], $resp); + } + } + } + } + } + return app()->make(MenuRepository::class)->commandMenu($type, $resp, $prompt); + } + + + /** + * TODO + * @param $_path + * @param $data + * @param array $resp + * @return array + * @author Qinii + * @day 3/18/22 + */ + protected function menu($_path, $data, &$resp = [], $isAppend = 0) + { + $check = true; + if ($_path && is_array($data)) { + $v = [ + 'route' => $data['_name'], + 'menu_name' => $data['_alias'] ?? '权限', + 'params' => $data['_params'] ?? '', + ]; + if (!isset($data['_repeat']) || (isset($data['_repeat']) && !$data['_repeat'])){ + $check = $this->checkRepeat($v['route'], $v['menu_name']); + $this->k[] = $v['route']; + $this->kv[$v['route']] = $v['menu_name']; + } + + if (!$check) { + throw new Exception( "路由名重复 < " . $v['route']. ' >' . '「'. $v['menu_name']. ' 」'); + } + if ($isAppend) { + $_path = 'append_'.$_path; + } + + $resp[$_path][$data['_name']] = $v; + + if (isset($data['_append']) && !empty($data['_append'])) { + foreach ($data['_append'] as $datum) { + $datum['_repeat'] = true; + $this->menu($datum['_path'] ?? $data['_path'], $datum, $resp, 1); + } + } + } + return $resp; + } + + protected function checkRepeat($key, $value) + { + if (in_array($key, $this->k)) { + if ($value != $this->kv[$key]) { + return false; + } + } + return true; + } + + +} diff --git a/app/command/updateSpu.php b/app/command/updateSpu.php new file mode 100644 index 00000000..efb0e160 --- /dev/null +++ b/app/command/updateSpu.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +declare (strict_types=1); + +namespace app\command; + +use app\common\repositories\store\product\SpuRepository; +use think\console\Command; +use think\console\Input; +use think\console\Output; +use think\console\input\Option; + +class updateSpu extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('spu') + ->addOption('productType', null, Option::VALUE_REQUIRED, 'product type :0,1,2,3') + ->setDescription('the update spu command'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/15 + * @param Input $input + * @param Output $output + * @return int|void|null + */ + protected function execute(Input $input, Output $output) + { + $prodcutType = []; + if ($input->hasOption('productType')){ + $tyep = $input->getOption('productType'); + if(in_array($tyep,[0,1,2,3,4])) $prodcutType = [$tyep]; + } + + + $output->writeln('开始执行'); + $this->checkAndUpdateSpu($prodcutType); + $output->writeln('执行完成'); + } + + public function checkAndUpdateSpu($prodcutType) + { + app()->make(SpuRepository::class)->updateSpu($prodcutType); + } +} diff --git a/app/common.php b/app/common.php new file mode 100644 index 00000000..cc258ef0 --- /dev/null +++ b/app/common.php @@ -0,0 +1,1156 @@ + +// +---------------------------------------------------------------------- + +// 应用公共文件 + +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use crmeb\services\UploadService; +use Swoole\Lock; +use think\db\BaseQuery; + +if (!function_exists('go')) { + function go(): bool + { + return \Swoole\Coroutine::create(...func_get_args()); + } +} + +if (!function_exists('isDebug')) { + function isDebug(): bool + { + return !!env('APP_DEBUG'); + } +} + +if (!function_exists('formToData')) { + function formToData($form): array + { + $rule = $form->formRule(); + $action = $form->getAction(); + $method = $form->getMethod(); + $title = $form->getTitle(); + $config = (object)$form->formConfig(); + $admin = config('admin.api_admin_prefix'); + $merchant = config('admin.api_merchant_prefix'); + $api = $action; + if (strpos($api, '/' . $admin) === 0) { + $api = substr($api, strlen($admin) + 1); + } else if (strpos($api, '/' . $merchant) === 0) { + $api = substr($api, strlen($merchant) + 1); + } + $api = str_replace('.html', '', $api); + return compact('rule', 'action', 'method', 'title', 'config', 'api'); + } +} + +if (!function_exists('getDistance')) { + + function getDistance($lat1, $lng1, $lat2, $lng2) + { + //将角度转为狐度 + $radLat1 = deg2rad($lat1); //deg2rad()函数将角度转换为弧度 + $radLat2 = deg2rad($lat2); + $radLng1 = deg2rad($lng1); + $radLng2 = deg2rad($lng2); + $a = $radLat1 - $radLat2; + $b = $radLng1 - $radLng2; + $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6371; + return round($s, 1); + } +} + +/** + * 无线级分类处理 + * + * @param array $data 数据源 + * @param string $idName 主键 + * @param string $fieldName 父级字段 + * @param string $childrenKey 子级字段名 + * @return array + * @author 张先生 + * @date 2020-03-27 + */ +if (!function_exists('formatCategory')) { + function formatCategory(array $data, string $idName = "id", string $fieldName = 'pid', $childrenKey = 'children') + { + $items = []; + foreach ($data as $item) { + $items[$item[$idName]] = $item; + } + $result = array(); + foreach ($items as $item) { + if (isset($items[$item[$fieldName]])) { + $items[$item[$fieldName]][$childrenKey][] = &$items[$item[$idName]]; + } else if ($item[$fieldName] == 0) { + $result[] = &$items[$item[$idName]]; + } + } + return $result; + } +} + +if (!function_exists('formatTreeList')) { + function formatTreeList(&$options, $name, $pidName = 'pid', $pid = 0, $level = 0, &$data = []): array + { + $_options = $options; + foreach ($_options as $k => $option) { + if ($option[$pidName] == $pid) { + $data[] = ['value' => $k, 'label' => str_repeat('|---', $level + 1) . $option[$name]]; + unset($options[$k]); + formatTreeList($options, $name, $pidName, $k, $level + 1, $data); + } + } + return $data; + } +} + +if (!function_exists('formatTree')) { + function formatTree(&$options, $name, $pidName = 'pid', $pid = 0, $level = 0, $data = []): array + { + $_options = $options; + foreach ($_options as $k => $option) { + if ($option[$pidName] == $pid) { + $value = ['id' => $k, 'title' => $option[$name]]; + unset($options[$k]); + $value['children'] = formatTree($options, $name, $pidName, $k, $level + 1); + $data[] = $value; + } + } + return $data; + } +} + +if (!function_exists('formatCascaderData')) { + function formatCascaderData(&$options, $name, $baseLevel = 0, $pidName = 'pid', $pid = 0, $level = 0, $data = []): array + { + $_options = $options; + foreach ($_options as $k => $option) { + if ($option[$pidName] == $pid) { + $value = ['value' => $k, 'label' => $option[$name]]; + unset($options[$k]); + $value['children'] = formatCascaderData($options, $name, $baseLevel, $pidName, $k, $level + 1); + if (!count($value['children'])) unset($value['children']); + $data[] = $value; + } + } + return $data; + } +} + + +/** + * @function toMap 数组重新组装 + * @param array $data 数据 + * @param string $field key + * @param string $value value default null + * @return array + * @author 张先生 + * @date 2020-04-01 + */ +if (!function_exists('toMap')) { + function toMap(array $data, $field = 'id', $value = '') + { + $result = array(); + + if (empty($data)) { + return $result; + } + + //开始处理数据 + foreach ($data as $item) { + $val = $item; + if (!empty($value)) { + $val = $item[$value]; + } + $result[$item[$field]] = $val; + } + + return $result; + } +} + +/** + * @function getUniqueListByArray 从数组中获取某个字段的值,重新拼装成新的一维数组 + * @param array $data 数据 + * @param string $field key + * @return array + * @author 张先生 + * @date 2020-04-01 + */ +if (!function_exists('getUniqueListByArray')) { + function getUniqueListByArray(array $data, $field = 'id') + { + return array_unique(array_values(array_column($data, $field))); + } +} + + +if (!function_exists('isPhone')) { + function isPhone($test) + { + return !preg_match("/^1[3456789]{1}\d{9}$/", $test); + } +} + +if (!function_exists('getMonth')) { + /** + * 获取本季度 time + * @param int|string $time + * @param $ceil + * @return array + */ + function getMonth($time = '', $ceil = 0) + { + if ($ceil != 0) + $season = ceil(date('n') / 3) - $ceil; + else + $season = ceil(date('n') / 3); + $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y'))); + $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y'))); + return array($firstday, $lastday); + } +} + + +if (!function_exists('getModelTime')) { + /** + * @param BaseQuery $model + * @param string $section + * @param string $prefix + * @param string $field + * @return mixed + * @author xaboy + * @day 2020-04-29 + */ + function getModelTime(BaseQuery $model, string $section, $prefix = 'create_time', $field = '-',$time = '') + { + if (!isset($section)) return $model; + switch ($section) { + case 'today': + $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('today')), date('Y-m-d H:i:s', strtotime('tomorrow -1second'))]); + break; + case 'week': + $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('this week 00:00:00')), date('Y-m-d H:i:s', strtotime('next week 00:00:00 -1second'))]); + break; + case 'month': + $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('first Day of this month 00:00:00')), date('Y-m-d H:i:s', strtotime('first Day of next month 00:00:00 -1second'))]); + break; + case 'year': + $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('this year 1/1')), date('Y-m-d H:i:s', strtotime('next year 1/1 -1second'))]); + break; + case 'yesterday': + $model->whereBetween($prefix, [date('Y-m-d H:i:s', strtotime('yesterday')), date('Y-m-d H:i:s', strtotime('today -1second'))]); + break; + case 'quarter': + list($startTime, $endTime) = getMonth(); + $model = $model->where($prefix, '>', $startTime); + $model = $model->where($prefix, '<', $endTime); + break; + case 'lately7': + $model = $model->where($prefix, 'between', [date('Y-m-d', strtotime("-7 day")), date('Y-m-d H:i:s')]); + break; + case 'lately30': + $model = $model->where($prefix, 'between', [date('Y-m-d', strtotime("-30 day")), date('Y-m-d H:i:s')]); + break; + default: + if (strstr($section, $field) !== false) { + list($startTime, $endTime) = explode($field, $section); + if (strlen($startTime) == 4) { + $model->whereBetweenTime($prefix, date('Y-m-d H:i:s', strtotime($section)), date('Y-m-d H:i:s', strtotime($section . ' +1day -1second'))); + } else { + if ($startTime == $endTime) { + $model = $model->whereBetweenTime($prefix, date('Y-m-d 0:0:0', strtotime($startTime)), date('Y-m-d 23:59:59', strtotime($endTime))); + } else if(strpos($startTime, ':')) { + $model = $model->whereBetweenTime($prefix, $startTime, $endTime); + } else { + $model = $model->whereBetweenTime($prefix, date('Y-m-d H:i:s', strtotime($startTime)), date('Y-m-d H:i:s', strtotime($endTime . ' +1day -1second'))); + } + } + } + break; + } + return $model; + } +} + +if (!function_exists('hasMany')) { + function hasMany($collection, $field, $model, $searchKey, $insertKey, $where = [] ,$select = '*') + { + $ids = []; + $link = []; + + if (!$collection) return []; + $collection = $collection->toArray(); + foreach ($collection as $k => $item) { + if (is_array($item[$field])) { + $link[$k] = array_unique($item[$field]); + $ids = array_merge($item[$field], $ids); + } else { + $link[$k] = array_unique(explode(',', $item[$field])); + } + $ids = array_merge($link[$k], $ids); + if (isset($collection[$k][$insertKey])) unset($collection[$k][$insertKey]); + } + $ids = array_filter(array_unique($ids)); + if (!count($ids)) { + return $collection; + } + $many = $model::whereIn($searchKey, array_unique($ids))->where($where)->field($select)->select(); + + if (!$many) return $collection; + $many = $many->toArray(); + foreach ($link as $k => $val) { + foreach ($many as $item) { + if (in_array($item[$searchKey], $val)) { + + if (!isset($collection[$k][$insertKey])) $collection[$k][$insertKey] = []; + + $collection[$k][$insertKey][] = $item; + } + } + } + + return $collection; + } +} + +if (!function_exists('activeProductSku')) { + //格式活动商品SKU + function activeProductSku($activeData, $type = null) + { + $make = app()->make(\app\common\repositories\store\product\ProductRepository::class); + $price = 0; + $data = []; + foreach($activeData as $key => $value) { + $maxPrice = 0; + $must_price = 0; + $attrValue = []; + if(is_null($value['product'])) continue; + $productSku = $value['productSku']; + $productAttr = $value['product']['attr']; + $productAttrValue = $value['product']['attrValue']; + unset($value['productSku'], $value['product']['attrValue'], $value['product']['attr']); + foreach ($productAttrValue as $attr_value) { + if (!empty($productSku)){ + foreach ($productSku as $sk => $sv) { + if ( $sv['unique'] == $attr_value['unique']) { + if ($type == 'discounts') { + unset($attr_value['ot_price'], $attr_value['price']); + $attr_value['ot_price'] = $sv['price']; + $attr_value['price'] = $sv['active_price']; + $_price = bcsub($sv['price'], $sv['active_price'], 2); + if ($value['type']){ + $must_price = $must_price > $_price ? $must_price : $_price; + } else { + $maxPrice = $maxPrice > $_price ? $maxPrice : $_price; + } + } else { + $attr_value['productSku'] = $sv; + } + $attrValue[] = $attr_value; + } + } + } + } + $attr = $make->detailAttr($productAttr); + if ($type == 'discounts') { + $sku = $make->detailAttrValue($attrValue, null); + $value['product']['sku'] = $sku; + + } else { + $value['product']['attrValue'] = $attrValue; + } + $value['product']['attr'] = $attr; + $price = bcadd($price, bcadd($must_price,$maxPrice,2), 2); + if ($value['type'] == 1) { + array_unshift($data,$value); + }else { + $data[] = $value; + } + } + return compact('data', 'price'); + } +} + + +if (!function_exists('systemConfig')) { + /** + * 获取系统配置 + * + * @param string|string[] $key + * @return mixed + * @author xaboy + * @day 2020-05-08 + */ + function systemConfig($key) + { + return merchantConfig(0, $key); + } +} + +if (!function_exists('getDatesBetweenTwoDays')) { + function getDatesBetweenTwoDays($startDate, $endDate) + { + $dates = []; + if (strtotime($startDate) > strtotime($endDate)) { + //如果开始日期大于结束日期,直接return 防止下面的循环出现死循环 + return $dates; + } elseif ($startDate == $endDate) { + //开始日期与结束日期是同一天时 + array_push($dates, date('m-d', strtotime($startDate))); + return $dates; + } else { + array_push($dates, date('m-d', strtotime($startDate))); + $currentDate = $startDate; + do { + $nextDate = date('Y-m-d', strtotime($currentDate . ' +1 days')); + array_push($dates, date('m-d', strtotime($currentDate . ' +1 days'))); + $currentDate = $nextDate; + } while ($endDate != $currentDate); + return $dates; + } + } +} + +if (!function_exists('getStartModelTime')) { + function getStartModelTime(string $section) + { + switch ($section) { + case 'today': + case 'yesterday': + return date('Y-m-d', strtotime($section)); + case 'week': + return date('Y-m-d', strtotime('this week')); + case 'month': + return date('Y-m-d', strtotime('first Day of this month')); + case 'year': + return date('Y-m-d', strtotime('this year 1/1')); + case 'quarter': + list($startTime, $endTime) = getMonth(); + return $startTime; + case 'lately7': + return date('Y-m-d', strtotime("-7 day")); + case 'lately30': + return date('Y-m-d', strtotime("-30 day")); + default: + if (strstr($section, '-') !== false) { + list($startTime, $endTime) = explode('-', $section); + return date('Y-m-d H:i:s', strtotime($startTime)); + } + return date('Y-m-d H:i:s'); + } + } +} + +if (!function_exists('merchantConfig')) { + /** + * 获取商户配置 + * + * @param int $merId + * @param string|string[] $key + * @return mixed + * @author xaboy + * @day 2020-05-08 + */ + function merchantConfig(int $merId, $key) + { + $request = request(); + $make = app()->make(ConfigValueRepository::class); + if (is_array($key)) { + $_key = []; + $cacheData = []; + foreach ($key as $v) { + if ($request->hasCache($merId, $v)) { + $cacheData[$v] = $request->getCache($merId, $v); + } else { + $_key[] = $v; + } + } + if (!count($_key)) return $cacheData; + $data = $make->more($_key, $merId); + $request->setCache($merId, $data); + $data += $cacheData; + } else { + if ($request->hasCache($merId, $key)) { + $data = $request->getCache($merId, $key); + } else { + $data = $make->get($key, $merId); + $request->setCache($merId, $key, $data); + } + } + return $data; + } +} + +if (!function_exists('systemGroupData')) { + /** + * 获取总后台组合数据配置 + * + * @param string $key + * @param int|null $page + * @param int|null $limit + * @return array + * @author xaboy + * @day 2020/5/27 + */ + function systemGroupData(string $key, ?int $page = null, ?int $limit = 10) + { + $make = app()->make(GroupDataRepository::class); + return $make->groupData($key, 0, $page, $limit); + } +} + +if (!function_exists('merchantGroupData')) { + /** + * 获取商户后台组合数据配置 + * + * @param int $merId + * @param string $key + * @param int|null $page + * @param int|null $limit + * @return array + * @author xaboy + * @day 2020/5/27 + */ + function merchantGroupData(int $merId, string $key, ?int $page = null, ?int $limit = 10) + { + $make = app()->make(GroupDataRepository::class); + return $make->groupData($key, $merId, $page, $limit); + } +} + +if (!function_exists('filter_emoji')) { + + // 过滤掉emoji表情 + function filter_emoji($str) + { + $str = preg_replace_callback( //执行一个正则表达式搜索并且使用一个回调进行替换 + '/./u', + function (array $match) { + return strlen($match[0]) >= 4 ? '' : $match[0]; + }, + $str + ); + return $str; + } +} + +if (!function_exists('setHttpType')) { + + /** + * TODO 修改 https 和 http 移动到common + * @param $url $url 域名 + * @param int $type 0 返回https 1 返回 http + * @return string + */ + function setHttpType($url, $type = 0) + { + $domainTop = substr($url, 0, 5); + if ($type) { + if ($domainTop == 'https') $url = 'http' . substr($url, 5, strlen($url)); + } else { + if ($domainTop != 'https') $url = 'https:' . substr($url, 5, strlen($url)); + } + return $url; + } +} + +if (!function_exists('remoteImage')) { + + /** + * TODO 获取小程序二维码是否生成 + * @param $url + * @return array + */ + function remoteImage($url) + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $result = curl_exec($curl); + $result = json_decode($result, true); + if (is_array($result)) return ['status' => false, 'msg' => $result['errcode'] . '---' . $result['errmsg']]; + return ['status' => true]; + } +} + +if (!function_exists('image_to_base64')) { + /** + * 获取图片转为base64 + * @param string $avatar + * @return bool|string + */ + function image_to_base64($avatar = '', $timeout = 9) + { + checkSuffix($avatar); + try { + $url = parse_url($avatar); + $url = $url['host']; + $header = [ + 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:45.0) Gecko/20100101 Firefox/45.0', + 'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', + 'Accept-Encoding: gzip, deflate, br', + 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', + 'Host:' . $url + ]; + $dir = pathinfo($url); + $host = $dir['dirname']; + $refer = $host . '/'; + $curl = curl_init(); + curl_setopt($curl, CURLOPT_REFERER, $refer); + curl_setopt($curl, CURLOPT_URL, $avatar); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_ENCODING, 'gzip'); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); + $data = curl_exec($curl); + $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + if ($code == 200) { + return "data:image/jpeg;base64," . base64_encode($data); + } else { + return false; + } + } catch (Exception $e) { + return false; + } + } +} + + +if (!function_exists('put_image')) { + /** + * 获取图片转为base64 + * @param string $avatar + * @return bool|string + */ + function put_image($url, $filename = '') + { + + if ($url == '') { + return false; + } + try { + if ($filename == '') { + + $ext = pathinfo($url); + if ($ext['extension'] != "jpg" && $ext['extension'] != "png" && $ext['extension'] != "jpeg") { + return false; + } + $filename = time() . "." . $ext['extension']; + } + + //文件保存路径 + ob_start(); + readfile($url); + $img = ob_get_contents(); + ob_end_clean(); + $path = 'public/uploads/qrcode'; + $fp2 = fopen($path . '/' . $filename, 'a'); + fwrite($fp2, $img); + fclose($fp2); + return $path . '/' . $filename; + } catch (Exception $e) { + return false; + } + } +} + +if (!function_exists('path_to_url')) { + /** + * 路径转url路径 + * @param $path + * @return string + */ + function path_to_url($path) + { + return trim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '.'); + } +} + +if (!function_exists('tidy_url')) { + /** + * 路径转url路径 + * @param $url + * @param int $http + * @param string $site + * @return string + */ + function tidy_url($url, $http = null, $site = null) + { + if (!$site) { + $site = systemConfig('site_url'); + } + $url = path_to_url($url); + if (strpos($url, 'http') === false) + $url = rtrim($site, '/') . '/' . ltrim($url, '/'); + + if (is_null($http)) { + $http = (parse_url($site)['scheme'] ?? '') == 'https' ? 0 : 1; + } + $url = set_http_type($url, $http); + return $url; + } +} + + +if (!function_exists('curl_file_exist')) { + /** + * CURL 检测远程文件是否在 + * @param $url + * @return bool + */ + function curl_file_exist($url) + { + $ch = curl_init(); + try { + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); + $contents = curl_exec($ch); + if (preg_match("/404/", $contents)) return false; + if (preg_match("/403/", $contents)) return false; + return true; + } catch (Exception $e) { + return false; + } + } +} + + +if (!function_exists('set_http_type')) { + /** + * 修改 https 和 http + * @param $url $url 域名 + * @param int $type 0 返回https 1 返回 http + * @return string + */ + function set_http_type($url, $type = 0) + { + $domainTop = substr($url, 0, 5); + if ($type) { + if ($domainTop == 'https') $url = 'http' . substr($url, 5, strlen($url)); + } else { + if ($domainTop != 'https') $url = 'https:' . substr($url, 5, strlen($url)); + } + return $url; + } +} + +if (!function_exists('setSharePoster')) { + /** + * TODO 生成分享二维码图片 + * @param array $config + * @param $path + * @return array|bool|string + * @throws Exception + */ + function setSharePoster($config, $path) + { + $imageDefault = array( + 'left' => 0, + 'top' => 0, + 'right' => 0, + 'bottom' => 0, + 'width' => 100, + 'height' => 100, + 'opacity' => 100 + ); + $textDefault = array( + 'text' => '', + 'left' => 0, + 'top' => 0, + 'fontSize' => 32, //字号 + 'fontColor' => '255,255,255', //字体颜色 + 'angle' => 0, + ); + $background = $config['background']; //海报最底层得背景 + if (substr($background, 0, 1) === '/') { + $background = substr($background, 1); + } + $backgroundInfo = getimagesize($background); + $background = imagecreatefromstring(file_get_contents($background)); + $backgroundWidth = $backgroundInfo[0]; //背景宽度 + $backgroundHeight = $backgroundInfo[1]; //背景高度 + $imageRes = imageCreatetruecolor($backgroundWidth, $backgroundHeight); + $color = imagecolorallocate($imageRes, 0, 0, 0); + imagefill($imageRes, 0, 0, $color); + imagecopyresampled($imageRes, $background, 0, 0, 0, 0, imagesx($background), imagesy($background), imagesx($background), imagesy($background)); + if (!empty($config['image'])) { + foreach ($config['image'] as $key => $val) { + $val = array_merge($imageDefault, $val); + $info = getimagesize($val['url']); + $function = 'imagecreatefrom' . image_type_to_extension($info[2], false); + if ($val['stream']) { + $info = getimagesizefromstring($val['url']); + $function = 'imagecreatefromstring'; + } + $res = $function($val['url']); + $resWidth = $info[0]; + $resHeight = $info[1]; + $canvas = imagecreatetruecolor($val['width'], $val['height']); + imagefill($canvas, 0, 0, $color); + imagecopyresampled($canvas, $res, 0, 0, 0, 0, $val['width'], $val['height'], $resWidth, $resHeight); + $val['left'] = $val['left'] < 0 ? $backgroundWidth - abs($val['left']) - $val['width'] : $val['left']; + $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) - $val['height'] : $val['top']; + imagecopymerge($imageRes, $canvas, $val['left'], $val['top'], $val['right'], $val['bottom'], $val['width'], $val['height'], $val['opacity']); //左,上,右,下,宽度,高度,透明度 + } + } + if (isset($config['text']) && !empty($config['text'])) { + foreach ($config['text'] as $key => $val) { + $val = array_merge($textDefault, $val); + list($R, $G, $B) = explode(',', $val['fontColor']); + $fontColor = imagecolorallocate($imageRes, $R, $G, $B); + $val['left'] = $val['left'] < 0 ? $backgroundWidth - abs($val['left']) : $val['left']; + $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) : $val['top']; + imagettftext($imageRes, $val['fontSize'], $val['angle'], $val['left'], $val['top'], $fontColor, $val['fontPath'], $val['text']); + } + } + ob_start(); + imagejpeg($imageRes); + imagedestroy($imageRes); + $res = ob_get_contents(); + ob_end_clean(); + $key = substr(md5(rand(0, 9999)), 0, 5) . date('YmdHis') . rand(0, 999999) . '.jpg'; + $uploadType = (int)systemConfig('upload_type') ?: 1; + $upload = UploadService::create($uploadType); + $res = $upload->to($path)->validate()->stream($res, $key); + if ($res === false) { + return $upload->getError(); + } else { + $info = $upload->getUploadInfo(); + $info['image_type'] = $uploadType; + return $info; + } + } +} + +if (!function_exists('getTimes')) { + function getTimes() + { + $dates = []; + for ($i = 0; $i <= 24; $i++) { + for ($j = 0; $j < 60; $j++) { + $dates[] = sprintf('%02.d', $i) . ':' . sprintf('%02.d', $j); + } + } + return $dates; + } +} + +if (!function_exists('monday')) { + /** + * 获取周一 + * + * @param null $time + * @return false|string + * @author xaboy + * @day 2020/6/22 + */ + function monday($time = null) + { + return date('Y-m-d', strtotime('Sunday -6 day', $time ?: time())); + } +} + +if (!function_exists('orderLock')) { + /** + * @param string $name + * @return Lock + * @author xaboy + * @day 2020/8/25 + */ + function makeLock($name = 'default'): Lock + { + return $GLOBALS['_swoole_order_lock'][$name]; + } +} + +if (!function_exists('get_crmeb_version')) { + /** + * 获取CRMEB系统版本号 + * @param string $default + * @return string + */ + function get_crmeb_version($default = 'v1.0.0') + { + try { + $version = parse_ini_file(app()->getRootPath() . '.version'); + return $version['version'] ?? $default; + } catch (Throwable $e) { + return $default; + } + } +} + +if (!function_exists('get_crmeb_version_code')) { + /** + * 获取CRMEB系统版本号 + * @param string $default + * @return string + */ + function get_crmeb_version_code($default = '1.7.2') + { + try { + $version = parse_ini_file(app()->getRootPath() . '.version'); + return $version['code'] ?? $default; + } catch (Throwable $e) { + return $default; + } + } +} + +if (!function_exists('update_crmeb_compiled')) { + /** + * 获取CRMEB系统版本号 + * @param string $default + * @return string + */ + function update_crmeb_compiled($default = 'v1.0.0') + { + $compiled = [ + '7.1' => 'compiled71', + '7.2' => 'compiled72', + '7.3' => 'compiled73', + '7.4' => 'compiled74', + ]; + + $phpv = @phpversion(); + $phpvs = substr($phpv, 0, 3); + $key = $compiled[$phpvs] ?? ''; + if (!$key) + return false; + $root = app()->getRootPath(); + $compiledPath = $root . 'install/compiled'; + $file = $root . 'install/compiled/' . $key . '.zip'; + $toPath = $root . 'crmeb/basic'; + $toConfigPath = $root . 'config/crmeb.php'; + try { + if (is_file($file)) { + $zip = new ZipArchive(); + if ($zip->open($file) === true) { + $zip->extractTo($compiledPath . '/'); + $zip->close(); + } + if (is_dir($compiledPath . '/basic')) { + if (is_dir($toPath) || mkdir($toPath, 0777) || is_dir($toPath)) { + foreach (glob($compiledPath . '/basic/*') as $item) { + @rename($item, $toPath . '/' . pathinfo($item, PATHINFO_BASENAME)); + } + } + @rmdir($compiledPath . '/basic'); + } + if (is_file($compiledPath . '/crmeb.php')) { + @rename($compiledPath . '/crmeb.php', $toConfigPath); + } + } + } catch (\Exception $exception) { + return false; + } + return true; + } +} + +if (!function_exists('attr_format')) { + /** + * 格式化属性 + * @param $arr + * @return array + */ + function attr_format($arr) + { + $data = []; + $res = []; + $count = count($arr); + if ($count > 1) { + for ($i = 0; $i < $count - 1; $i++) { + if ($i == 0) $data = $arr[$i]['detail']; + //替代变量1 + $rep1 = []; + foreach ($data as $v) { + foreach ($arr[$i + 1]['detail'] as $g) { + //替代变量2 + $rep2 = ($i != 0 ? '' : $arr[$i]['value'] . '_$_') . $v . '-$-' . $arr[$i + 1]['value'] . '_$_' . $g; + $tmp[] = $rep2; + if ($i == $count - 2) { + foreach (explode('-$-', $rep2) as $k => $h) { + //替代变量3 + $rep3 = explode('_$_', $h); + //替代变量4 + $rep4['detail'][$rep3[0]] = isset($rep3[1]) ? $rep3[1] : ''; + } + if ($count == count($rep4['detail'])) + $res[] = $rep4; + } + } + } + $data = isset($tmp) ? $tmp : []; + } + } else { + $dataArr = []; + foreach ($arr as $k => $v) { + foreach ($v['detail'] as $kk => $vv) { + $dataArr[$kk] = $v['value'] . '_' . $vv; + $res[$kk]['detail'][$v['value']] = $vv; + } + } + $data[] = implode('-', $dataArr); + } + return [$data, $res]; + } +} + +if (!function_exists('filter_emoji')) { + //过滤掉emoji表情 + function filter_emoji($str) + { + $str = preg_replace_callback('/./u', function (array $match) { + return strlen($match[0]) >= 4 ? '' : $match[0]; + }, $str); + return $str; + } +} + +/* + * TODO 腾讯地图转换百度地图 GCJ02 转 BD09 + * 中国正常GCJ02坐标---->百度地图BD09坐标 + * 腾讯地图/高德地图用的也是GCJ02坐标 + * @param double $lat 纬度 + * @param double $lng 经度 + */ +if (!function_exists('gcj02ToBd09')) { + function gcj02ToBd09($lng, $lat) + { + $x_pi = 3.14159265358979324 * 3000.0 / 180.0; + $x = $lng; + $y = $lat; + $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi); + $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi); + + $lng = $z * cos($theta) + 0.0065; + $lat = $z * sin($theta) + 0.006; + return [$lng,$lat]; + } +} + +if (!function_exists('lbs_address')) { + function lbs_address($region, $address) + { + $locationOption = new \Joypack\Tencent\Map\Bundle\AddressOption(systemConfig('tx_map_key')); + $locationOption->setAddress($address); + $locationOption->setRegion($region); + $location = new \Joypack\Tencent\Map\Bundle\Address($locationOption); + $res = $location->request(); + if ($res->error) { + throw new \think\exception\ValidateException($res->error); + } + if ($res->status) { + throw new \think\exception\ValidateException($res->message); + } + if (!$res->result) { + throw new \think\exception\ValidateException('获取失败'); + } + return $res->result; + } +} + + +if (!function_exists('aj_captcha_check_one')) { + /** + * 验证滑块1次验证 + * @param string $token + * @param string $pointJson + * @return bool + */ + function aj_captcha_check_one(string $captchaType, string $token, string $pointJson) + { + aj_get_serevice($captchaType)->check($token, $pointJson); + return true; + } +} + +if (!function_exists('aj_captcha_check_two')) { + /** + * 验证滑块2次验证 + * @param string $token + * @param string $pointJson + * @return bool + */ + function aj_captcha_check_two(string $captchaType, string $captchaVerification ) + { + aj_get_serevice($captchaType)->verificationByEncryptCode($captchaVerification); + return true; + } +} + + +if (!function_exists('aj_captcha_create')) { + /** + * 创建验证码 + * @return array + */ + function aj_captcha_create(string $captchaType) + { + return aj_get_serevice($captchaType)->get(); + } +} + +if (!function_exists('aj_get_serevice')) { + + function aj_get_serevice(string $captchaType) + { + $config = \think\facade\Config::get('ajcaptcha'); + switch ($captchaType) { + case "clickWord": + $service = new \Fastknife\Service\ClickWordCaptchaService($config); + break; + case "blockPuzzle": +// $service = new \Fastknife\Service\BlockPuzzleCaptchaService($config); + $service = new \crmeb\services\BlockPuzzleCaptchaService($config); + break; + default: + throw new \think\exception\ValidateException('captchaType参数不正确:'.$captchaType); + } + return $service; + } +} + +if (!function_exists('checkSuffix')) { + function checkSuffix($data) + { + $suffix = \think\facade\Config::get('upload.fileExt'); + if (is_array($data)){ + foreach ($data as $datum) { + if (strpos($datum,'phar://') !== false) + throw new \think\exception\ValidateException('操作失败'); + $result = pathinfo($datum); + if (isset($result['extension']) && !in_array($result['extension'],$suffix)) { + throw new \think\exception\ValidateException('文件后缀不允许'); + } + } + } else { + if (strpos($data,'phar://') !== false ) + throw new \think\exception\ValidateException('操作失败'); + $result = pathinfo($data); + if (isset($result['extension']) && !in_array($result['extension'],$suffix)) { + throw new \think\exception\ValidateException('文件后缀不允许'); + } + } + return ; + } +} + + + diff --git a/app/common/dao/BaseDao.php b/app/common/dao/BaseDao.php new file mode 100644 index 00000000..36f04a97 --- /dev/null +++ b/app/common/dao/BaseDao.php @@ -0,0 +1,310 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao; + + +use app\common\model\BaseModel; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\db\Query; +use think\Model; + +/** + * Class BaseDao + * @package app\common\dao + * @author xaboy + * @day 2020-03-30 + */ +abstract class BaseDao +{ + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + abstract protected function getModel(): string; + + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public function getPk() + { + return ($this->getModel())::tablePk(); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function exists(int $id) + { + return $this->fieldExists($this->getPk(), $id); + } + + public function merInExists(int $merId, $ids) + { + $pk = ($this->getModel())::getDB()->where('mer_id',$merId)->where($this->getPk(),'in',$ids)->column($this->getPk()); + $ids = is_array($ids) ? $ids : explode(',',$ids); + sort($ids); + sort($pk); + return $ids == $pk; + } + + /** + * @param array $where + * @return BaseModel + */ + public function query(array $where):Query + { + return ($this->getModel())::getInstance()->where($where); + } + + /** + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-30 + */ + public function fieldExists($field, $value, ?int $except = null): bool + { + $query = ($this->getModel())::getDB()->where($field, $value); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->count() > 0; + } + + /** + * @param array $data + * @return self|Model + * @author xaboy + * @day 2020-03-27 + */ + public function create(array $data) + { + return ($this->getModel())::create($data); + } + + + /** + * @param int $id + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function update(int $id, array $data) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->update($data); + } + + /** + * @param array $ids + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function updates(array $ids, array $data) + { + return ($this->getModel())::getDB()->whereIn($this->getPk(), $ids)->update($data); + } + + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function delete(int $id) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->delete(); + } + + + /** + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function get($id) + { + return ($this->getModel())::getInstance()->find($id); + } + + /** + * @param array $where + * @param string $field + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function getWhere(array $where, string $field = '*', array $with = []) + { + return ($this->getModel())::getInstance()->where($where)->when($with, function ($query) use ($with) { + $query->with($with); + })->field($field)->find(); + } + + /** + * @param array $where + * @param string $field + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function selectWhere(array $where, string $field = '*') + { + return ($this->getModel())::getInstance()->where($where)->field($field)->select(); + } + + /** + * @param int $id + * @param array $with + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function getWith(int $id, $with = []) + { + return ($this->getModel())::getInstance()->with($with)->find($id); + } + + + /** + * @param array $data + * @return int + * @author xaboy + * @day 2020/6/8 + */ + public function insertAll(array $data) + { + return ($this->getModel())::getDB()->insertAll($data); + } + + /** + * TODO 通过条件判断是否存在 + * @param array $where + * @author Qinii + * @day 2020-06-13 + */ + public function getWhereCount(array $where) + { + return ($this->getModel()::getDB())->where($where)->count(); + } + + public function existsWhere($where) + { + return ($this->getModel())::getDB()->where($where)->count() > 0; + } + + /** + * TODO 查询,如果不存在就创建 + * @Author:Qinii + * @Date: 2020/9/8 + * @param array $where + * @return array|Model|null + */ + public function findOrCreate(array $where) + { + $res = ($this->getModel()::getDB())->where($where)->find(); + if(!$res)$res = $this->getModel()::create($where); + return $res; + } + + /** + * TODO 搜索 + * @param $where + * @return BaseModel + * @author Qinii + * @day 2020-10-16 + */ + public function getSearch(array $where) + { + foreach ($where as $key => $item) { + if ($item !== '') { + $keyArray[] = $key; + $whereArr[$key] = $item; + } + } + if(empty($keyArray)){ + return ($this->getModel())::getDB(); + }else{ + return ($this->getModel())::withSearch($keyArray, $whereArr); + } + } + + /** + * TODO 自增 + * @param array $id + * @param string $field + * @param int $num + * @return mixed + * @author Qinii + * @day 1/11/21 + */ + public function incField(int $id, string $field , $num = 1) + { + return ($this->getModel()::getDB())->where($this->getPk(),$id)->inc($field,$num)->update(); + } + + /** + * TODO 自减 + * @param array $id + * @param string $field + * @param int $num + * @return mixed + * @author Qinii + * @day 1/11/21 + */ + public function decField(int $id, string $field , $num = 1) + { + return ($this->getModel()::getDB()) + ->where($this->getPk(),$id) + ->where($field, '>=' ,$num) + ->dec($field,$num)->update(); + } + + public function merHas(int $merId, int $id, ?int $isDel = 0) + { + return ($this->getModel()::getDB())->where($this->getPk(), $id)->where('mer_id', $merId) + ->when(!is_null($isDel), function($query) use($isDel) { + $query->where('is_del', $isDel); + })->count($this->getPk()) > 0; + } +} diff --git a/app/common/dao/article/ArticleCategoryDao.php b/app/common/dao/article/ArticleCategoryDao.php new file mode 100644 index 00000000..707a87f4 --- /dev/null +++ b/app/common/dao/article/ArticleCategoryDao.php @@ -0,0 +1,143 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\article; + + +use app\common\dao\BaseDao; +use app\common\model\article\ArticleCategory; +use app\common\model\BaseModel; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class ArticleCategoryDao + * @package app\common\dao\article + * @author xaboy + * @day 2020-04-20 + */ +class ArticleCategoryDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return ArticleCategory::class; + } + + /** + * @param int $mer_id + * @return array + * @author xaboy + * @day 2020-04-20 + */ + public function getAllOptions($mer_id = 0) + { + return ArticleCategory::getDB()->where('mer_id', $mer_id)->order('sort DESC')->column('pid,title', $this->getPk()); + } + + /** + * @param int $mer_id + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-20 + */ + public function getAll($mer_id = 0,$status = null) + { + return ArticleCategory::getDB()->where('mer_id', $mer_id)->when($status,function($query)use($status){ + $query->where('status',$status); + })->order('sort DESC')->select(); + } + + /** + * @param array $where + * @return \think\db\BaseQuery + * @author xaboy + * @day 2020/9/18 + */ + public function search(array $where) + { + return ArticleCategory::getDB()->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + })->when(isset($where['pid']) && $where['pid'] !== '', function ($query) use ($where) { + $query->where('pid', $where['pid']); + })->order('sort DESC, article_category_id DESC'); + } + + /** + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + * @author xaboy + * @day 2020-04-20 + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where('mer_id', $merId)->where($field, $value)->count() > 0; + } + + /** + * @param int $merId + * @param int $id + * @param null $except + * @return bool + * @author xaboy + * @day 2020-04-20 + */ + public function merExists(int $merId, int $id, $except = null) + { + return $this->merFieldExists($merId, $this->getPk(), $id, $except); + } + + /** + * @param int $id + * @param int $merId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function get( $id, $merId = 0) + { + return ($this->getModel())::getDB()->where('mer_id', 0)->find($id); + } + + /** + * @param int $id + * @param int $merId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function delete(int $id, $merId = 0) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->where('mer_id', $merId)->delete(); + } +} diff --git a/app/common/dao/article/ArticleContentDao.php b/app/common/dao/article/ArticleContentDao.php new file mode 100644 index 00000000..fecd673a --- /dev/null +++ b/app/common/dao/article/ArticleContentDao.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\article; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; + +class ArticleContentDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return ArticleContentDao::class; + } +} diff --git a/app/common/dao/article/ArticleDao.php b/app/common/dao/article/ArticleDao.php new file mode 100644 index 00000000..a7c3377f --- /dev/null +++ b/app/common/dao/article/ArticleDao.php @@ -0,0 +1,192 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\article; + +use think\Collection; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use app\common\dao\BaseDao; +use app\common\model\article\Article; +use app\common\model\BaseModel; +use think\Model; + +class ArticleDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Article::class; + } + + /** + * @param int $mer_id + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function getAll($mer_id = 0) + { + return Article::getDB()->with('content')->where('mer_id', $mer_id)->select(); + } + + /** + * 搜索列表 + * @param $merId + * @param array $where + * @return BaseQuery + * @author Qinii + */ + public function search($merId,array $where) + { + $query = Article::getDB(); + if (isset($where['cid']) && $where['cid'] !== '') $query->where('cid', (int)$where['cid']); + if (isset($where['title']) && $where['title'] !== '') $query->whereLike('title', "%{$where['title']}%"); + if (isset($where['status']) && $where['status'] !== '') $query->where('status', $where['status']); + if (isset($where['wechat_news_id']) && $where['wechat_news_id'] !== '') $query->where('wechat_news_id', $where['wechat_news_id']); + + if (isset($where['article_id']) && $where['article_id'] !== ''){ + if (is_array($where['article_id'])) { + $query->whereIn('article_id', $where['article_id']); + } else { + $query->where('article_id', $where['article_id']); + } + + } + + + $query->with(['content','articleCategory']); + + return $query->where('mer_id',$merId)->order('sort DESC,create_time DESC'); + } + + + + /** + * 根据 字段名查询 + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + * @author Qinii + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where('mer_id', $merId)->where('wechat_news_id',0)->where($field, $value)->count() > 0; + } + + /** + * 查询一条 + * @param int $merId + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + * + */ + public function get( $id, int $merId = 0) + { + return ($this->getModel())::getDB()->where('mer_id', $merId)->where('wechat_news_id',0)->with(['content','articleCategory'])->find($id); + } + + /** + * @param int $id + * @param int $merId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function delete(int $id, int $merId = 0) + { + $result = ($this->getModel())::getDB()->where('mer_id', $merId) + ->where($this->getPk(),$id) + ->with('content') + ->find(); + return $result->together(['content'])->delete(); + } + + + /** + * 关联添加 + * @param array $data + * @return BaseDao|Model|void + * @author Qinii + */ + public function create(array $data) + { + Db::transaction(function()use($data){ + $content = $data['content']; + unset($data['content']); + $article = $this->getModel()::create($data); + $article->content()->save(['content' => $content]); + }); + } + + /** + * 关联更新 + * @param int $id + * @param array $data + * @return int|void + * @author Qinii + */ + public function update(int $id, array $data) + { + Db::transaction(function()use($id,$data){ + $content = $data['content']; + unset($data['content']); + + $this->getModel()::where($this->getPk(),$id)->update($data); + + $article = $this->getModel()::find($id); + $article->content->content = $content; + $article->together(['content'])->save(); + }); + } + + /** + * 根据字段获取 主键值 + * @param int $vale + * @param null $field + * @return array + * @author Qinii + */ + public function getKey(int $vale,$field = null) + { + return ($this->getModel())::getDB()->where($field,$vale)->column($this->getPk()); + } + + public function wechatNewIdByData($id) + { + return ($this->getModel())::getDB()->where('wechat_news_id', $id)->select(); + } + + public function switchStatus($id, $data) + { + return ($this->getModel())::getDB()->where($this->getPk(),$id)->update($data); + } +} diff --git a/app/common/dao/community/CommunityCategoryDao.php b/app/common/dao/community/CommunityCategoryDao.php new file mode 100644 index 00000000..0f7dd362 --- /dev/null +++ b/app/common/dao/community/CommunityCategoryDao.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\community; + + +use app\common\dao\BaseDao; +use app\common\model\community\CommunityCategory; +use crmeb\traits\CategoresDao; + +class CommunityCategoryDao extends BaseDao +{ + use CategoresDao; + + protected function getModel(): string + { + return CommunityCategory::class; + } +} diff --git a/app/common/dao/community/CommunityDao.php b/app/common/dao/community/CommunityDao.php new file mode 100644 index 00000000..e14f4e03 --- /dev/null +++ b/app/common/dao/community/CommunityDao.php @@ -0,0 +1,127 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\community; + + +use app\common\dao\BaseDao; +use app\common\model\community\Community; +use app\common\model\system\Relevance; +use app\common\repositories\system\RelevanceRepository; + +class CommunityDao extends BaseDao +{ + + protected function getModel(): string + { + return Community::class; + } + + public function search(array $where) + { + $query = Community::hasWhere('author', function($query) use ($where){ + $query->when(isset($where['username']) && $where['username'] !== '', function ($query) use($where) { + $query->whereLike('real_name|phone|nickname',"%{$where['username']}%"); + }); + $query->where(true); + }); + $query + ->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use($where) { + $query->whereLike('Community.title',"%{$where['keyword']}%"); + }) + ->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use($where) { + $query->where('Community.uid',$where['uid']); + }) + ->when(isset($where['uids']) && $where['uids'] !== '', function ($query) use($where) { + $query->whereIn('Community.uid',$where['uids']); + }) + ->when(isset($where['topic_id']) && $where['topic_id'] !== '', function ($query) use($where) { + $query->where('Community.topic_id',$where['topic_id']); + }) + ->when(isset($where['community_id']) && $where['community_id'] !== '', function ($query) use($where) { + $query->where('Community.community_id',$where['community_id']); + }) + ->when(isset($where['not_id']) && $where['not_id'] !== '', function ($query) use($where) { + $query->whereNotIn('Community.community_id',$where['not_id']); + }) + ->when(isset($where['community_ids']) && $where['community_ids'] !== '', function ($query) use($where) { + $query->whereIn('Community.community_id',$where['community_ids']); + }) + ->when(isset($where['is_type']) && $where['is_type'] !== '', function ($query) use($where) { + $query->whereIn('Community.is_type',$where['is_type']); + }) + ->when(isset($where['is_show']) && $where['is_show'] !== '', function ($query) use($where) { + $query->where('Community.is_show',$where['is_show']); + }) + ->when(isset($where['status']) && $where['status'] !== '', function ($query) use($where) { + $query->where('Community.status',$where['status']); + }) + ->when(isset($where['start']) && $where['start'] !== '', function ($query) use($where) { + $query->where('Community.start',$where['start']); + }) + ->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use($where) { + $query->where('Community.is_del',$where['is_del']); + }) + ->when(isset($where['category_id']) && $where['category_id'] !== '', function ($query) use($where) { + $query->where('Community.category_id',$where['category_id']); + }) + ->when(isset($where['spu_id']) && $where['spu_id'] !== '', function ($query) use($where) { + $id = Relevance::where('right_id', $where['spu_id']) + ->where('type',RelevanceRepository::TYPE_COMMUNITY_PRODUCT) + ->column('left_id'); + $query->where('community_id','in', $id); + }); + + $order = 'Community.create_time DESC'; + + if (isset($where['order']) && $where['order'] == 'start') { + $order = 'Community.start DESC,Community.create_time DESC'; + } + + $query->order($order); + return $query; + } + + public function uidExists(int $id, int $uid) + { + return $this->getModel()::getDb()->where('uid',$uid)->where($this->getPk(),$id)->count() > 0; + } + + public function exists(int $id) + { + return $this->getModel()::getDb()->where('is_del',0)->where($this->getPk(),$id)->count() > 0; + } + + public function destoryByUid($uid) + { + return $this->getModel()::getDb()->where('uid' ,$uid)->update(['is_del' => 1]); + } + + public function joinUser($where) + { + return Community::hasWhere('relevanceRight',function($query) use($where){ + $query->where('type',RelevanceRepository::TYPE_COMMUNITY_START)->where('left_id',$where['uid']); + }) + ->when(isset($where['is_type']) && $where['is_type'] !== '', function ($query) use($where) { + $query->whereIn('Community.is_type',$where['is_type']); + }) + ->when(isset($where['is_show']) && $where['is_show'] !== '', function ($query) use($where) { + $query->where('Community.is_show',$where['is_show']); + }) + ->when(isset($where['status']) && $where['status'] !== '', function ($query) use($where) { + $query->where('Community.status',$where['status']); + }) + ->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use($where) { + $query->where('Community.is_del',$where['is_del']); + }); + } +} diff --git a/app/common/dao/community/CommunityReplyDao.php b/app/common/dao/community/CommunityReplyDao.php new file mode 100644 index 00000000..5ed923f5 --- /dev/null +++ b/app/common/dao/community/CommunityReplyDao.php @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\community; + + +use app\common\dao\BaseDao; +use app\common\model\community\CommunityReply; + +class CommunityReplyDao extends BaseDao +{ + + protected function getModel(): string + { + return CommunityReply::class; + } + + public function uidExists(int $id, int $uid) + { + return $this->getModel()::getDb()->where($this->getPk(), $id)->where('uid', $uid)->where('is_del', 0)->find(); + } + + public function search(array $where) + { + $query = CommunityReply::hasWhere('author',function($query) use($where) { + $query->when(isset($where['username']) && $where['username'] !== '', function ($query) use($where) { + $query->whereLike('nickname',"%{$where['username']}%"); + }); + $query->where(true); + }); + + $query->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use($where) { + $query->whereLike('content',"%{$where['keyword']}%"); + }); + $query->when(isset($where['date']) && $where['date'] !== '', function ($query) use($where) { + getModelTime($query, $where['date'], 'CommunityReply.create_time'); + }); + $query->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use($where) { + $query->where('is_del',$where['is_del']); + }); + + $query->when(isset($where['pid']) && $where['pid'] !== '', function ($query) use($where) { + $query->where('pid',$where['pid']); + }); + + $query->when(isset($where['community_id']) && $where['community_id'] !== '', function ($query) use($where) { + $query->where('community_id',$where['community_id']); + }); + return $query->order('CommunityReply.create_time DESC'); + } +} diff --git a/app/common/dao/community/CommunityTopicDao.php b/app/common/dao/community/CommunityTopicDao.php new file mode 100644 index 00000000..4c8c137c --- /dev/null +++ b/app/common/dao/community/CommunityTopicDao.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\community; + + +use app\common\dao\BaseDao; +use app\common\model\community\CommunityTopic; + +class CommunityTopicDao extends BaseDao +{ + + protected function getModel(): string + { + return CommunityTopic::class; + } + + public function countInc(int $id, string $filed, int $inc = 1) + { + return $this->getModel()::getDb()->where($this->getPk(), $id)->inc($filed, $inc)->update(); + } + + public function countDec(int $id, string $filed, int $dec = 1) + { + try{ + return $this->getModel()::getDb()->where($this->getPk(), $id)->dec($filed, $dec)->update(); + }catch (\Exception $exception) { + + } + } +} diff --git a/app/common/dao/delivery/DeliveryOrderDao.php b/app/common/dao/delivery/DeliveryOrderDao.php new file mode 100644 index 00000000..1fd3a02f --- /dev/null +++ b/app/common/dao/delivery/DeliveryOrderDao.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\delivery; + +use app\common\dao\BaseDao; +use app\common\model\delivery\DeliveryOrder; + +class DeliveryOrderDao extends BaseDao +{ + + protected function getModel(): string + { + return DeliveryOrder::class; + } +} diff --git a/app/common/dao/delivery/DeliveryStationDao.php b/app/common/dao/delivery/DeliveryStationDao.php new file mode 100644 index 00000000..8e03cbb2 --- /dev/null +++ b/app/common/dao/delivery/DeliveryStationDao.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\delivery; + +use app\common\dao\BaseDao; +use app\common\model\delivery\DeliveryStation; + +class DeliveryStationDao extends BaseDao +{ + + protected function getModel(): string + { + return DeliveryStation::class; + } +} diff --git a/app/common/dao/store/CityAreaDao.php b/app/common/dao/store/CityAreaDao.php new file mode 100644 index 00000000..7300b9fe --- /dev/null +++ b/app/common/dao/store/CityAreaDao.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\CityArea; + +class CityAreaDao extends BaseDao +{ + + protected function getModel(): string + { + return CityArea::class; + } + + public function search(array $where) + { + return CityArea::getDB()->when(isset($where['pid']) && $where['pid'] !== '', function ($query) use ($where) { + $query->where('parent_id', $where['pid']); + })->when(isset($where['address']) && $where['address'] !== '', function ($query) use ($where) { + $address = explode('/', trim($where['address'], '/')); + $p = array_shift($address); + if (mb_strlen($p) - 1 === mb_strpos($p, '市')) { + $p = mb_substr($p, 0, -1); + } elseif (mb_strlen($p) - 1 === mb_strpos($p, '省')) { + $p = mb_substr($p, 0, -1); + } elseif (mb_strlen($p) - 3 === mb_strpos($p, '自治区')) { + $p = mb_substr($p, 0, -3); + } + $pcity = $this->search([])->where('name', $p)->find(); + $street = array_pop($address); + if ($pcity) { + $path = '/' . $pcity->id . '/'; + $query->whereLike('path', "/{$pcity->id}/%"); + foreach ($address as $item) { + $id = $this->search([])->whereLike('path', $path . '%')->where('name', $item)->value('id'); + if ($id) { + $path .= $id . '/'; + } else { + break; + } + } + } + $query->whereLike('path', $path . '%')->where('name', $street); + }); + } + + public function getCityList(CityArea $city) + { + if (!$city->parent_id) return [$city]; + $lst = $this->search([])->where('id', 'in', explode('/', trim($city->path, '/')))->order('id ASC')->select(); + $lst[] = $city; + return $lst; + } +} diff --git a/app/common/dao/store/ExcelDao.php b/app/common/dao/store/ExcelDao.php new file mode 100644 index 00000000..bcb5ce3e --- /dev/null +++ b/app/common/dao/store/ExcelDao.php @@ -0,0 +1,78 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store; + +use app\common\model\store\Excel; +use app\common\dao\BaseDao; + +class ExcelDao extends BaseDao +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + protected function getModel(): string + { + return Excel::class; + } + + + public function search(array $where) + { + $query = $this->getModel()::getDB() + ->when(isset($where['type']) && $where['type'] !== '',function($query) use($where){ + $query->where('type',$where['type']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query) use($where){ + $query->where('mer_id',$where['mer_id']); + }) + ->when(isset($where['admin_id']) && $where['admin_id'] !== '',function($query) use($where){ + $query->where('admin_id',$where['admin_id']); + }); + $query->order('create_time DESC'); + return $query; + } + + /** + * TODO 获取小于某个时间的文件 + * @param $time + * @return mixed + * @author Qinii + * @day 2020-08-15 + */ + public function getDelByTime($time) + { + return $this->getModel()::getDB()->whereTime('create_time','<',$time)->column('path','excel_id'); + } + + /** + * TODO 类型 + * @return array + * @author Qinii + * @day 9/28/21 + */ + public function getTypeData() + { + $data = (new Excel())->typeData; + foreach ($data as $k => $v) { + $ret[] = [ + 'key' => $k, + 'value' => $v, + ]; + } + return $ret; + } +} diff --git a/app/common/dao/store/GuaranteeDao.php b/app/common/dao/store/GuaranteeDao.php new file mode 100644 index 00000000..abf1b0ae --- /dev/null +++ b/app/common/dao/store/GuaranteeDao.php @@ -0,0 +1,25 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\Guarantee; + +class GuaranteeDao extends BaseDao +{ + + + protected function getModel(): string + { + return Guarantee::class; + } + +} diff --git a/app/common/dao/store/GuaranteeTemplateDao.php b/app/common/dao/store/GuaranteeTemplateDao.php new file mode 100644 index 00000000..3257483a --- /dev/null +++ b/app/common/dao/store/GuaranteeTemplateDao.php @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\GuaranteeTemplate; + +class GuaranteeTemplateDao extends BaseDao +{ + + protected function getModel(): string + { + return GuaranteeTemplate::class; + } + +} diff --git a/app/common/dao/store/GuaranteeValueDao.php b/app/common/dao/store/GuaranteeValueDao.php new file mode 100644 index 00000000..2fd87d52 --- /dev/null +++ b/app/common/dao/store/GuaranteeValueDao.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\GuaranteeValue; + +class GuaranteeValueDao extends BaseDao +{ + + + protected function getModel(): string + { + return GuaranteeValue::class; + } + + public function chageStatus(int $id,int $status) + { + $this->getModel()::getDB()->where('guarantee_id',$id)->update(['status' => $status]); + } + + public function clear($id) + { + $this->getModel()::getDB()->where('guarantee_template_id',$id)->delete(); + } +} diff --git a/app/common/dao/store/PriceRuleDao.php b/app/common/dao/store/PriceRuleDao.php new file mode 100644 index 00000000..17e4cf47 --- /dev/null +++ b/app/common/dao/store/PriceRuleDao.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store; + + +use app\common\dao\BaseDao; +use app\common\model\store\PriceRule; +use app\common\repositories\system\RelevanceRepository; + +class PriceRuleDao extends BaseDao +{ + + protected function getModel(): string + { + return PriceRule::class; + } + + public function search(array $where) + { + return PriceRule::getDB()->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('rule_name', "%{$where['keyword']}%"); + })->when(isset($where['is_show']) && $where['is_show'] !== '', function ($query) use ($where) { + $query->where('is_show', $where['is_show']); + })->when(isset($where['cate_id']) && $where['cate_id'] !== '', function ($query) use ($where) { + $ids = app()->make(RelevanceRepository::class)->query([ + 'type' => RelevanceRepository::PRICE_RULE_CATEGORY + ])->where(function ($query) use ($where) { + if (is_array($where['cate_id'])) { + $query->whereIn('right_id', $where['cate_id']); + } else { + $query->where('right_id', (int)$where['cate_id']); + } + })->group('left_id')->column('left_id'); + $ids[] = -1; + $query->where(function ($query) use ($ids) { + $query->whereIn('rule_id', $ids)->whereOr('is_default', 1); + }); + }); + } +} diff --git a/app/common/dao/store/StoreActivityDao.php b/app/common/dao/store/StoreActivityDao.php new file mode 100644 index 00000000..b2f69f3a --- /dev/null +++ b/app/common/dao/store/StoreActivityDao.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\StoreActivity; +use app\common\repositories\system\RelevanceRepository; + +/** + * + * Class StoreActivityDao + * @package app\common\dao\system\merchant + */ +class StoreActivityDao extends BaseDao +{ + protected function getModel(): string + { + return StoreActivity::class; + } + + public function search(array $where = []) + { + $where['is_del'] = 0; + return $this->getSearch($where); + } +} diff --git a/app/common/dao/store/StoreAttrTemplateDao.php b/app/common/dao/store/StoreAttrTemplateDao.php new file mode 100644 index 00000000..9752b8dd --- /dev/null +++ b/app/common/dao/store/StoreAttrTemplateDao.php @@ -0,0 +1,127 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\StoreAttrTemplate; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class StoreAttrTemplateDao + * @package app\common\dao\store + * @author xaboy + * @day 2020-05-06 + */ +class StoreAttrTemplateDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return StoreAttrTemplate::class; + } + + /** + * @param $merId + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-06 + */ + public function search($merId, array $where = []) + { + return StoreAttrTemplate::getDB()->when(isset($where['keyword']),function($query) use($where){ + $query->whereLike('template_name',"%{$where['keyword']}%"); + })->where('mer_id', $merId)->order('attr_template_id DESC'); + } + + /** + * @param int $merId + * @param int $id + * @param null $except + * @return bool + * @author xaboy + * @day 2020-04-15 + */ + public function merExists(int $merId, int $id, $except = null) + { + return $this->merFieldExists($merId, $this->getPk(), $id, $except); + } + + /** + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + * @author xaboy + * @day 2020-04-15 + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where('mer_id', $merId)->where($field, $value)->count() > 0; + } + + + /** + * @param int $id + * @param int $merId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function get( $id, $merId = 0) + { + return ($this->getModel())::getDB()->where('mer_id', $merId)->find($id); + } + + /** + * @param int $id + * @param int $merId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-15 + */ + public function delete($id, $merId = 0) + { + $query = ($this->getModel())::getDB()->where('mer_id', $merId); + if (is_array($id)) { + $query->where($this->getPk(), 'in',$id); + } else { + $query->where($this->getPk(), $id); + } + return $query->delete(); + } + + public function getList($merId) + { + return ($this->getModel())::getDB()->where('mer_id',$merId)->field('attr_template_id,template_name,template_value')->select(); + } +} diff --git a/app/common/dao/store/StoreBrandCategoryDao.php b/app/common/dao/store/StoreBrandCategoryDao.php new file mode 100644 index 00000000..bc6cabfd --- /dev/null +++ b/app/common/dao/store/StoreBrandCategoryDao.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\StoreBrandCategory as model; +use crmeb\traits\CategoresDao; + +class StoreBrandCategoryDao extends BaseDao +{ + + use CategoresDao; + + protected function getModel(): string + { + return model::class; + } + public function getMaxLevel() + { + return 2; + } + + public function getAll($mer_id = 0,$status = null) + { + return $this->getModel()::getDB()->when(($status !== null),function($query)use($status){ + $query->where($this->getStatus(),$status); + })->order('sort DESC')->select(); + } + + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB() + ->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + }) + ->where($field, $value)->count() > 0; + } + + public function getAllByField( $field, $value, $except = null) + { + return ($this->getModel())::getDB() + ->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + }) + ->where($field, $value); + } + + /** + * @return array + * @author xaboy + * @day 2020/7/22 + */ + public function options() + { + return model::getDB()->where('is_show', 1)->order('sort DESC')->column('pid,cate_name', 'store_brand_category_id'); + } + +} diff --git a/app/common/dao/store/StoreBrandDao.php b/app/common/dao/store/StoreBrandDao.php new file mode 100644 index 00000000..39f43261 --- /dev/null +++ b/app/common/dao/store/StoreBrandDao.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\StoreBrand as model; +use crmeb\traits\CategoresDao; + +class StoreBrandDao extends BaseDao +{ + + use CategoresDao; + + protected function getModel(): string + { + return model::class; + } + + + public function getAll() + { + $query = $this->getModel()::hasWhere('brandCategory',function($query){ + $query->where('is_show',1); + }); + $query->where('StoreBrand.is_show',1); + $list = $query->order('StoreBrand.sort DESC,StoreBrand.create_time DESC')->select()->toArray(); + array_push($list,[ + "brand_id" => 0, + "brand_category_id" => 0, + "brand_name" => "其他", + "sort" => 999, + "pic" => "", + "is_show" => 1, + "create_time" => "", + ]); + return $list; + } + + + public function merFieldExists($field, $value, $except = null) + { + return ($this->getModel())::getDB() + ->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + }) + ->where($field, $value)->count() > 0; + } + + public function search(array $where) + { + $query = $this->getModel()::getDB(); + if(isset($where['brand_category_id']) && $where['brand_category_id']) + $query->where('brand_category_id',$where['brand_category_id']); + if(isset($where['brand_name']) && $where['brand_name']) + $query->where('brand_name','like','%'.$where['brand_name'].'%'); + if((isset($where['ids']) && $where['ids'])) + $query->where($this->getPk(),'in',$where['ids']); + return $query->order('sort DESC,create_time desc'); + + } + +} diff --git a/app/common/dao/store/StoreCategoryDao.php b/app/common/dao/store/StoreCategoryDao.php new file mode 100644 index 00000000..491eb5b1 --- /dev/null +++ b/app/common/dao/store/StoreCategoryDao.php @@ -0,0 +1,99 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\StoreCategory as model; +use crmeb\traits\CategoresDao; + +class StoreCategoryDao extends BaseDao +{ + + use CategoresDao; + + protected function getModel(): string + { + return model::class; + } + + public function findChildrenId($id) + { + return model::getDB()->whereLike('path', '%/'. $id . '/%')->column('store_category_id'); + } + + public function selectChildrenId(array $ids) + { + if (!is_array($ids) || empty($ids)) return []; + $query = model::getDB()->where(function($query) use($ids){ + foreach ($ids as $id) { + $query->whereOr('path', 'like','%/'. $id . '/%'); + } + }); + return $query->column('store_category_id'); + } + + + public function fieldExistsList(?int $merId,$field,$value,$except = null) + { + return ($this->getModel()::getDB())->when($except ,function($query)use($field,$except){ + $query->where($field,'<>',$except); + })->when(($merId !== null) ,function($query)use($merId){ + $query->where('mer_id',$merId); + })->where($field,$value); + + } + + public function getTwoLevel($merId = 0) + { + $pid = model::getDB()->where('pid', 0)->where('is_show',1)->where('mer_id', $merId)->order('sort DESC')->column('store_category_id'); + return model::getDB()->whereIn('pid', $pid)->where('is_show', 1)->where('mer_id', $merId)->limit(20)->order('sort DESC')->column('store_category_id,cate_name,pid'); + } + + public function children($pid, $merId = 0) + { + return model::getDB()->where('pid', $pid)->where('mer_id', $merId)->where('is_show', 1)->order('sort DESC')->column('store_category_id,cate_name,pic'); + } + + public function allChildren($id) + { + $path = model::getDB()->where('store_category_id', is_array($id) ? 'IN' : '=', $id)->where('mer_id', 0)->column('path', 'store_category_id'); + if (!count($path)) return []; + return model::getDB()->where(function ($query) use ($path) { + foreach ($path as $k => $v) { + $query->whereOr('path', 'LIKE', "$v$k/%"); + } + })->where('mer_id', 0)->order('sort DESC')->column('store_category_id'); + } + + public function idsByAllChildren(array $ids) + { + $paths = model::getDB()->whereIn('store_category_id', $ids)->where('mer_id', 0)->column('path'); + if (!count($paths)) return []; + return model::getDB()->where(function ($query) use ($paths) { + foreach ($paths as $path) { + $query->whereOr('path', 'LIKE', "$path%"); + } + })->where('mer_id', 0)->order('sort DESC')->column('store_category_id'); + } + + public function getMaxLevel($merId = null) + { + if($merId) return 2; + return 3; + } + + public function searchLevelAttr($query, $value) + { + $query->where('level', $value); + } +} diff --git a/app/common/dao/store/StorePrinterDao.php b/app/common/dao/store/StorePrinterDao.php new file mode 100644 index 00000000..f128e284 --- /dev/null +++ b/app/common/dao/store/StorePrinterDao.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store; + +use app\common\dao\BaseDao; +use app\common\model\store\StorePrinter; + +class StorePrinterDao extends BaseDao +{ + + protected function getModel(): string + { + return StorePrinter::class; + } + +} diff --git a/app/common/dao/store/StoreSeckillActiveDao.php b/app/common/dao/store/StoreSeckillActiveDao.php new file mode 100644 index 00000000..6917343b --- /dev/null +++ b/app/common/dao/store/StoreSeckillActiveDao.php @@ -0,0 +1,143 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store; + +use app\common\model\store\StoreSeckillActive; +use app\common\dao\BaseDao; +use app\common\repositories\store\product\SpuRepository; + +class StoreSeckillActiveDao extends BaseDao +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + protected function getModel(): string + { + return StoreSeckillActive::class; + } + + + /** + * TODO 搜索 + * @param array $where + * @return mixed + * @author Qinii + * @day 2020-08-05 + */ + public function search(array $where) + { + $query = $this->getModel()::getDB() + ->when(isset($where['status']) && $where['status'] !== '',function($query) use($where){ + $query->where('status',$where['status']); + }) + ->when(isset($where['start_day']) && $where['start_day'] !== '',function($query) use($where){ + $query->whereTime('start_day','<=',$where['start_day']); + }) + ->when(isset($where['end_day']) && $where['end_day'] !== '',function($query) use($where){ + $query->whereTime('end_day','>',$where['end_day']); + }) + ->when(isset($where['start_time']) && $where['start_time'] !== '',function($query) use($where){ + $query->whereTime('start_time','<=',$where['start_time']); + }) + ->when(isset($where['end_time']) && $where['end_time'] !== '',function($query) use($where){ + $query ->whereTime('end_time','>',$where['end_time']); + }) + ->when(isset($where['product_id']) && $where['product_id'] !== '',function($query) use($where){ + $query->where('product_id',$where['product_id']); + }) + ->when(isset($where['day']) && $where['day'] !== '',function($query) use($where){ + $query->whereTime('start_day','<=',$where['day'])->whereTime('end_day','>',$where['day']); + }) + ->when(isset($where['time']) && $where['time'] !== '',function($query) use($where){ + $query->whereTime('start_time','<=',$where['time'])->whereTime('end_time','>',$where['time']); + }); + + $query->order('start_time DESC'); + return $query; + } + + + /** + * TODO + * @param int $productId + * @param array $data + * @return mixed + * @author Qinii + * @day 2020-08-11 + */ + public function updateByProduct(int $productId,array $data) + { + return $this->getModel()::getDB()->where('product_id',$productId)->update($data); + } + + /** + * TODO + * @author Qinii + * @day 2020-08-11 + */ + public function valActiveStatus() + { + $day = date('Y-m-d',time()); + $_h = date('H',time()); + $id = $this->getModel()::getDB()->where('status',1) + ->whereTime('end_day','<=',$day) + ->whereTime('end_time','<',$_h) + ->column('seckill_active_id'); + if($id) { + $this->getModel()::getDB()->where('seckill_active_id', 'in', $id)->update(['status' => -1]); + $where = [ + 'product_type' => 1, + 'activity_ids' => $id + ]; + app()->make(SpuRepository::class)->getSearch($where)->update(['status' => 0]); + } + } + + /** + * TODO 不同状态商品 + * @param $status + * @return mixed + * @author Qinii + * @day 2020-08-19 + */ + public function getStatus($status) + { + $day = date('Y-m-d',time()); + $_h = date('H',time()); + $query = $this->getModel()::getDB(); + if($status == 1) //未开始 + $query->where('status','<>',-1)->where(function($query)use ($day,$_h){ + $query->whereTime('start_day','>',$day)->whereOr(function($query)use($day,$_h){ + $query->whereTime('start_day','<=',$day)->where('start_time','>',$_h); + }); + }); + + if($status == 2)//进行中 + $query->where('status',1) + ->whereTime('start_day','<=',$day)->whereTime('end_day','>',$day) + ->where('start_time','<=',$_h)->where('end_time','>',$_h); + + if($status == 3) //结束 + $query->where('status',-1)->whereOr(function($query)use($day,$_h){ + $query->whereTime('end_day','<',$day) + ->whereOr(function($query)use($day,$_h){ + $query->whereTime('start_day','<=',$day)->whereTime('end_day','>=',$day)->where('end_time','<=',$_h); + }); + }); + return $query; + } +} diff --git a/app/common/dao/store/StoreSeckillTimeDao.php b/app/common/dao/store/StoreSeckillTimeDao.php new file mode 100644 index 00000000..e5f74450 --- /dev/null +++ b/app/common/dao/store/StoreSeckillTimeDao.php @@ -0,0 +1,112 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store; + +use app\common\model\store\StoreSeckillTime; +use app\common\dao\BaseDao; + +class StoreSeckillTimeDao extends BaseDao +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + protected function getModel(): string + { + return StoreSeckillTime::class; + } + + public function getTime($status) + { + foreach (StoreSeckillTime::ISTIME as $k => $item){ + if($status && $k !== 24){ + $time [] = ['value' => $k, 'label' => $item]; + } + if(!$status && $k !== 0){ + $time [] = ['value' => $k, 'label' => $item]; + } + } + return $time; + } + + + public function search(array $where) + { + $query = $this->getModel()::getDB() + ->when(isset($where['status']) && $where['status'] !== '',function($query) use($where){ + $query->where('status',$where['status']); + }) + ->when(isset($where['title']) && $where['title'] !== '',function($query) use($where){ + $query->where('title','like','%'.$where['title'].'%'); + }) + ->when(isset($where['start_time']) && $where['start_time'] !== '',function($query) use($where){ + $query->whereTime('start_time','<=',intval($where['start_time'])); + }) + ->when(isset($where['end_time']) && $where['end_time'] !== '',function($query) use($where){ + $query->whereTime('end_time','>=',intval($where['end_time'])); + }); + $query->order('start_time ASC'); + return $query; + } + + /** + * TODO 开始时间 在别的时间段中 + * @param $time + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function valStartTime($time,$id) + { + return $this->getModel()::getDB() + ->when($id,function ($query)use($id){ + $query->where($this->getPk(),'<>',$id); + })->where('start_time','<=',$time)->where('end_time','>',$time)->count(); + } + + /** + * TODO 结束时间在别的时间段中 + * @param $time + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function valEndTime($time,$id) + { + return $this->getModel()::getDB() + ->when($id,function ($query)use($id){ + $query->where($this->getPk(),'<>',$id); + })->where('start_time','<',$time)->where('end_time','>=',$time)->count(); + } + + /** + * TODO 时间段包含了别的时间段 + * @param array $data + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function valAllTime(array $data,$id) + { + return $this->getModel()::getDB() + ->when($id,function ($query)use($id){ + $query->where($this->getPk(),'<>',$id); + })->where('start_time','>',$data['start_time'])->where('end_time','<=',$data['end_time'])->count(); + } + +} diff --git a/app/common/dao/store/broadcast/BroadcastAssistantDao.php b/app/common/dao/store/broadcast/BroadcastAssistantDao.php new file mode 100644 index 00000000..94290dfe --- /dev/null +++ b/app/common/dao/store/broadcast/BroadcastAssistantDao.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\broadcast; + +use app\common\dao\BaseDao; +use app\common\model\store\broadcast\BroadcastAssistant; +use think\exception\ValidateException; + +class BroadcastAssistantDao extends BaseDao +{ + + protected function getModel(): string + { + return BroadcastAssistant::class; + } + + public function merExists(int $id, int $merId) + { + return $this->existsWhere([$this->getPk() => $id, 'is_del' => 0, 'mer_id' => $merId]); + } + + public function intersection(?string $ids, int $merId) + { + if (!$ids) return [0]; + return $this->getModel()::getDb()->whereIn('assistant_id',$ids)->where('mer_id', $merId)->column('assistant_id'); + } + + public function existsAll($ids, $merId) + { + foreach ($ids as $id) { + $has = $this->getModel()::getDb()->where('assistant_id',$id)->where('mer_id',$merId)->count(); + if (!$has) throw new ValidateException('ID:'.$id.' 不存在'); + } + + return true; + } +} diff --git a/app/common/dao/store/broadcast/BroadcastGoodsDao.php b/app/common/dao/store/broadcast/BroadcastGoodsDao.php new file mode 100644 index 00000000..1f1b41c5 --- /dev/null +++ b/app/common/dao/store/broadcast/BroadcastGoodsDao.php @@ -0,0 +1,133 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\broadcast; + + +use app\common\dao\BaseDao; +use app\common\model\store\broadcast\BroadcastGoods; +use app\common\repositories\system\merchant\MerchantRepository; +use think\db\BaseQuery; +use think\db\exception\DbException; + +/** + * Class BroadcastGoodsDao + * @package app\common\dao\store\broadcast + * @author xaboy + * @day 2020/7/29 + */ +class BroadcastGoodsDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/7/29 + */ + protected function getModel(): string + { + return BroadcastGoods::class; + } + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020/7/30 + */ + public function delete(int $id) + { + return $this->update($id, ['is_del' => 1]); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020/7/30 + */ + public function exists(int $id) + { + return $this->existsWhere(['broadcast_goods_id' => $id, 'is_del' => 0]); + } + + /** + * @param int $id + * @param int $merId + * @return bool + * @author xaboy + * @day 2020/7/30 + */ + public function merExists(int $id, int $merId) + { + return $this->existsWhere(['broadcast_goods_id' => $id, 'is_del' => 0, 'is_mer_del' => 0, 'mer_id' => $merId]); + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/7/30 + */ + public function search(array $where) + { + if (isset($where['is_trader']) && $where['is_trader'] !== '') { + $query = BroadcastGoods::hasWhere('merchant', function ($query) use ($where) { + $query->where('is_trader', $where['is_trader']); + }); + } else { + $query = BroadcastGoods::getDB()->alias('BroadcastGoods'); + } + $query->when(isset($where['mer_id']), function ($query) use ($where) { + $query->where('BroadcastGoods.mer_id', $where['mer_id']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('goods_id|mark|name|broadcast_goods_id', "%{$where['keyword']}%"); + })->when(isset($where['valid']) && $where['valid'] !== '', function ($query) use ($where) { + $query->where('BroadcastGoods.is_show', 1); + })->when(isset($where['mer_valid']) && $where['mer_valid'] !== '', function ($query) use ($where) { + $query->where('BroadcastGoods.is_show', 1)->where('BroadcastGoods.is_mer_show', 1); + })->when(isset($where['broadcast_goods_id']) && $where['broadcast_goods_id'] !== '', function ($query) use ($where) { + $query->where('BroadcastGoods.broadcast_goods_id', $where['broadcast_goods_id']); + })->when(isset($where['status_tag']) && $where['status_tag'] !== '', function ($query) use ($where) { + if ($where['status_tag'] == 1) { + $query->where('BroadcastGoods.status', 2); + } else if ($where['status_tag'] == -1) { + $query->where('BroadcastGoods.status', -1); + } else if ($where['status_tag'] == 0) { + $query->whereIn('BroadcastGoods.status', [0, 1]); + } + })->where('BroadcastGoods.is_del', 0)->where('BroadcastGoods.is_mer_del', 0); + return $query; + } + + public function goodsStatusAll() + { + return BroadcastGoods::getDB()->where('goods_id', '>', 0)->whereIn('audit_status', [0, 1])->column('audit_status', 'goods_id'); + } + + public function updateGoods($goods_id, $data) + { + return BroadcastGoods::getDB()->where('goods_id', $goods_id)->update($data); + } + + public function goodsList($merId, array $ids) + { + return BroadcastGoods::getDB()->whereIn('broadcast_goods_id', $ids)->where('mer_id', $merId)->where('is_show', 1)->where('is_mer_show', 1)->where('is_del', 0)->where('status', 2)->select(); + } + + public function merDelete(int $id) + { + return $this->update($id, ['is_mer_del' => 1]); + } +} diff --git a/app/common/dao/store/broadcast/BroadcastRoomDao.php b/app/common/dao/store/broadcast/BroadcastRoomDao.php new file mode 100644 index 00000000..430243c5 --- /dev/null +++ b/app/common/dao/store/broadcast/BroadcastRoomDao.php @@ -0,0 +1,156 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\broadcast; + + +use app\common\dao\BaseDao; +use app\common\model\store\broadcast\BroadcastRoom; +use app\common\repositories\system\merchant\MerchantRepository; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class BroadcastRoomDao + * @package app\common\dao\store\broadcast + * @author xaboy + * @day 2020/7/29 + */ +class BroadcastRoomDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/7/29 + */ + protected function getModel(): string + { + return BroadcastRoom::class; + } + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020/7/30 + */ + public function delete(int $id) + { + return $this->update($id, ['is_del' => 1]); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020/7/30 + */ + public function exists(int $id) + { + return $this->existsWhere(['broadcast_room_id' => $id, 'is_del' => 0]); + } + + /** + * @param int $id + * @param int $merId + * @return bool + * @author xaboy + * @day 2020/7/30 + */ + public function merExists(int $id, int $merId) + { + return $this->existsWhere(['broadcast_room_id' => $id, 'is_del' => 0, 'is_mer_del' => 0, 'mer_id' => $merId]); + } + + public function merDelete(int $id) + { + return $this->update($id, ['is_mer_del' => 1]); + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/7/30 + */ + public function search(array $where) + { + if(isset($where['is_trader']) && $where['is_trader'] !== ''){ + $query = BroadcastRoom::hasWhere('merchant',function($query)use($where){ + $query->where('is_trader',$where['is_trader']); + }); + }else{ + $query = BroadcastRoom::getDB()->alias('BroadcastRoom'); + } + $query->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('room_id|name|anchor_name|anchor_wechat|broadcast_room_id', "%{$where['keyword']}%"); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('BroadcastRoom.mer_id', $where['mer_id']); + })->when(isset($where['live_status']) && $where['live_status'] !== '', function ($query) use ($where) { + $query->where('BroadcastRoom.live_status', $where['live_status']); + })->when(isset($where['star']) && $where['star'] !== '', function ($query) use ($where) { + $query->where('BroadcastRoom.star', $where['star']); + })->when(isset($where['show_tag']) && $where['show_tag'] !== '', function ($query) use ($where) { + $query->where('is_show', 1)->where('is_mer_show', 1)->where('status', 2); + })->when(isset($where['hot']) && $where['hot'] !== '', function ($query) use ($where) { + $query->order('live_status ASC,star DESC,sort DESC'); + })->when(isset($where['broadcast_room_id']) && $where['broadcast_room_id'] !== '', function ($query) use ($where) { + $query->where('BroadcastRoom.broadcast_room_id', $where['broadcast_room_id']); + })->when(isset($where['status_tag']) && $where['status_tag'] !== '', function ($query) use ($where) { + if ($where['status_tag'] == 1) { + $query->where('BroadcastRoom.status', 2); + } else if ($where['status_tag'] == -1) { + $query->where('BroadcastRoom.status', -1); + } else if ($where['status_tag'] == 0) { + $query->whereIn('BroadcastRoom.status', [0, 1]); + } + })->when(isset($where['show_type']) && $where['show_type'] !== '', function ($query) use ($where) { + if ($where['show_type'] == 3) { + $query->where('BroadcastRoom.is_mer_show', 1)->where('BroadcastRoom.is_show', 1); + } else if ($where['show_type'] == 2) { + $query->where('BroadcastRoom.is_mer_show', 0)->where('BroadcastRoom.is_show', 1); + } else if ($where['show_type'] == 1) { + $query->where('BroadcastRoom.is_mer_show', 1)->where('BroadcastRoom.is_show', 0); + } else if ($where['show_type'] == 0) { + $query->where('BroadcastRoom.is_mer_show', 0)->where('BroadcastRoom.is_show', 0); + } + })->where('BroadcastRoom.is_del', 0)->where('BroadcastRoom.is_mer_del', 0); + + return $query; + } + + /** + * @param $roomId + * @param $merId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/7/31 + */ + public function validRoom($roomId, $merId) + { + return BroadcastRoom::getDB()->where('broadcast_room_id', $roomId)->where('mer_id', $merId)->where('status', 2)->where('is_show', 1)->find(); + } + + public function getRooms(array $roomIds) + { + return BroadcastRoom::getDB()->whereIn('room_id', $roomIds)->column('live_status,broadcast_room_id', 'room_id'); + } +} diff --git a/app/common/dao/store/broadcast/BroadcastRoomGoodsDao.php b/app/common/dao/store/broadcast/BroadcastRoomGoodsDao.php new file mode 100644 index 00000000..d2eb7108 --- /dev/null +++ b/app/common/dao/store/broadcast/BroadcastRoomGoodsDao.php @@ -0,0 +1,69 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\broadcast; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\broadcast\BroadcastRoomGoods; +use app\common\repositories\store\order\StoreCartRepository; + +class BroadcastRoomGoodsDao extends BaseDao +{ + + protected function getModel(): string + { + return BroadcastRoomGoods::class; + } + + public function clear($id) + { + return BroadcastRoomGoods::getDB()->where('broadcast_room_id', $id)->delete(); + } + + public function goodsId($id) + { + return BroadcastRoomGoods::getDB()->where('broadcast_room_id', $id)->column('broadcast_goods_id'); + } + + public function rmGoods($goodsId, $roomId) + { + return BroadcastRoomGoods::getDB()->where('broadcast_room_id', $roomId)->where('broadcast_goods_id', $goodsId)->delete(); + } + + public function getGoodsList($roomId, $page, $limit) + { + $query = BroadcastRoomGoods::getDB()->where('broadcast_room_id', $roomId); + $count = $query->count(); + $list = $query->page($page, $limit)->with('goods.product')->select()->toArray(); + $ids = array_column($list, 'broadcast_goods_id'); + if (count($ids)) { + $sourcePayInfo = app()->make(StoreCartRepository::class)->getSourcePayInfo(1, $ids); + $data = []; + foreach ($sourcePayInfo as $item) { + $data[$item['source_id']] = $item; + } + foreach ($list as $k => $goods) { + $list[$k]['goods']['pay_num'] = $data[$goods['broadcast_goods_id']]['pay_num'] ?? 0; + $list[$k]['goods']['pay_price'] = $data[$goods['broadcast_goods_id']]['pay_price'] ?? 0; + } + } + return compact('list', 'count'); + } + + public function deleteGoods($goodsId) + { + return BroadcastRoomGoods::getDB()->where('broadcast_goods_id', $goodsId)->delete(); + } +} diff --git a/app/common/dao/store/coupon/StoreCouponDao.php b/app/common/dao/store/coupon/StoreCouponDao.php new file mode 100644 index 00000000..c8226263 --- /dev/null +++ b/app/common/dao/store/coupon/StoreCouponDao.php @@ -0,0 +1,342 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\coupon; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCoupon; +use app\common\model\store\coupon\StoreCouponUser; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use think\Collection; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class StoreCouponIssueDao + * @package app\common\dao\store\coupon + * @author xaboy + * @day 2020-05-14 + */ +class StoreCouponDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return StoreCoupon::class; + } + + /** + * @param int $merId + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-14 + */ + public function search(?int $merId, array $where) + { + if(isset($where['is_trader']) && $where['is_trader'] !== ''){ + $query = StoreCoupon::hasWhere('merchant',function($query)use($where){ + $query->where('is_trader',$where['is_trader']); + }); + }else{ + $query = StoreCoupon::getDB()->alias('StoreCoupon'); + } + $query->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('StoreCoupon.status', (int)$where['status']); + })->when(isset($where['coupon_name']) && $where['coupon_name'] !== '', function ($query) use ($where) { + $query->whereLike('title', "%{$where['coupon_name']}%"); + })->when(isset($where['coupon_id']) && $where['coupon_id'] !== '', function ($query) use ($where) { + $query->where('coupon_id', (int)$where['coupon_id']); + })->when(isset($where['send_type']) && $where['send_type'] !== '', function ($query) use ($where) { + $query->where('send_type', (int)$where['send_type']); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('type', (int)$where['type']); + })->when($merId !== null, function ($query) use ($merId) { + $query->where('StoreCoupon.mer_id', $merId); + })->when(isset($where['is_mer']) && $where['is_mer'] !== '', function ($query) use ($merId) { + $query->where('type', '<', 10); + }); + return $query->where('StoreCoupon.is_del', 0)->order(($merId ? 'StoreCoupon.sort DESC,' : '') . 'coupon_id DESC'); + } + + /** + * @param int|null $type + * @param int $send_type + * @return BaseQuery + * @author xaboy + * @day 2020/6/18 + */ + public function validCouponQuery($type = null, $send_type = 0) + { + $query = StoreCoupon::getDB() + ->where('status', 1) + ->where('send_type', $send_type) + ->where('is_del', 0) + ->order('sort DESC,coupon_id DESC') + ->when(!is_null($type), function ($query) use ($type) { + $query->where('type', $type); + }); + $query->where(function (BaseQuery $query) { + $query->where('is_limited', 0)->whereOr(function (BaseQuery $query) { + $query->where('is_limited', 1)->where('remain_count', '>', 0); + }); + }) + ->where(function (BaseQuery $query) { + $query->where('is_timeout', 0)->whereOr(function (BaseQuery $query) { + $time = date('Y-m-d H:i:s'); + $query->where('is_timeout', 1)->where('start_time', '<', $time)->where('end_time', '>', $time); + }); + }) + ->where(function (BaseQuery $query) { + $query->where('coupon_type', 0)->whereOr(function (BaseQuery $query) { + $query->where('coupon_type', 1)->where('use_end_time', '>', date('Y-m-d H:i:s')); + }); + }); + return $query; + } + + public function validCouponQueryWithMerchant($where,$uid = null) + { + $query = StoreCoupon::alias('C')->leftJoin('Merchant M','C.mer_id = M.mer_id') + ->where('C.status', 1) + ->where('C.is_del', 0) + ->when(isset($where['type']) && !is_null($where['type']), function ($query) use ($where) { + if ($where['type'] == '') { + $query->where('C.type', 'in', [0,10,11,12]); + } else { + $query->where('C.type', $where['type']); + } + }) + ->when(isset($where['send_type']) && $where['send_type'] !== '', function($query) use($where){ + $query->where('C.send_type', $where['send_type']); + }) + ->when(isset($where['not_svip']) && $where['not_svip'] !== '', function($query) use($where){ + $query->where('C.send_type', '<>',StoreCouponRepository::GET_COUPON_TYPE_SVIP); + }) + ->when($uid, function($query) use($uid){ + $couponId = StoreCouponUser::where('uid',$uid)->whereIn('status',[1,2])->column('coupon_id'); + $query->whereNotIn('C.coupon_id', $couponId); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function($query) use($where){ + $query->where('C.mer_id', $where['mer_id']); + }) + ->where(function (BaseQuery $query) { + $query->where('is_limited', 0)->whereOr(function (BaseQuery $query) { + $query->where('is_limited', 1)->where('remain_count', '>', 0); + }); + }) + ->where(function (BaseQuery $query) { + $query->where('is_timeout', 0)->whereOr(function (BaseQuery $query) { + $time = date('Y-m-d H:i:s'); + $query->where('is_timeout', 1)->where('start_time', '<', $time)->where('end_time', '>', $time); + }); + }) + ->where(function (BaseQuery $query) { + $query->where('C.mer_id', 0)->whereOr(function (BaseQuery $query) { + $query->where('M.is_del',0)->where('M.status',1)->where('M.mer_state',1); + }); + }) + ->where(function (BaseQuery $query) { + $query->where('coupon_type', 0)->whereOr(function (BaseQuery $query) { + $query->where('coupon_type', 1)->where('use_end_time', '>', date('Y-m-d H:i:s')); + }); + }); + return $query->order('C.sort DESC,C.create_time DESC'); + } + + + /** + * @param $id + * @param $uid + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/19 + */ + public function validCoupon($id, $uid) + { + return $this->validCouponQuery()->when($uid, function (BaseQuery $query, $uid) { + $query->with(['issue' => function (BaseQuery $query) use ($uid) { + $query->where('uid', $uid); + }]); + })->where('coupon_id', $id)->find(); + } + + public function validSvipCoupon($id, $uid) + { + return $this->validCouponQuery(null,StoreCouponRepository::GET_COUPON_TYPE_SVIP)->when($uid, function (BaseQuery $query, $uid) { + $query->with(['svipIssue' => function (BaseQuery $query) use ($uid) { + $query->where('uid', $uid); + }]); + })->where('coupon_id', $id)->find(); + } + + /** + * @param $merId + * @param null $uid + * @return Collection + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function validMerCoupon($merId, $uid = null, $type = 0) + { + return $this->validCouponQuery($type)->when($uid, function (BaseQuery $query, $uid) { + $query->with(['issue' => function (BaseQuery $query) use ($uid) { + $query->where('uid', $uid); + }]); + })->where('mer_id', $merId)->select(); + } + + /** + * @param $merId + * @param null $uid + * @return int + * @author xaboy + * @day 2020/6/19 + */ + public function validMerCouponExists($merId, $uid = null) + { + return $this->validCouponQuery(0)->when($uid, function (BaseQuery $query, $uid) { + $query->with(['issue' => function (BaseQuery $query) use ($uid) { + $query->where('uid', $uid); + }]); + })->where('mer_id', $merId)->count(); + } + + /** + * @param array $couponIds + * @param null $uid + * @return Collection + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function validProductCoupon(array $couponIds, $uid = null) + { + return $this->validCouponQuery(1)->when($uid, function (BaseQuery $query, $uid) { + $query->with(['issue' => function (BaseQuery $query) use ($uid) { + $query->where('uid', $uid); + }]); + })->whereIn('coupon_id', $couponIds)->select(); + } + + /** + * @param array $couponIds + * @param null $uid + * @return int + * @author Qinii + */ + public function validProductCouponExists(array $couponIds, $uid = null) + { + return $this->validCouponQuery(1)->when($uid, function (BaseQuery $query, $uid) { + $query->with(['issue' => function (BaseQuery $query) use ($uid) { + $query->where('uid', $uid); + }]); + })->whereIn('coupon_id', $couponIds)->count(); + } + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-13 + */ + public function delete(int $id) + { + return StoreCoupon::getDB()->where($this->getPk(), $id)->update(['is_del' => 1]); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020-05-13 + */ + public function exists(int $id) + { + return StoreCoupon::getDB()->where($this->getPk(), $id)->where('is_del', 0)->count($this->getPk()) > 0; + } + + /** + * @param int $merId + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-13 + */ + public function merDelete(int $merId, int $id) + { + return StoreCoupon::getDB()->where($this->getPk(), $id)->where('mer_id', $merId)->update(['is_del' => 1]); + } + + /** + * @param int $merId + * @param int $id + * @return bool + * @author xaboy + * @day 2020-05-13 + */ + public function merExists(int $merId, int $id) + { + return StoreCoupon::getDB()->where($this->getPk(), $id)->where('mer_id', $merId)->where('is_del', 0)->count($this->getPk()) > 0; + } + + /** + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/18 + */ + public function newPeopleCoupon() + { + return $this->validCouponQuery(null, 2)->select(); + } + + /** + * @param array|null $ids + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/19 + */ + public function getGiveCoupon(array $ids = null) + { + return $this->validCouponQuery(null, 3)->when($ids, function ($query, $ids) { + $query->whereIn('coupon_id', $ids); + })->select(); + } +} diff --git a/app/common/dao/store/coupon/StoreCouponIssueUserDao.php b/app/common/dao/store/coupon/StoreCouponIssueUserDao.php new file mode 100644 index 00000000..d4553e0a --- /dev/null +++ b/app/common/dao/store/coupon/StoreCouponIssueUserDao.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\coupon; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponIssueUser; +use think\db\BaseQuery; + +/** + * Class StoreCouponIssueUserDao + * @package app\common\dao\store\coupon + * @author xaboy + * @day 2020/6/2 + */ +class StoreCouponIssueUserDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/6/2 + */ + protected function getModel(): string + { + return StoreCouponIssueUser::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/6/2 + */ + public function search(array $where) + { + return StoreCouponIssueUser::getDB()->when(isset($where['coupon_id']) && $where['coupon_id'] != '', function ($query) use ($where) { + $query->where('coupon_id', $where['coupon_id']); + })->when(isset($where['uid']) && $where['uid'] != '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->order('create_time'); + } +} diff --git a/app/common/dao/store/coupon/StoreCouponProductDao.php b/app/common/dao/store/coupon/StoreCouponProductDao.php new file mode 100644 index 00000000..e3aa7029 --- /dev/null +++ b/app/common/dao/store/coupon/StoreCouponProductDao.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\coupon; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponProduct; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class StoreCouponProductDao + * @package app\common\dao\store\coupon + * @author xaboy + * @day 2020-05-13 + */ +class StoreCouponProductDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return StoreCouponProduct::class; + } + + /** + * @param array $data + * @return int + * @author xaboy + * @day 2020-05-13 + */ + public function insertAll(array $data) + { + return StoreCouponProduct::getDB()->insertAll($data); + } + + /** + * @param $couponId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-13 + */ + public function clear($couponId) + { + return StoreCouponProduct::getDB()->where('coupon_id', $couponId)->delete(); + } + + /** + * @param $productId + * @return array + * @author xaboy + * @day 2020/6/1 + */ + public function productByCouponId($productId) + { + return StoreCouponProduct::getDB()->whereIn('product_id', $productId)->column('coupon_id'); + } + + public function search(array $where) + { + return StoreCouponProduct::getDB() + ->when(isset($where['coupon_id']) && $where['coupon_id'] !== '', function ($query) use ($where) { + return $query->where('coupon_id', $where['coupon_id']); + }) + ->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + return $query->where('type', $where['type']); + }); + } +} diff --git a/app/common/dao/store/coupon/StoreCouponSendDao.php b/app/common/dao/store/coupon/StoreCouponSendDao.php new file mode 100644 index 00000000..f1c19dc0 --- /dev/null +++ b/app/common/dao/store/coupon/StoreCouponSendDao.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\coupon; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponSend; + +class StoreCouponSendDao extends BaseDao +{ + + protected function getModel(): string + { + return StoreCouponSend::class; + } + + public function search(array $where) + { + return StoreCouponSend::getDB()->alias('A')->leftJoin('StoreCoupon B', 'B.coupon_id = A.coupon_id') + ->when(isset($where['coupon_name']) && $where['coupon_name'] !== '', function ($query) use ($where) { + $query->whereLike('B.title', "%{$where['coupon_name']}%"); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'A.create_time'); + }) + ->when(isset($where['coupon_type']) && $where['coupon_type'] !== '', function ($query) use ($where) { + $query->where('B.type', $where['coupon_type']); + }) + ->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('A.status', $where['status']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('A.mer_id', $where['mer_id']); + }); + } +} diff --git a/app/common/dao/store/coupon/StoreCouponUserDao.php b/app/common/dao/store/coupon/StoreCouponUserDao.php new file mode 100644 index 00000000..0edb4e9a --- /dev/null +++ b/app/common/dao/store/coupon/StoreCouponUserDao.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\coupon; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponUser; + +/** + * Class StoreCouponUserDao + * @package app\common\dao\store\coupon + * @author xaboy + * @day 2020-05-14 + */ +class StoreCouponUserDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return StoreCouponUser::class; + } + + public function search(array $where) + { + return StoreCouponUser::when(isset($where['username']) && $where['username'] !== '', function ($query) use ($where) { + $query->hasWhere('user', [['nickname', 'LIKE', "%{$where['username']}%"]]); + })->when(isset($where['coupon_type']) && $where['coupon_type'] !== '', function ($query) use ($where) { + $query->hasWhere('coupon', ['type' => $where['coupon_type']]); + })->alias('StoreCouponUser')->when(isset($where['coupon']) && $where['coupon'] !== '', function ($query) use ($where) { + $query->whereLike('StoreCouponUser.coupon_title', "%{$where['coupon']}%"); + })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('StoreCouponUser.status', $where['status']); + })->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('StoreCouponUser.uid', $where['uid']); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('StoreCouponUser.mer_id', $where['mer_id']); + })->when(isset($where['coupon_id']) && $where['coupon_id'] !== '', function ($query) use ($where) { + $query->where('StoreCouponUser.coupon_id', $where['coupon_id']); + })->when(isset($where['coupon']) && $where['coupon'] !== '', function ($query) use ($where) { + $query->whereLike('StoreCouponUser.coupon_title|StoreCouponUser.coupon_id', "%{$where['coupon']}%"); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('StoreCouponUser.type', $where['type']); + })->when(isset($where['send_id']) && $where['send_id'] !== '', function ($query) use ($where) { + $query->where('StoreCouponUser.send_id', $where['send_id'])->where('StoreCouponUser.type', 'send'); + })->when(isset($where['statusTag']) && $where['statusTag'] !== '', function ($query) use ($where) { + if ($where['statusTag'] == 1) { + $query->where('StoreCouponUser.status', 0); + } else { + $query->whereIn('StoreCouponUser.status', [1, 2])->where('StoreCouponUser.create_time', '>', date('Y-m-d H:i:s', strtotime('-60 day'))); + } + })->order('StoreCouponUser.coupon_user_id DESC'); + } + + public function validIntersection($merId, $uid, array $ids): array + { + $time = date('Y-m-d H:i:s'); + return StoreCouponUser::getDB()->whereIn('coupon_user_id', $ids)->where('start_time', '<', $time)->where('end_time', '>', $time) + ->where('is_fail', 0)->where('status', 0)->where('mer_id', $merId)->where('uid', $uid)->column('coupon_user_id'); + } + + public function validQuery($type) + { + $time = date('Y-m-d H:i:s'); + return StoreCouponUser::getDB() + ->when($type, function ($query) use($time){ + $query->where('start_time', '<', $time); + }) + ->where('end_time', '>', $time)->where('is_fail', 0)->where('status', 0); + } + + public function failCoupon() + { + $time = date('Y-m-d H:i:s'); + return StoreCouponUser::getDB()->where('end_time', '<', $time)->where('is_fail', 0)->where('status', 0)->update(['status' => 2]); + } + + public function userTotal($uid, $type = 1) + { + return $this->validQuery($type)->where('uid', $uid)->count(); + } + + public function usedNum($couponId) + { + return StoreCouponUser::getDB()->where('coupon_id', $couponId)->where('status', 1)->count(); + } + + public function sendNum($couponId, $sendId = null, $status = null) + { + return StoreCouponUser::getDB()->where('coupon_id', $couponId)->when($sendId, function ($query, $sendId) { + $query->where('type', 'send')->where('send_id', $sendId); + })->when(isset($status), function ($query) use ($status) { + $query->where('status', $status); + })->count(); + } + + public function validUserPlatformCoupon($uid) + { + $time = date('Y-m-d H:i:s'); + return StoreCouponUser::getDB()->where('uid', $uid)->where('mer_id', 0)->where('start_time', '<', $time)->where('end_time', '>', $time) + ->where('is_fail', 0)->where('status', 0) + ->with(['product' => function ($query) { + $query->field('coupon_id,product_id'); + }, 'coupon' => function ($query) { + $query->field('coupon_id,type,send_type'); + }])->order('coupon_price DESC, coupon_user_id ASC')->select(); + } +} diff --git a/app/common/dao/store/order/MerchantReconciliationDao.php b/app/common/dao/store/order/MerchantReconciliationDao.php new file mode 100644 index 00000000..ac63e8e1 --- /dev/null +++ b/app/common/dao/store/order/MerchantReconciliationDao.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\order; + +use app\common\dao\BaseDao; +use app\common\model\store\order\MerchantReconciliation as model; +use app\common\repositories\system\admin\AdminRepository; +use app\common\repositories\system\merchant\MerchantRepository; + +class MerchantReconciliationDao extends BaseDao +{ + public function getModel(): string + { + return model::class; + } + + public function search(array $where) + { + $query = ($this->getModel()::getDB()) + ->when(isset($where['mer_id']) && $where['mer_id'] != '' ,function($query)use($where){ + $query->where('mer_id',$where['mer_id']); + })->when(isset($where['status']) && $where['status'] != '' ,function($query)use($where){ + $query->where('status',$where['status']); + })->when(isset($where['is_accounts']) && $where['is_accounts'] != '' ,function($query)use($where){ + $query->where('is_accounts',$where['is_accounts']); + })->when(isset($where['date']) && $where['date'] != '' ,function($query)use($where){ + getModelTime($query,$where['date']); + })->when(isset($where['reconciliation_id']) && $where['reconciliation_id'] != '' ,function($query)use($where){ + $query->where('reconciliation_id',$where['reconciliation_id']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '',function($query)use($where){ + $make = app()->make(AdminRepository::class); + $admin_id = $make->getSearch(['real_name' => $where['keyword']],null,false)->column('admin_id'); + $query->where(function($query) use($admin_id,$where){ + if(isset($where['mer_id'])){ + $query->where('admin_id','in',$admin_id); + }else { + $mer_make = app()->make(MerchantRepository::class); + $mer_id = $mer_make->getSearch(['keyword' => $where['keyword']])->column('mer_id'); + $query->where('admin_id','in',$admin_id)->whereOr('mer_id','in',$mer_id); + } + }); + }); + return $query->order('create_time DESC,status DESC'); + } + +} diff --git a/app/common/dao/store/order/MerchantReconciliationOrderDao.php b/app/common/dao/store/order/MerchantReconciliationOrderDao.php new file mode 100644 index 00000000..729aca23 --- /dev/null +++ b/app/common/dao/store/order/MerchantReconciliationOrderDao.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\order; + +use app\common\dao\BaseDao; +use app\common\model\store\order\MerchantReconciliationOrder as model; + +class MerchantReconciliationOrderDao extends BaseDao +{ + public function getModel(): string + { + return model::class; + } + + + public function search($where) + { + return ($this->getModel()::getDB())->when(isset($where['reconciliation_id']) && $where['reconciliation_id'] !== '',function ($query)use ($where){ + $query->where('reconciliation_id',$where['reconciliation_id']); + })->when(isset($where['type']) && $where['type'] !== '',function ($query)use ($where){ + $query->where('type',$where['type']); + }); + } +} diff --git a/app/common/dao/store/order/PresellOrderDao.php b/app/common/dao/store/order/PresellOrderDao.php new file mode 100644 index 00000000..2e5ccff1 --- /dev/null +++ b/app/common/dao/store/order/PresellOrderDao.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\order\PresellOrder; + +class PresellOrderDao extends BaseDao +{ + + protected function getModel(): string + { + return PresellOrder::class; + } + + public function search(array $where) + { + return PresellOrder::getDB()->when(isset($where['pay_type']) && $where['pay_type'] !== '', function ($query) use ($where) { + $query->whereIn('pay_type', $where['pay_type']); + })->when(isset($where['paid']) && $where['paid'] !== '', function ($query) use ($where) { + $query->where('paid', $where['paid']); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['order_ids']) && $where['order_ids'] !== '', function ($query) use ($where) { + $query->where('order_id','in',$where['order_ids']); + }); + } + + public function userOrder($uid, $orderId) + { + return PresellOrder::getDB()->where('uid', $uid)->where('order_id', $orderId)->find(); + } + + /** + * @param $time + * @return array + * @author xaboy + * @day 2020/11/3 + */ + public function getTimeOutIds($time) + { + return PresellOrder::getDB()->where('status', 1)->where('paid', 0) + ->where('final_end_time', '<', $time)->column('presell_order_id'); + } + + public function sendSmsIds($date) + { + return PresellOrder::getDB()->where('status', 1)->where('paid', 0) + ->whereLike('final_start_time', $date . '%')->column('order_id'); + } +} diff --git a/app/common/dao/store/order/StoreCartDao.php b/app/common/dao/store/order/StoreCartDao.php new file mode 100644 index 00000000..079fefb3 --- /dev/null +++ b/app/common/dao/store/order/StoreCartDao.php @@ -0,0 +1,160 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\order\StoreCart; +use app\common\model\user\UserAddress; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\model\Relation; + +class StoreCartDao extends BaseDao +{ + + protected function getModel(): string + { + return StoreCart::class; + } + + public function test() + { + return StoreCart::getDB()->with(['product' => function (Relation $query) { + $query->where('store_name', '儿童节礼物'); + }])->select(); + } + + /** + * @param array $ids + * @param $uid + * @param int|null $merId + * @return array + * @author xaboy + * @day 2020/6/5 + */ + public function validIntersection(array $ids, $uid, int $merId = null): array + { + return StoreCart::getDB()->whereIn('cart_id', $ids) + ->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + }) + ->where('is_del', 0)->where('is_fail', 0)->where('is_pay', 0)->where('uid', $uid)->column('cart_id'); + } + + /** + * @Author:Qinii + * @Date: 2020/6/1 + * @param int $uid + * @return mixed + */ + public function getAll(int $uid,$product_type) + { + $query = ($this->getModel())::where(['uid' => $uid, 'is_del' => 0, 'is_new' => 0, 'is_pay' => 0,'product_type' => $product_type]) + ->with([ + 'product' => function ($query) { + $query->field('product_id,image,store_name,is_show,status,is_del,unit_name,price,mer_status,is_used,product_type,once_max_count,once_min_count,pay_limit,mer_svip_status,svip_price_type'); + }, + 'productAttr' => function ($query) { + $query->field('product_id,stock,price,unique,sku,image,svip_price'); + }, + 'merchant' => function ($query) { + $query->field('mer_id,mer_name,mer_state,mer_avatar,is_trader,type_id')->with(['type_name']); + } + ])->select(); + + return $query; + } + + public function cartIbByData(array $ids, int $uid, ?UserAddress $address) + { + return StoreCart::getDb()->where('uid', $uid)->with([ + 'product' => function (Relation $query) use ($address) { + $query->field('product_id,cate_id,image,store_name,is_show,status,is_del,unit_name,price,mer_status,temp_id,give_coupon_ids,is_gift_bag,is_used,product_type,old_product_id,integral_rate,delivery_way,delivery_free,type,extend,pay_limit,once_max_count,once_min_count,mer_svip_status,svip_price_type'); + if ($address) { + $cityIds = array_filter([$address->province_id, $address->city_id, $address->district_id, $address->street_id]); + $query->with(['temp' => ['region' => function (Relation $query) use ($cityIds) { + $query->where(function ($query) use ($cityIds) { + foreach ($cityIds as $v) { + $query->whereOr('city_id', 'like', "%/{$v}/%"); + } + $query->whereOr('city_id', '0'); + })->order('shipping_template_region_id DESC')->withLimit(1); + }, 'undelives' => function ($query) use ($cityIds) { + foreach ($cityIds as $v) { + $query->whereOr('city_id', 'like', "%/{$v}/%"); + } + }, 'free' => function (Relation $query) use ($cityIds) { + foreach ($cityIds as $v) { + $query->whereOr('city_id', 'like', "%/{$v}/%"); + } + $query->order('shipping_template_free_id DESC')->withLimit(1); + }]]); + } + }, + 'productAttr' => function (Relation $query) { + $query->field('image,extension_one,extension_two,product_id,stock,price,unique,sku,volume,weight,ot_price,cost,svip_price') + ->append(['bc_extension_one', 'bc_extension_two']); + }, + 'merchant' => function (Relation $query) use ($uid) { + $query->field('mer_id,mer_name,mer_state,mer_avatar,delivery_way,commission_rate,category_id')->with(['coupon' => function ($query) use ($uid) { + $query->where('uid', $uid); + }, + 'config' => function ($query) { + $query->whereIn('config_key', ['mer_integral_status', 'mer_integral_rate', 'mer_store_stock', 'mer_take_status', 'mer_take_name', 'mer_take_phone', 'mer_take_address', 'mer_take_location', 'mer_take_day', 'mer_take_time']); + }, + 'merchantCategory' + ]); + }])->whereIn('cart_id', $ids)->order('product_type DESC,cart_id DESC')->select(); + } + + /** + * @param array $cartIds + * @param int $uid + * @author Qinii + */ + public function batchDelete(array $cartIds, int $uid) + { + return ($this->getModel()::getDB())->where('uid', $uid)->whereIn('cart_id', $cartIds)->delete(); + } + + /** + * @param int $uid + * @return mixed + * @author Qinii + */ + public function getCartCount(int $uid,$product_type) + { + $data = ($this->getModel()::getDB())->where(['uid' => $uid, 'is_del' => 0, 'is_new' => 0, 'is_pay' => 0,'product_type' => $product_type])->field('SUM(cart_num) as count')->select(); + $data[0]['count'] = $data[0]['count'] ? $data[0]['count'] : 0; + return $data; + } + + /** + * @param $source + * @param array|null $ids + * @author xaboy + * @day 2020/8/31 + */ + public function getSourcePayInfo($source, ?array $ids = null) + { + return StoreCart::getDB()->alias('A')->where('A.source', $source)->where('A.is_pay', 1)->when($ids, function ($query, $ids) { + $query->whereIn('A.source_id', $ids); + })->leftJoin('StoreOrderProduct B', 'A.cart_id = B.cart_id') + ->field('sum(B.product_num) as pay_num,sum(B.product_price) as pay_price,A.source_id')->group('A.source_id')->select(); + } +} diff --git a/app/common/dao/store/order/StoreCartDao.php.bak b/app/common/dao/store/order/StoreCartDao.php.bak new file mode 100644 index 00000000..0880d239 --- /dev/null +++ b/app/common/dao/store/order/StoreCartDao.php.bak @@ -0,0 +1,160 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\order\StoreCart; +use app\common\model\user\UserAddress; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\model\Relation; + +class StoreCartDao extends BaseDao +{ + + protected function getModel(): string + { + return StoreCart::class; + } + + public function test() + { + return StoreCart::getDB()->with(['product' => function (Relation $query) { + $query->where('store_name', '儿童节礼物'); + }])->select(); + } + + /** + * @param array $ids + * @param $uid + * @param int|null $merId + * @return array + * @author xaboy + * @day 2020/6/5 + */ + public function validIntersection(array $ids, $uid, int $merId = null): array + { + return StoreCart::getDB()->whereIn('cart_id', $ids) + ->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + }) + ->where('is_del', 0)->where('is_fail', 0)->where('is_pay', 0)->where('uid', $uid)->column('cart_id'); + } + + /** + * @Author:Qinii + * @Date: 2020/6/1 + * @param int $uid + * @return mixed + */ + public function getAll(int $uid) + { + $query = ($this->getModel())::where(['uid' => $uid, 'is_del' => 0, 'is_new' => 0, 'is_pay' => 0]) + ->with([ + 'product' => function ($query) { + $query->field('product_id,image,store_name,is_show,status,is_del,unit_name,price,mer_status,is_used,product_type,once_max_count,once_min_count,pay_limit,mer_svip_status,svip_price_type'); + }, + 'productAttr' => function ($query) { + $query->field('product_id,stock,price,unique,sku,image,svip_price'); + }, + 'merchant' => function ($query) { + $query->field('mer_id,mer_name,mer_state,mer_avatar,is_trader,type_id')->with(['type_name']); + } + ])->select(); + + return $query; + } + + public function cartIbByData(array $ids, int $uid, ?UserAddress $address) + { + return StoreCart::getDb()->where('uid', $uid)->with([ + 'product' => function (Relation $query) use ($address) { + $query->field('product_id,cate_id,image,store_name,is_show,status,is_del,unit_name,price,mer_status,temp_id,give_coupon_ids,is_gift_bag,is_used,product_type,old_product_id,integral_rate,delivery_way,delivery_free,type,extend,pay_limit,once_max_count,once_min_count,mer_svip_status,svip_price_type'); + if ($address) { + $cityIds = array_filter([$address->province_id, $address->city_id, $address->district_id, $address->street_id]); + $query->with(['temp' => ['region' => function (Relation $query) use ($cityIds) { + $query->where(function ($query) use ($cityIds) { + foreach ($cityIds as $v) { + $query->whereOr('city_id', 'like', "%/{$v}/%"); + } + $query->whereOr('city_id', '0'); + })->order('shipping_template_region_id DESC')->withLimit(1); + }, 'undelives' => function ($query) use ($cityIds) { + foreach ($cityIds as $v) { + $query->whereOr('city_id', 'like', "%/{$v}/%"); + } + }, 'free' => function (Relation $query) use ($cityIds) { + foreach ($cityIds as $v) { + $query->whereOr('city_id', 'like', "%/{$v}/%"); + } + $query->order('shipping_template_free_id DESC')->withLimit(1); + }]]); + } + }, + 'productAttr' => function (Relation $query) { + $query->field('image,extension_one,extension_two,product_id,stock,price,unique,sku,volume,weight,ot_price,cost,svip_price') + ->append(['bc_extension_one', 'bc_extension_two']); + }, + 'merchant' => function (Relation $query) use ($uid) { + $query->field('mer_id,mer_name,mer_state,mer_avatar,delivery_way,commission_rate,category_id')->with(['coupon' => function ($query) use ($uid) { + $query->where('uid', $uid); + }, + 'config' => function ($query) { + $query->whereIn('config_key', ['mer_integral_status', 'mer_integral_rate', 'mer_store_stock', 'mer_take_status', 'mer_take_name', 'mer_take_phone', 'mer_take_address', 'mer_take_location', 'mer_take_day', 'mer_take_time']); + }, + 'merchantCategory' + ]); + }])->whereIn('cart_id', $ids)->order('product_type DESC,cart_id DESC')->select(); + } + + /** + * @param array $cartIds + * @param int $uid + * @author Qinii + */ + public function batchDelete(array $cartIds, int $uid) + { + return ($this->getModel()::getDB())->where('uid', $uid)->whereIn('cart_id', $cartIds)->delete(); + } + + /** + * @param int $uid + * @return mixed + * @author Qinii + */ + public function getCartCount(int $uid) + { + $data = ($this->getModel()::getDB())->where(['uid' => $uid, 'is_del' => 0, 'is_new' => 0, 'is_pay' => 0])->field('SUM(cart_num) as count')->select(); + $data[0]['count'] = $data[0]['count'] ? $data[0]['count'] : 0; + return $data; + } + + /** + * @param $source + * @param array|null $ids + * @author xaboy + * @day 2020/8/31 + */ + public function getSourcePayInfo($source, ?array $ids = null) + { + return StoreCart::getDB()->alias('A')->where('A.source', $source)->where('A.is_pay', 1)->when($ids, function ($query, $ids) { + $query->whereIn('A.source_id', $ids); + })->leftJoin('StoreOrderProduct B', 'A.cart_id = B.cart_id') + ->field('sum(B.product_num) as pay_num,sum(B.product_price) as pay_price,A.source_id')->group('A.source_id')->select(); + } +} diff --git a/app/common/dao/store/order/StoreGroupOrderDao.php b/app/common/dao/store/order/StoreGroupOrderDao.php new file mode 100644 index 00000000..5826df98 --- /dev/null +++ b/app/common/dao/store/order/StoreGroupOrderDao.php @@ -0,0 +1,95 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreGroupOrder; + +/** + * Class StoreGroupOrderDao + * @package app\common\dao\store\order + * @author xaboy + * @day 2020/6/9 + */ +class StoreGroupOrderDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/6/9 + */ + protected function getModel(): string + { + return StoreGroupOrder::class; + } + + /** + * @param null $uid + * @return int + * @author xaboy + * @day 2020/6/11 + */ + public function orderNumber($uid = null) + { + return StoreGroupOrder::when($uid, function ($query, $uid) { + $query->where('uid', $uid); + })->where('is_del', 0)->where('paid', 0)->count(); + } + + /** + * @param array $where + * @return \think\db\BaseQuery + * @author xaboy + * @day 2020/6/9 + */ + public function search(array $where) + { + return StoreGroupOrder::getDB()->when(isset($where['paid']) && $where['paid'] !== '', function ($query) use ($where) { + $query->where('paid', $where['paid']); + })->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->order('create_time DESC')->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) { + $query->where('is_del', $where['is_del']); + }, function ($query) { + $query->where('is_del', 0); + }); + } + + /** + * @param $time + * @param bool $is_remind + * @return array + * @author xaboy + * @day 2020/6/9 + */ + public function getTimeOutIds($time, $is_remind = false) + { + return StoreGroupOrder::getDB()->where('is_del', 0)->where('paid', 0) + ->when($is_remind, function ($query) { + $query->where('is_remind', 0); + })->where('create_time', '<=', $time)->column('group_order_id'); + } + + public function isRemind($id) + { + return StoreGroupOrder::getDB()->where('group_order_id', $id)->update(['is_remind' => 1]); + } + + public function totalNowMoney($uid) + { + return StoreGroupOrder::getDB()->where('pay_type', 0)->where('uid', $uid)->sum('pay_price') ?: 0; + } +} diff --git a/app/common/dao/store/order/StoreImportDao.php b/app/common/dao/store/order/StoreImportDao.php new file mode 100644 index 00000000..e5935f6e --- /dev/null +++ b/app/common/dao/store/order/StoreImportDao.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreImport; + +class StoreImportDao extends BaseDao +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 3/16/21 + */ + protected function getModel(): string + { + return StoreImport::class; + } +} diff --git a/app/common/dao/store/order/StoreImportDeliveryDao.php b/app/common/dao/store/order/StoreImportDeliveryDao.php new file mode 100644 index 00000000..9eb4e697 --- /dev/null +++ b/app/common/dao/store/order/StoreImportDeliveryDao.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreImportDelivery; + +class StoreImportDeliveryDao extends BaseDao +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 3/16/21 + */ + protected function getModel(): string + { + return StoreImportDelivery::class; + } +} diff --git a/app/common/dao/store/order/StoreOrderDao.php b/app/common/dao/store/order/StoreOrderDao.php new file mode 100644 index 00000000..cd283261 --- /dev/null +++ b/app/common/dao/store/order/StoreOrderDao.php @@ -0,0 +1,737 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreOrderProduct; +use app\common\model\store\order\StoreOrderStatus; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; + +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\Model; + +/** + * Class StoreOrderDao + * @package app\common\dao\store\order + * @author xaboy + * @day 2020/6/8 + */ +class StoreOrderDao extends BaseDao +{ + //订单状态(0:待发货;1:待收货;2:待评价;3:已完成; 9: 拼团中 10: 待付尾款 11:尾款超时未付 -1:已退款) + const ORDER_STATUS_BE_SHIPPED = 0; + const ORDER_STATUS_BE_RECEIVE = 1; + const ORDER_STATUS_REPLY = 2; + const ORDER_STATUS_SUCCESS = 3; + const ORDER_STATUS_SPELL = 9; + const ORDER_STATUS_TAIL = 10; + const ORDER_STATUS_TAIL_FAIL = 11; + const ORDER_STATUS_REFUND = -1; + + + /** + * @return string + * @author xaboy + * @day 2020/6/8 + */ + protected function getModel(): string + { + return StoreOrder::class; + } + + /** + * @param array $where + * @param int $sysDel + * @return BaseQuery + * @author xaboyCRMEB + * @day 2020/6/16 + */ + public function search(array $where, $sysDel = 0) + { + $query = StoreOrder::hasWhere('merchant', function ($query) use ($where) { + if (isset($where['is_trader']) && $where['is_trader'] !== '') { + $query->where('is_trader', $where['is_trader']); + } + $query->where('is_del',0); + }); + + $query->when(($sysDel !== null), function ($query) use ($sysDel) { + $query->where('is_system_del', $sysDel); + }) + ->when(isset($where['order_type']) && $where['order_type'] >= 0 && $where['order_type'] !== '', function ($query) use ($where) { + if ($where['order_type'] == 2) { + $query->where('is_virtual', 1); + } else if($where['order_type'] == 0){ //实体发货订单 + $query->where('order_type', 0)->where('is_virtual',0); + } else if($where['order_type'] == 3) { //发货订单 + $query->where('order_type', 0); + } else { + $query->where('order_type', $where['order_type']); + } + }) + ->when(isset($where['activity_type']) && $where['activity_type'] != '', function ($query) use ($where) { + $query->where('activity_type', $where['activity_type']); + }) + ->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + switch ($where['status']) { + case 0 : + $query->whereIn('StoreOrder.status', [0, 9]); + break; + case -2 : + $query->where('paid', 1)->whereNotIn('StoreOrder.status', [10, 11]); + break; + case 10 : + $query->where('paid', 1)->whereIn('StoreOrder.status', [10, 11]); + break; + default: + $query->where('StoreOrder.status', $where['status']); + break; + } + }) + ->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + }) + ->when(isset($where['is_user']) && $where['is_user'] !== '', function ($query) use ($where) { + $query->where(function($query) { + $query->where('order_type',0)->whereOr(function($query){ + $query->where('order_type',1)->where('main_id',0); + }); + }); + }) + //待核销订单 + ->when(isset($where['is_verify']) && $where['is_verify'], function ($query) use ($where) { + $query->where('StoreOrder.order_type', 1)->where('StoreOrder.status',0); + }) + ->when(isset($where['pay_type']) && $where['pay_type'] !== '', function ($query) use ($where) { + $query->where('StoreOrder.pay_type', $where['pay_type']); + }) + ->when(isset($where['order_ids']) && $where['order_ids'] !== '', function ($query) use ($where) { + $query->whereIn('order_id', $where['order_ids']); + }) + ->when(isset($where['order_id']) && $where['order_id'] !== '', function ($query) use ($where) { + $query->where('order_id', $where['order_id']); + }) + ->when(isset($where['take_order']) && $where['take_order'] != '', function ($query) use ($where) { + $query->where('order_type', 1)->whereNotNull('verify_time'); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('StoreOrder.mer_id', $where['mer_id']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'StoreOrder.create_time'); + }) + ->when(isset($where['verify_date']) && $where['verify_date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['verify_date'], 'verify_time'); + }) + ->when(isset($where['order_sn']) && $where['order_sn'] !== '', function ($query) use ($where) { + $query->where('order_sn', 'like', '%' . $where['order_sn'] . '%'); + }) + ->when(isset($where['paid']) && $where['paid'] !== '', function ($query) use ($where) { + $query->where('StoreOrder.paid', $where['paid']); + }) + ->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) { + $query->where('StoreOrder.is_del', $where['is_del']); + }) + ->when(isset($where['service_id']) && $where['service_id'] !== '', function ($query) use ($where) { + $query->where('service_id', $where['service_id']); + }) + ->when(isset($where['username']) && $where['username'] !== '', function ($query) use ($where) { + $query->join('User U','StoreOrder.uid = U.uid') + ->where(function($query) use($where) { + $query->where('nickname', 'like', "%{$where['username']}%") + ->whereOr('phone', 'like', "%{$where['username']}%") + ->whereOr('user_phone', 'like', "%{$where['username']}%"); + }); + }) + ->when(isset($where['store_name']) && $where['store_name'] !== '', function ($query) use ($where) { + $orderId = StoreOrderProduct::alias('op') + ->join('storeProduct sp','op.product_id = sp.product_id') + ->whereLike('store_name',"%{$where['store_name']}%") + ->when((isset($where['sp.mer_id']) && $where['mer_id'] !== ''),function($query) use($where){ + $query->where('mer_id',$where['mer_id']); + })->column('order_id'); + $query->whereIn('order_id',$orderId ?: '' ); + }) + ->when(isset($where['search']) && $where['search'] !== '', function ($query) use ($where) { + $orderId = StoreOrderProduct::alias('op') + ->join('storeProduct sp','op.product_id = sp.product_id') + ->whereLike('store_name',"%{$where['search']}%") + ->when((isset($where['sp.mer_id']) && $where['mer_id'] !== ''),function($query) use($where){ + $query->where('mer_id',$where['mer_id']); + })->column('order_id'); + $query->where(function($query) use($orderId,$where){ + $query->whereIn('order_id',$orderId ? $orderId : '') + ->whereOr('order_sn','like',"%{$where['search']}%") + ->whereOr('user_phone','like',"%{$where['search']}%"); + }); + }) + ->when(isset($where['group_order_sn']) && $where['group_order_sn'] !== '', function ($query) use ($where) { + $query->join('StoreGroupOrder GO','StoreOrder.group_order_id = GO.group_order_id')->where('group_order_sn',$where['group_order_sn']); + }) + ->when(isset($where['keywords']) && $where['keywords'] !== '', function ($query) use ($where) { + $query->where(function ($query) use ($where) { + $query->whereLike('StoreOrder.real_name|StoreOrder.user_phone|order_sn', "%" . $where['keywords'] . "%"); + }); + }) + ->when(isset($where['reconciliation_type']) && $where['reconciliation_type'] !== '', function ($query) use ($where) { + $query->when($where['reconciliation_type'], function ($query) use ($where) { + $query->where('reconciliation_id', '<>', 0); + }, function ($query) use ($where) { + $query->where('reconciliation_id', 0); + }); + })->order('StoreOrder.create_time DESC'); + + return $query; + } + + + /** + * @param $id + * @param $uid + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/11 + */ + public function userOrder($id, $uid) + { + return StoreOrder::getDB()->where('order_id', $id)->where('uid', $uid)->where('is_del', 0)->where('paid', 1)->where('is_system_del', 0)->find(); + } + + /** + * @param array $where + * @param $ids + * @return BaseQuery + * @author xaboy + * @day 2020/6/26 + */ + public function usersOrderQuery(array $where, $ids, $uid) + { + return StoreOrder::getDB()->where(function ($query) use ($uid, $ids) { + $query->whereIn('uid', $ids)->whereOr(function ($query) use ($uid) { + if ($uid) { + $query->where('uid', $uid)->where('is_selfbuy', 1); + } + }); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'pay_time'); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('order_id|order_sn', "%{$where['keyword']}%"); + })->where('paid', 1)->order('pay_time DESC'); + } + + /** + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020/6/11 + */ + public function fieldExists($field, $value, ?int $except = null): bool + { + return ($this->getModel()::getDB())->when($except, function ($query) use ($field, $except) { + $query->where($field, '<>', $except); + })->where($field, $value)->count() > 0; + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/6/12 + */ + public function getMerId($id) + { + return StoreOrder::getDB()->where('order_id', $id)->value('mer_id'); + } + + /** + * @param array $where + * @return bool + * @author Qinii + * @day 2020-06-12 + */ + public function merFieldExists(array $where) + { + return ($this->getModel()::getDB())->where($where)->count() > 0; + } + + /** + * TODO + * @param $reconciliation_id + * @return mixed + * @author Qinii + * @day 2020-06-15 + */ + public function reconciliationUpdate($reconciliation_id) + { + return ($this->getModel()::getDB())->whereIn('reconciliation_id', $reconciliation_id)->update(['reconciliation_id' => 0]); + } + + public function dayOrderNum($day, $merId = null) + { + return StoreOrder::getDB()->where('paid', 1)->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($day, function ($query, $day) { + getModelTime($query, $day, 'pay_time'); + })->count(); + } + + public function dayOrderPrice($day, $merId = null) + { + return getModelTime(StoreOrder::getDB()->where('paid', 1)->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + }), $day, 'pay_time')->sum('pay_price'); + } + + public function dateOrderPrice($date, $merId = null) + { + return StoreOrder::getDB()->where('paid', 1)->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->sum('pay_price'); + } + + public function dateOrderNum($date, $merId = null) + { + return StoreOrder::getDB()->where('paid', 1)->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->count(); + } + + public function dayOrderUserNum($day, $merId = null) + { + return StoreOrder::getDB()->where('paid', 1)->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($day, function ($query, $day) { + getModelTime($query, $day, 'pay_time'); + })->group('uid')->count(); + } + + public function orderUserNum($date, $paid = null, $merId = null) + { + return StoreOrder::getDB()->when($paid, function ($query, $paid) { + $query->where('paid', $paid); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($date, function ($query, $date) use ($paid) { + if (!$paid) { + getModelTime($query, $date); +// $query->where(function ($query) use ($date) { +// $query->where(function ($query) use ($date) { +// $query->where('paid', 1); +// getModelTime($query, $date, 'pay_time'); +// })->whereOr(function ($query) use ($date) { +// $query->where('paid', 0); +// getModelTime($query, $date); +// }); +// }); + } else + getModelTime($query, $date, 'pay_time'); + })->group('uid')->count(); + } + + public function orderUserGroup($date, $paid = null, $merId = null) + { + return StoreOrder::getDB()->when($paid, function ($query, $paid) { + $query->where('paid', $paid); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->group('uid')->field(Db::raw('uid,sum(pay_price) as pay_price,count(order_id) as total'))->select(); + } + + public function oldUserNum(array $ids, $merId = null) + { + return StoreOrder::getDB()->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->whereIn('uid', $ids)->where('paid', 1)->group('uid')->count(); + } + + public function oldUserIds(array $ids, $merId = null) + { + return StoreOrder::getDB()->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->whereIn('uid', $ids)->where('paid', 1)->group('uid')->column('uid'); + } + + public function orderPrice($date, $paid = null, $merId = null) + { + return StoreOrder::getDB()->when($paid, function ($query, $paid) { + $query->where('paid', $paid); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->when($date, function ($query, $date) use ($paid) { + if (!$paid) { + $query->where(function ($query) use ($date) { + $query->where(function ($query) use ($date) { + $query->where('paid', 1); + getModelTime($query, $date, 'pay_time'); + })->whereOr(function ($query) use ($date) { + $query->where('paid', 0); + getModelTime($query, $date); + }); + }); + } else + getModelTime($query, $date, 'pay_time'); + })->sum('pay_price'); + } + + public function orderGroupNum($date, $merId = null) + { + $field = Db::raw('sum(pay_price) as pay_price,count(*) as total,count(distinct uid) as user,pay_time,from_unixtime(unix_timestamp(pay_time),\'%m-%d\') as `day`'); + if ($date == 'year'){ + $field = Db::raw('sum(pay_price) as pay_price,count(*) as total,count(distinct uid) as user,pay_time,from_unixtime(unix_timestamp(pay_time),\'%m\') as `day`'); + } + $query = StoreOrder::getDB()->field($field) + ->where('paid', 1)->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + }); + return $query->order('pay_time ASC')->group('day')->select(); + } + + public function orderGroupNumPage($where, $page, $limit, $merId = null) + { + return StoreOrder::getDB()->when(isset($where['dateRange']), function ($query) use ($where) { + getModelTime($query, date('Y/m/d 00:00:00', $where['dateRange']['start']) . '-' . date('Y/m/d 00:00:00', $where['dateRange']['stop']), 'pay_time'); + })->field(Db::raw('sum(pay_price) as pay_price,count(*) as total,count(distinct uid) as user,pay_time,from_unixtime(unix_timestamp(pay_time),\'%m-%d\') as `day`')) + ->where('paid', 1)->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->order('pay_time DESC')->page($page, $limit)->group('day')->select(); + } + + public function dayOrderPriceGroup($date, $merId = null) + { + return StoreOrder::getDB()->field(Db::raw('sum(pay_price) as price, from_unixtime(unix_timestamp(pay_time),\'%H:%i\') as time')) + ->where('paid', 1)->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->group('time')->select(); + } + + public function dayOrderNumGroup($date, $merId = null) + { + return StoreOrder::getDB()->field(Db::raw('count(*) as total, from_unixtime(unix_timestamp(pay_time),\'%H:%i\') as time')) + ->where('paid', 1)->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->group('time')->select(); + } + + public function dayOrderUserGroup($date, $merId = null) + { + return StoreOrder::getDB()->field(Db::raw('count(DISTINCT uid) as total, from_unixtime(unix_timestamp(pay_time),\'%H:%i\') as time')) + ->where('paid', 1)->when($date, function ($query, $date) { + getModelTime($query, $date, 'pay_time'); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->group('time')->select(); + } + + /** + * 获取当前时间到指定时间的支付金额 管理员 + * @param string $start 开始时间 + * @param string $stop 结束时间 + * @return mixed + */ + public function chartTimePrice($start, $stop, $merId = null) + { + return StoreOrder::getDB()->where('paid', 1) + ->where('pay_time', '>=', $start) + ->where('pay_time', '<', $stop) + ->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + }) + ->field('sum(pay_price) as num,FROM_UNIXTIME(unix_timestamp(pay_time), \'%Y-%m-%d\') as time') + ->group('time') + ->order('pay_time ASC')->select()->toArray(); + } + + /** + * @param $date + * @param null $merId + * @return mixed + */ + public function chartTimeNum($date, $merId = null) + { + return StoreOrder::getDB()->where('paid', 1)->when($date, function ($query) use ($date) { + getModelTime($query, $date, 'pay_time'); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->field('count(order_id) as num,FROM_UNIXTIME(unix_timestamp(pay_time), \'%Y-%m-%d\') as time') + ->group('time') + ->order('pay_time ASC')->select()->toArray(); + } + + /** + * @param $end + * @return mixed + * @author xaboy + * @day 2020/9/16 + */ + public function getFinishTimeoutIds($end) + { + return StoreOrderStatus::getDB()->alias('A')->leftJoin('StoreOrder B', 'A.order_id = B.order_id') + ->where('A.change_type', 'take') + ->where('A.change_time', '<', $end)->where('B.paid', 1)->where('B.status', 2) + ->column('A.order_id'); + } + + + /** + * TODO 参与人数 + * @param array $data + * @param int|null $uid + * @return BaseQuery + * @author Qinii + * @day 2020-11-11 + */ + public function getTattendCount(array $data,?int $uid) + { + $query = StoreOrder::hasWhere('orderProduct',function($query)use($data,$uid){ + $query->when(isset($data['activity_id']),function ($query)use($data){ + $query->where('activity_id',$data['activity_id']); + }) + ->when(isset($data['product_sku']),function ($query)use($data){ + $query->where('product_sku',$data['product_sku']); + }) + ->when(isset($data['product_id']),function ($query)use($data){ + $query->where('product_id',$data['product_id']); + }) + ->when(isset($data['exsits_id']),function ($query)use ($data){ + switch ($data['product_type']){ + case 3: + $make = app()->make(ProductAssistSetRepository::class); + $id = 'product_assist_id'; + break; + case 4: + $make = app()->make(ProductGroupBuyingRepository::class); + $id = 'product_group_id'; + break; + } + $where = [$id => $data['exsits_id']]; + $activity_id = $make->getSearch($where)->column($make->getPk()); + if($activity_id) { + $id = array_unique($activity_id); + $query->where('activity_id','in',$id); + }else{ + $query->where('activity_id','<',0); + } + }) + ->where('product_type',$data['product_type']); + if($uid) $query->where('uid',$uid); + }); + $query->where('activity_type',$data['product_type']); + switch($data['product_type']) + { + case 0: + $query->where(function($query){ + $query->where(function($query){ + $query->where('paid',1); + })->whereOr(function($query){ + $query->where('paid',0)->where('is_del',0); + }); + }); + break; + case 1: //秒杀 + $query->where(function($query){ + $query->where(function($query){ + $query->where('paid',1); + })->whereOr(function($query){ + $query->where('paid',0)->where('is_del',0); + }); + })->when(isset($data['day']), function ($query) use ($data) { + $query->whereDay('StoreOrder.create_time', $data['day']); + }); + break; + case 2: //预售 + + /** + * 第一阶段参与人数:所有人 + * 第二阶段参与人数:支付了第一阶段 + */ + //第二阶段 + if($data['type'] == 1){ + $query->where(function($query){ + $query->where('paid',1)->whereOr(function($query){ + $query->where('paid',0)->where('is_del',0); + }); + }); + } + if($data['type'] == 2) $query->where('paid',1)->where('status','in',[0,1,2,3,-1]); + break; + case 3: //助力 + $query->where(function($query){ + $query->where('paid',1)->whereOr(function($query){ + $query->where('paid',0)->where('is_del',0); + }); + }); + break; + case 4: // + $query->where(function($query){ + $query->where('paid',1)->whereOr(function($query){ + $query->where('paid',0)->where('is_del',0); + }) + ->where('status','>',-1); + }); + break; + } + return $query; + } + + /** + * 未使用 + * TODO 成功支付人数 + * @param int $productType + * @param int $activityId + * @param int|null $uid + * @param int|null $status + * @author Qinii + * @day 2020-10-30 + */ + public function getTattendSuccessCount($data,?int $uid) + { + $query = StoreOrder::hasWhere('orderProduct',function($query)use($data,$uid){ + $query->when(isset($data['activity_id']),function ($query)use($data){ + $query->where('activity_id',$data['activity_id']); + }) + ->when(isset($data['product_sku']),function ($query)use($data){ + $query->where('product_sku',$data['product_sku']); + }) + ->when(isset($data['product_id']),function ($query)use($data){ + $query->where('product_id',$data['product_id']); + }) + ->when(isset($data['exsits_id']),function ($query)use ($data){ + switch ($data['product_type']){ + case 3: + $make = app()->make(ProductAssistSetRepository::class); + $id = 'product_assist_id'; + break; + case 4: + $make = app()->make(ProductGroupBuyingRepository::class); + $id = 'product_group_id'; + break; + } + $where = [$id => $data['exsits_id']]; + $activity_id = $make->getSearch($where)->column($make->getPk()); + if($activity_id) { + $id = array_unique($activity_id); + $query->where('activity_id','in',$id); + }else{ + $query->where('activity_id','<',0); + } + }) + ->where('product_type',$data['product_type']); + if($uid) $query->where('uid',$uid); + }); + $query->where('activity_type',$data['product_type'])->where('paid',1); + + switch($data['product_type']) + { + case 1: //秒杀 + $query->where(function($query){ + $query->where(function($query){ + $query->where('paid',1); + }); + })->when(isset($data['day']), function ($query) use ($data) { + $query->whereDay('StoreOrder.create_time', $data['day']); + }); + break; + case 2: //预售 + if($data['type'] == 1){ //第一阶段 + $query->where('status','in',[0,1,2,3,10]); + } else { //第二阶段 + $query->where('status','in',[0,1,2,3]); + } + break; + case 3: //助力 + break; + case 4: + break; + } + return $query; + } + + + /** + * TODO 获取退款单数量 + * @param $where + * @return mixed + * @author Qinii + * @day 1/4/21 + */ + public function getSeckillRefundCount($where,$type = 1) + { + $query = StoreOrderProduct::getDB()->alias('P')->join('StoreRefundOrder R','P.order_id = R.order_id'); + $query->join('StoreOrder O','O.order_id = P.order_id'); + $query + ->when(isset($where['activity_id']),function ($query)use($where){ + $query->where('P.activity_id',$where['activity_id']); + }) + ->when(isset($where['product_sku']),function ($query)use($where){ + $query->where('P.product_sku',$where['product_sku']); + }) + ->when(isset($where['day']), function ($query) use ($where) { + $query->whereDay('P.create_time', $where['day']); + }) + ->when($type == 1, function ($query) use ($where) { + $query->where('O.verify_time',null)->where('O.delivery_type',null); + },function ($query){ + $query ->where('R.refund_type',2); + }) + ->where('P.product_type',1)->where('R.status',3); + return $query->count(); + } + + + /** + * TODO 用户的某个商品购买数量 + * @param int $uid + * @param int $productId + * @return int + * @author Qinii + * @day 2022/9/26 + */ + public function getMaxCountNumber(int $uid, int $productId) + { + return StoreOrder::hasWhere('orderProduct',function($query) use($productId){ + $query->where('product_id', $productId); + }) + ->where(function($query) { + $query->where('is_del',0)->whereOr(function($query){ + $query->where('is_del',1)->where('paid',1); + }); + })->where('StoreOrder.uid',$uid)->count() + ; + } +} diff --git a/app/common/dao/store/order/StoreOrderProductDao.php b/app/common/dao/store/order/StoreOrderProductDao.php new file mode 100644 index 00000000..d60cbba0 --- /dev/null +++ b/app/common/dao/store/order/StoreOrderProductDao.php @@ -0,0 +1,145 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrderProduct; +use think\facade\Db; +use think\model\Relation; + +/** + * Class StoreOrderProductDao + * @package app\common\dao\store\order + * @author xaboy + * @day 2020/6/10 + */ +class StoreOrderProductDao extends BaseDao +{ + const ORDER_VERIFY_STATUS_ = 1; + const ORDER_VERIFY_STATUS_SUCCESS = 3; + /** + * @return string + * @author xaboy + * @day 2020/6/10 + */ + protected function getModel(): string + { + return StoreOrderProduct::class; + } + + /** + * @param $id + * @param $uid + * @return array|\think\Model|null + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function userOrderProduct($id, $uid) + { + return StoreOrderProduct::getDB()->where('uid', $uid)->where('order_product_id', $id)->with(['orderInfo' => function (Relation $query) { + $query->field('order_id,order_sn,mer_id')->where('status', 2); + }])->find(); + } + + /** + * @param $orderId + * @return int + * @author xaboy + * @day 2020/6/12 + */ + public function noReplyProductCount($orderId) + { + return StoreOrderProduct::getDB()->where('order_id', $orderId)->where('is_refund','<>','3')->where('is_reply', 0) + ->count(); + } + + /** + * @param array $ids + * @param $uid + * @param null $orderId + * @return \think\Collection + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function userRefundProducts(array $ids, $uid, $orderId = null) + { + return StoreOrderProduct::getDB()->whereIn('order_product_id', $ids)->when($orderId, function ($query, $orderId) { + return $query->where('order_id', $orderId); + })->where('uid', $uid)->where('refund_num', '>', 0)->select(); + } + + public function orderProductGroup($date, $merId = null, $limit = 7) + { + return StoreOrderProduct::getDB()->alias('A')->leftJoin('StoreOrder B', 'A.order_id = B.order_id') + ->field(Db::raw('sum(A.product_num) as total,A.product_id,cart_info')) + ->withAttr('cart_info', function ($val) { + return json_decode($val, true); + })->when($date, function ($query, $date) { + getModelTime($query, $date, 'B.pay_time'); + })->when($merId, function ($query, $merId) { + $query->where('B.mer_id', $merId); + })->where('B.paid', 1)->group('A.product_id')->limit($limit)->order('total DESC')->select(); + } + + public function dateProductNum($date) + { + return StoreOrderProduct::getDB()->alias('A')->leftJoin('StoreOrder B', 'A.order_id = B.order_id')->when($date, function ($query, $date) { + getModelTime($query, $date, 'B.pay_time'); + })->where('B.paid',1)->sum('A.product_num'); + } + + /** + * TODO 用户购买活动商品数量 + * @param int $activityId + * @param int $uid + * @param int $orderType + * @return int + * @author Qinii + * @day 2020-10-23 + */ + public function getUserPayCount(int $activityId,int $uid,int $productType) + { + $query = StoreOrderProduct::hasWhere('orderInfo',function($query){ + // 已支付/未支付 + $query->where('is_del',0)->whereOr(function($query){ + $query->where('paid',1)->where('is_del',1); + }); + }); + $query->where('uid',$uid)->where('product_type',$productType)->where('activity_id',$activityId); + $count = $query->count(); + return $count; + } + + + public function getUserPayProduct(?string $keyword, int $uid) + { + $query = StoreOrderProduct::hasWhere('spu',function($query) use($keyword){ + $query->when($keyword, function ($query) use($keyword) { + $query->whereLike('store_name',"%{$keyword}%"); + }); + $query->where('product_type',0); + }); + $query->where('uid', $uid)->where('StoreOrderProduct.product_type',0); + return $query; + } + +} diff --git a/app/common/dao/store/order/StoreOrderProfitsharingDao.php b/app/common/dao/store/order/StoreOrderProfitsharingDao.php new file mode 100644 index 00000000..b9a6253c --- /dev/null +++ b/app/common/dao/store/order/StoreOrderProfitsharingDao.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\order; + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreOrderProfitsharing; + +class StoreOrderProfitsharingDao extends BaseDao +{ + protected function getModel(): string + { + return StoreOrderProfitsharing::class; + } + + public function getOrderSn() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = 'pr' . $msectime . random_int(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + public function search(array $where) + { + return StoreOrderProfitsharing::getDB()->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['order_id']) && $where['order_id'] !== '', function ($query) use ($where) { + $query->where('order_id', $where['order_id']); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('type', $where['type']); + })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + })->when(isset($where['profit_date']) && $where['profit_date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['profit_date'], 'profitsharing_time'); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('keyword', "%{$where['keyword']}%"); + }); + } + + public function getAutoProfitsharing($time) + { + return StoreOrderProfitsharing::getDB()->alias('A')->join('StoreOrder B', 'A.order_id = B.order_id', 'left') + ->where(function ($query) { + $query->where('B.status', '>', 1)->whereOr('B.status', -1); + })->where('A.status', 0)->where(function ($query) use ($time) { + $query->whereNotNull('B.verify_time')->where('B.verify_time', '<', $time); + })->column('A.profitsharing_id'); + } +} diff --git a/app/common/dao/store/order/StoreOrderReceiptDao.php b/app/common/dao/store/order/StoreOrderReceiptDao.php new file mode 100644 index 00000000..26124ac6 --- /dev/null +++ b/app/common/dao/store/order/StoreOrderReceiptDao.php @@ -0,0 +1,100 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\order; + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreOrderReceipt; +use app\common\model\user\User; + +class StoreOrderReceiptDao extends BaseDao +{ + protected function getModel(): string + { + return StoreOrderReceipt::class; + } + + public function search(array $where) + { + if((isset($where['order_type']) && $where['order_type'] !== '') || (isset($where['keyword']) && $where['keyword'] !== '')){ + $query = StoreOrderReceipt::hasWhere('storeOrder',function($query)use($where){ + switch ($where['order_type']) + { + case 1: + $query->where('StoreOrder.paid',0)->where('StoreOrder.is_del',0); + break; // 未支付 + case 2: + $query->where('StoreOrder.paid',1)->where('StoreOrder.status',0)->where('StoreOrder.is_del',0); + break; // 待发货 + case 3: + $query->where('StoreOrder.status',1)->where('StoreOrder.is_del',0); + break; // 待收货 + case 4: + $query->where('StoreOrder.status',2)->where('StoreOrder.is_del',0); + break; // 待评价 + case 5: + $query->where('StoreOrder.status',3)->where('StoreOrder.is_del',0); + break; // 交易完成 + case 6: + $query->where('StoreOrder.status',-1)->where('StoreOrder.is_del',0); + break; // 已退款 + case 7: + $query->where('StoreOrder.is_del',1); + break; // 已删除 + case 8: + $query->where('StoreOrder.is_del', 0); + break; //全部 + default: + $query->where(true); + break; //全部 + } + $query->when(isset($where['keyword']) && $where['keyword'] !== '' ,function($query)use($where){ + $query->whereLike("order_sn|real_name|user_phone","%{$where['keyword']}%"); + }); + }); + }else{ + $query = StoreOrderReceipt::alias('StoreOrderReceipt'); + } + $query->when(isset($where['status']) && $where['status'] !== '' ,function($query)use($where){ + $query->where('StoreOrderReceipt.status',$where['status']); + }) + ->when(isset($where['date']) && $where['date'] !== '' ,function($query)use($where){ + getModelTime($query,$where['date'],'StoreOrderReceipt.create_time'); + }) + ->when(isset($where['receipt_sn']) && $where['receipt_sn'] !== '' ,function($query)use($where){ + $query->where('StoreOrderReceipt.receipt_sn',$where['receipt_sn']); + }) + ->when(isset($where['username']) && $where['username'] !== '' ,function($query)use($where){ + $uid = User::whereLike('nickname|phone',"%{$where['username']}%")->column('uid'); + $query->where('StoreOrderReceipt.uid','in',$uid); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '' ,function($query)use($where){ + $query->where('StoreOrderReceipt.mer_id',$where['mer_id']); + }) + ->when(isset($where['uid']) && $where['uid'] !== '' ,function($query)use($where){ + $query->where('StoreOrderReceipt.uid',$where['uid']); + }) + ; + return $query->order('StoreOrderReceipt.create_time DESC'); + } + + public function updateBySn(string $receipt_sn,$data) + { + return $this->getModel()::getDB()->where('receipt_sn',$receipt_sn)->update($data); + } + + + public function deleteByOrderId($id) + { + return $this->getModel()::getDB()->where('order_id',$id)->delete(); + } +} diff --git a/app/common/dao/store/order/StoreOrderStatusDao.php b/app/common/dao/store/order/StoreOrderStatusDao.php new file mode 100644 index 00000000..050fcee1 --- /dev/null +++ b/app/common/dao/store/order/StoreOrderStatusDao.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrderStatus; + +/** + * Class StoreOrderStatusDao + * @package app\common\dao\store\order + * @author xaboy + * @day 2020/6/12 + */ +class StoreOrderStatusDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/6/12 + */ + protected function getModel(): string + { + return StoreOrderStatus::class; + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/6/12 + */ + public function search($where) + { + $query = ($this->getModel()::getDB()) + ->when(isset($where['id']) && $where['id'] !== '', function($query) use($where){ + $query->where('order_id', $where['id']); + }) + ->when(isset($where['type']) && $where['type'] !== '', function($query) use($where){ + $query->where('type', $where['type']); + }) + ->when(isset($where['user_type']) && $where['user_type'] !== '', function($query) use($where){ + $query->where('user_type', $where['user_type']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function($query) use($where){ + getModelTime($query, $where['date'],'change_time'); + }); + return $query; + } + + public function getTimeoutDeliveryOrder($end) + { + return StoreOrderStatus::getDB()->alias('A')->leftJoin('StoreOrder B', 'A.order_id = B.order_id') + ->whereIn('A.change_type', ['delivery_0', 'delivery_1', 'delivery_2']) + ->where('A.change_time', '<', $end)->where('B.paid', 1)->where('B.status', 1) + ->column('A.order_id'); + } +} diff --git a/app/common/dao/store/order/StoreRefundOrderDao.php b/app/common/dao/store/order/StoreRefundOrderDao.php new file mode 100644 index 00000000..1e25f8d4 --- /dev/null +++ b/app/common/dao/store/order/StoreRefundOrderDao.php @@ -0,0 +1,161 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreRefundOrder; +use app\common\repositories\system\merchant\MerchantRepository; +use think\db\BaseQuery; +use think\db\exception\DbException; + +class StoreRefundOrderDao extends BaseDao +{ + + protected function getModel(): string + { + return StoreRefundOrder::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/6/12 + */ + public function search(array $where) + { + if(isset($where['is_trader']) && $where['is_trader'] !== ''){ + $query = StoreRefundOrder::hasWhere('merchant',function($query)use($where){ + $query->where('is_trader',$where['is_trader']); + }); + }else{ + $query = (StoreRefundOrder::getDB())->alias('StoreRefundOrder'); + } + $query->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('StoreRefundOrder.mer_id', $where['mer_id']); + })->when(isset($where['order_sn']) && $where['order_sn'] !== '', function ($query) use ($where) { + $ids = StoreOrder::where('order_sn','like','%'.$where['order_sn'].'%')->column('order_id'); + $query->where('order_id','in',$ids); + })->when(isset($where['refund_order_sn']) && $where['refund_order_sn'] !== '', function ($query) use ($where) { + $query->where('refund_order_sn', 'like', '%' . $where['refund_order_sn'] . '%'); + })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('StoreRefundOrder.status', $where['status']); + })->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->when(isset($where['id']) && $where['id'] !== '', function ($query) use ($where) { + $query->where('refund_order_id', $where['id']); + })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) { + $query->where('StoreRefundOrder.is_del', $where['is_del']); + })->when(isset($where['type']) && $where['type'] == 1, function ($query) { + $query->whereIn('StoreRefundOrder.status', [0, 1, 2]); + })->when(isset($where['type']) && $where['type'] == 2, function ($query) { + $query->whereIn('status', [-1, 3,-10]); + })->when(isset($where['refund_type']) && $where['refund_type'] !== '',function($query)use($where){ + $query->where('refund_type',$where['refund_type']); + })->when(isset($where['reconciliation_type']) && $where['reconciliation_type'] !== '' ,function($query)use($where){ + $query->when($where['reconciliation_type'], + function($query)use($where){$query->where('reconciliation_id','<>',0);}, + function($query)use($where){$query->where('reconciliation_id',0);} + ); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query,$where['date'],'StoreRefundOrder.create_time'); + })->when(isset($where['order_id']) && $where['order_id'] !== '', function ($query) use ($where) { + $query->where('order_id', $where['order_id']); + })->when(isset($where['delivery_id']) && $where['delivery_id'] !== '', function ($query) use ($where) { + $query->where('StoreRefundOrder.delivery_id', $where['delivery_id']); + })->order('StoreRefundOrder.create_time DESC'); + return $query; + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-12 + */ + public function getOne($id) + { + return $this->getModel()::where($this->getPk(),$id)->with([ + 'refundProduct.product', + 'user' => function($query){ + $query->field('uid,nickname,phone'); + }, + 'order.orderProduct' + ])->find(); + } + + /** + * @param $where + * @return bool + * @author Qinii + * @day 2020-06-12 + */ + public function getFieldExists($where) + { + return (($this->getModel()::getDB())->where($where)->count()) > 0; + } + + /** + * @param $uid + * @param $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/12 + */ + public function userDel($uid, $id) + { + return StoreRefundOrder::getDB()->where('uid', $uid)->where('refund_order_id', $id)->where('status', 3)->update(['is_del' => 1, 'status_time' => date('Y-m-d H:i:s')]); + } + + /** + * TODO超过期限退款申请 + * @param $time + * @return mixed + * @author Qinii + * @day 2020-06-13 + */ + public function getTimeOutIds($time) + { + return ($this->getModel()::getDB())->where('status_time','<=',$time) + ->where(function($query){ + $query->where(function($query){ + $query->where('refund_type',1)->where('status',0); + })->whereOr(function($query){ + $query->where('refund_type',2)->where('status',2); + }); + })->column('refund_order_id'); + } + + /** + * TODO + * @param $reconciliation_id + * @return mixed + * @author Qinii + * @day 2020-06-15 + */ + public function reconciliationUpdate($reconciliation_id) + { + return ($this->getModel()::getDB())->whereIn('reconciliation_id',$reconciliation_id)->update(['reconciliation_id' => 0]); + } + + public function refundPirceByOrder(array $orderIds) + { + return $this->getModel()::getDB()->whereIn('order_id',$orderIds)->where('status',3)->sum('refund_price'); + } + +} diff --git a/app/common/dao/store/order/StoreRefundProductDao.php b/app/common/dao/store/order/StoreRefundProductDao.php new file mode 100644 index 00000000..c3287853 --- /dev/null +++ b/app/common/dao/store/order/StoreRefundProductDao.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreRefundProduct; + +class StoreRefundProductDao extends BaseDao +{ + + protected function getModel(): string + { + return StoreRefundProduct::class; + } + + public function search(array $where) + { + $query = $this->getModel()::getDB() + ->when(isset($where['order_id']) && $where['order_id'] !== '',function($query)use($where){ + $query->where('order_id',$where['order_id']); + }); + + return $query->order('create_time'); + } + + public function userRefundPrice(array $ids) + { + $lst = $this->getModel()::getDB()->alias('A')->leftJoin('StoreRefundOrder B', 'A.refund_order_id = B.refund_order_id') + ->where('B.status', '>', -1) + ->whereIn('A.order_product_id', $ids)->group('A.order_product_id') + ->field('A.order_product_id, SUM(A.refund_price) as refund_price, SUM(A.platform_refund_price) as platform_refund_price, SUM(A.refund_postage) as refund_postage, SUM(A.refund_integral) as refund_integral') + ->select()->toArray(); + $data = []; + foreach ($lst as $item) { + $data[$item['order_product_id']] = $item; + } + return $data; + } +} diff --git a/app/common/dao/store/order/StoreRefundStatusDao.php b/app/common/dao/store/order/StoreRefundStatusDao.php new file mode 100644 index 00000000..66ee9598 --- /dev/null +++ b/app/common/dao/store/order/StoreRefundStatusDao.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\order; + + +use app\common\dao\BaseDao; +use app\common\model\store\order\StoreRefundStatus; + +class StoreRefundStatusDao extends BaseDao +{ + + protected function getModel(): string + { + return StoreRefundStatus::class; + } + + public function search($id) + { + return $query = StoreRefundStatus::getDB()->where('refund_order_id', $id); + } +} diff --git a/app/common/dao/store/parameter/ParameterDao.php b/app/common/dao/store/parameter/ParameterDao.php new file mode 100644 index 00000000..d7b88167 --- /dev/null +++ b/app/common/dao/store/parameter/ParameterDao.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\parameter; + +use app\common\dao\BaseDao; +use app\common\model\store\parameter\Parameter; + +class ParameterDao extends BaseDao +{ + + protected function getModel(): string + { + return Parameter::class; + } + + + public function search(array $where) + { + } + + +} diff --git a/app/common/dao/store/parameter/ParameterTemplateDao.php b/app/common/dao/store/parameter/ParameterTemplateDao.php new file mode 100644 index 00000000..b6c5db11 --- /dev/null +++ b/app/common/dao/store/parameter/ParameterTemplateDao.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\parameter; + +use app\common\dao\BaseDao; +use app\common\model\store\parameter\ParameterTemplate; + +class ParameterTemplateDao extends BaseDao +{ + + protected function getModel(): string + { + return ParameterTemplate::class; + } + +} diff --git a/app/common/dao/store/parameter/ParameterValueDao.php b/app/common/dao/store/parameter/ParameterValueDao.php new file mode 100644 index 00000000..2474b765 --- /dev/null +++ b/app/common/dao/store/parameter/ParameterValueDao.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\parameter; + +use app\common\dao\BaseDao; +use app\common\model\store\parameter\ParameterValue; + +class ParameterValueDao extends BaseDao +{ + + protected function getModel(): string + { + return ParameterValue::class; + } + + public function clear($id,$field) + { + $this->getModel()::getDb()->where($field, $id)->delete(); + } + + +} diff --git a/app/common/dao/store/product/ProductAssistDao.php b/app/common/dao/store/product/ProductAssistDao.php new file mode 100644 index 00000000..8540c2cc --- /dev/null +++ b/app/common/dao/store/product/ProductAssistDao.php @@ -0,0 +1,160 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductAssist; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\merchant\MerchantRepository; + +class ProductAssistDao extends BaseDao +{ + protected function getModel(): string + { + return ProductAssist::class; + } + + public function search(array $where) + { + $query = ProductAssist::hasWhere('product',function($query)use($where){ + $query->when(isset($where['product_show']) && $where['product_show'] !== '',function($query)use($where){ + $query->where('is_del',0)->where('mer_status',1)->where('product_type',3); + }) + ->where('status',1); + }); + $query->Join('StoreSpu U', 'Product.product_id = U.product_id')->where('U.product_type', 3); + $query->when(isset($where['product_assist_id']) && $where['product_assist_id'] !== '',function($query)use($where){ + $query->where('product_assist_id',$where['product_assist_id']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '',function($query)use($where){ + $query->whereLike('ProductAssist.store_name|ProductAssist.product_id',"%{$where['keyword']}%"); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('ProductAssist.mer_id',$where['mer_id']); + }) + ->when(isset($where['type']) && $where['type'] !== '',function($query)use($where){ + switch ($where['type']){ + case 0: //未开始 + $query->whereTime('start_time','>',time()); + break; + case 1: //进行中 + $query->whereTime('start_time','<=',time())->whereTime('end_time','>',time()) + ->where('ProductAssist.product_status',1)->where('ProductAssist.status',1)->where('ProductAssist.is_show',1); + break; + case 2: //已结束 + $query->where(function($query){ + $query->where('action_status',-1)->whereOr('end_time','<= TIME',time()); + }); + break; + } + }) + ->when(isset($where['status']) && $where['status'] !== '',function($query)use($where){ + $query->where('ProductAssist.status',$where['status']); + }) + ->when(isset($where['is_show']) && $where['is_show'] !== '',function($query)use($where){ + $query->where('ProductAssist.is_show',$where['is_show']); + }) + ->when(isset($where['mer_name']) && $where['mer_name'] !== '',function($query)use($where){ + $make = app()->make(MerchantRepository::class); + $mer_id = $make->search(['keyword' => $where['mer_name']])->column('mer_id'); + $query->whereIn('ProductAssist.mer_id',$mer_id); + }) + ->when(isset($where['product_status']) && $where['product_status'] !== '',function($query)use($where){ + if($where['product_status'] == -1){ + $query->where('ProductAssist.product_status','in',[-1,-2]); + }else{ + $query->where('ProductAssist.product_status',$where['product_status']); + } + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '',function($query)use($where){ + $make = app()->make(MerchantRepository::class); + $mer_id = $make->search(['is_trader' => $where['is_trader']])->column('mer_id'); + $query->whereIn('ProductAssist.mer_id',$mer_id); + }) + ->when(isset($where['us_status']) && $where['us_status'] !== '',function($query)use($where){ + if($where['us_status'] == 0) { + $query->where('ProductAssist.is_show',0)->where('ProductAssist.status',1)->where('ProductAssist.product_status',1); + } + if($where['us_status'] == 1) { + $query->where('ProductAssist.is_show',1)->where('ProductAssist.status',1)->where('ProductAssist.product_status',1); + } + if($where['us_status'] == -1) { + $query->where(function($query){ + $query->where('ProductAssist.status',0)->whereOr('ProductAssist.product_status','<>',1); + }); + } + }) + ->when(isset($where['mer_labels']) && $where['mer_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.mer_labels', "%,{$where['mer_labels']},%"); + }) + ->when(isset($where['sys_labels']) && $where['sys_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.sys_labels', "%,{$where['sys_labels']},%"); + }) + ->when(isset($where['star']),function($query)use($where){ + $query->when($where['star'] !== '', function ($query) use ($where) { + $query->where('U.star', $where['star']); + }); + $query->order('U.star DESC,U.rank DESC,ProductAssist.create_time DESC'); + }); + $query->where('ProductAssist.is_del',0); + return $query; + } + + /** + * TODO 移动端展示 条件 + * @return array + * @author Qinii + * @day 2020-10-19 + */ + public function assistShow() + { + return [ + 'product_show' => 1, + 'product_status' => 1, + 'status' => 1, + 'is_show' => 1, + 'type' => 1 + ]; + } + + /** + * TODO + * @author Qinii + * @day 1/27/21 + */ + public function valActiveStatus() + { + $query = $this->getModel()::getDB()->whereTime('end_time','<=',time())->where('action_status',1); + $id = $query->column($this->getPk()); + if($id) { + $this->getModel()::getDB()->where($this->getPk(),'in',$id)->update(['action_status' => -1]); + $where = [ + 'product_type' => 3, + 'activity_ids' => $id + ]; + app()->make(SpuRepository::class)->getSearch($where)->update(['status' => 0]); + } + } + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id', $merId)->update(['is_del' => 1]); + } +} + diff --git a/app/common/dao/store/product/ProductAssistSetDao.php b/app/common/dao/store/product/ProductAssistSetDao.php new file mode 100644 index 00000000..0520928a --- /dev/null +++ b/app/common/dao/store/product/ProductAssistSetDao.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductAssistSet; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\system\merchant\MerchantRepository; +use think\Exception; + +class ProductAssistSetDao extends BaseDao +{ + protected function getModel(): string + { + return ProductAssistSet::class; + } + + + public function incNum(int $type,int $id,int $inc = 1) + { + try{ + $query = $this->getModel()::where($this->getPk(),$id); + if($type == 1) $query->inc('share_num',$inc)->update(); + if($type == 2) $query->inc('view_num',$inc)->update(); + }catch (Exception $exception){ + + } + } + + public function userCount() + { + $count = $this->getModel()::getDB()->count("*"); + $res = $this->getModel()::getDB()->order('create_time DESC')->with(['user' => function($query){ + $query->field('uid,avatar avatar_img'); + }])->limit(10)->group('uid')->select()->toArray(); + + $list = []; + foreach ($res as $item){ + if(isset($item['user']['avatar_img']) && $item['user']['avatar_img']){ + $list[] = $item['user']; + } + } + return compact('count','list'); + } + + /** + * TODO 更新状态 + * @param int $id + * @author Qinii + * @day 2020-11-25 + */ + public function changStatus(int $id) + { + $this->getModel()::getDB()->where($this->getPk(),$id)->update(['status' => 20]); + } +} + diff --git a/app/common/dao/store/product/ProductAssistSkuDao.php b/app/common/dao/store/product/ProductAssistSkuDao.php new file mode 100644 index 00000000..c80fc21d --- /dev/null +++ b/app/common/dao/store/product/ProductAssistSkuDao.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductAssistSku; +use think\facade\Db; + +class ProductAssistSkuDao extends BaseDao +{ + protected function getModel(): string + { + return ProductAssistSku::class; + } + + public function clear($id) + { + $this->getModel()::getDB()->where('product_assist_id',$id)->delete(); + } + + public function descStock(int $product_assist_id, string $unique, int $desc) + { + return $this->getModel()::getDB()->where('product_assist_id', $product_assist_id)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock-' . $desc) + ]); + } + + public function incStock(int $product_assist_id, string $unique, int $desc) + { + return $this->getModel()::getDB()->where('product_assist_id', $product_assist_id)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock+' . $desc) + ]); + } +} + diff --git a/app/common/dao/store/product/ProductAssistUserDao.php b/app/common/dao/store/product/ProductAssistUserDao.php new file mode 100644 index 00000000..030390ca --- /dev/null +++ b/app/common/dao/store/product/ProductAssistUserDao.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductAssistUser; + +class ProductAssistUserDao extends BaseDao +{ + protected function getModel(): string + { + return ProductAssistUser::class; + } + + + public function userCount(int $limit = 3) + { + $count = $this->getModel()::getDB()->count("*"); + $list = $this->getModel()::getDB()->limit(3)->order('create_time DESC')->select(); + return compact('count','list'); + } +} + diff --git a/app/common/dao/store/product/ProductAttrDao.php b/app/common/dao/store/product/ProductAttrDao.php new file mode 100644 index 00000000..54c05cb7 --- /dev/null +++ b/app/common/dao/store/product/ProductAttrDao.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductAttr as model; + +class ProductAttrDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $productId + * @return mixed + */ + public function clearAttr(int $productId) + { + return ($this->getModel())::where('product_id',$productId)->delete(); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + * @return mixed + */ + public function insert(array $data) + { + return ($this->getModel()::getDB())->insertAll($data); + } + +} diff --git a/app/common/dao/store/product/ProductAttrValueDao.php b/app/common/dao/store/product/ProductAttrValueDao.php new file mode 100644 index 00000000..3b0b29a0 --- /dev/null +++ b/app/common/dao/store/product/ProductAttrValueDao.php @@ -0,0 +1,279 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductAttrValue as model; +use app\common\repositories\store\product\ProductRepository; +use think\db\exception\DbException; +use think\facade\Db; + +/** + * Class ProductAttrValueDao + * @package app\common\dao\store\product + * @author xaboy + * @day 2020/6/9 + */ +class ProductAttrValueDao extends BaseDao +{ + /** + * @return string + * @author xaboy + * @day 2020/6/9 + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $productId + * @return mixed + */ + public function clearAttr(int $productId) + { + return ($this->getModel())::where('product_id', $productId)->delete(); + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return mixed + */ + public function getFieldColumnt($key, $value, $field, $except = null) + { + return ($this->getModel()::getDB())->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where($key, $value)->column($field); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $key + * @param $value + * @param $field + * @param null $except + * @return mixed + */ + public function getFieldSum($key, $value, $field, $except = null) + { + return ($this->getModel()::getDB())->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where($key, $value)->sum($field); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param array $data + * @return mixed + */ + public function insert(array $data) + { + return ($this->getModel()::getDB())->insertAll($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int|null $merId + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists(?int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->where($field, $value)->count() > 0; + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/6/9 + */ + public function getSku($id) + { + return ($this->getModel())::where('product_id', $id); + } + + /** + * @param int|null $merId + * @param $field + * @param $value + * @param null $except + * @return mixed + * @author xaboy + * @day 2020/6/9 + */ + public function getFieldExists(?int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->where($field, $value); + } + + /** + * @param int $productId + * @param string $unique + * @param int $desc + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function descStock(int $productId, string $unique, int $desc) + { + return model::getDB()->where('product_id', $productId)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock-' . $desc), + 'sales' => Db::raw('sales+' . $desc) + ]); + } + + /** + * @param int $productId + * @param string $sku + * @param int $desc + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function descSkuStock(int $productId, string $sku, int $desc) + { + return model::getDB()->where('product_id', $productId)->where('sku', $sku)->update([ + 'stock' => Db::raw('stock-' . $desc), + 'sales' => Db::raw('sales+' . $desc) + ]); + } + + /** + * @param int $productId + * @param string $unique + * @param int $inc + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function incStock(int $productId, string $unique, int $inc) + { + model::getDB()->where('product_id', $productId)->where('unique', $unique)->inc('stock', $inc)->update(); + model::getDB()->where('product_id', $productId)->where('unique', $unique)->where('sales', '>=', $inc)->dec('sales', $inc)->update(); + } + + /** + * @param int $productId + * @param string $sku + * @param int $inc + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function incSkuStock(int $productId, string $sku, int $inc) + { + model::getDB()->where('product_id', $productId)->where('sku', $sku)->inc('stock', $inc)->update(); + model::getDB()->where('product_id', $productId)->where('sku', $sku)->where('sales', '>', $inc)->dec('sales', $inc)->update(); + } + + /** + * @param int $productId + * @param string $unique + * @return bool + * @author xaboy + * @day 2020/6/9 + */ + public function attrExists(int $productId, string $unique): bool + { + return model::getDB()->where('product_id', $productId)->where('unique', $unique)->count() > 0; + } + + /** + * @param int $productId + * @param string $sku + * @return bool + * @author xaboy + * @day 2020/6/9 + */ + public function skuExists(int $productId, string $sku): bool + { + return model::getDB()->where('product_id', $productId)->where('sku', $sku)->count() > 0; + } + + /** + * TODO 商品佣金是否大于设置佣金比例 + * @param $productId + * @return bool + * @author Qinii + * @day 2020-06-25 + */ + public function checkExtensionById($productId) + { + $extension_one_rate = systemConfig('extension_one_rate'); + $extension_two_rate = systemConfig('extension_two_rate'); + + $count = ($this->getModel()::getDb())->where(function($query)use($productId,$extension_one_rate){ + $query->where('product_id',$productId)->whereRaw('price * '.$extension_one_rate.' > extension_one'); + })->whereOr(function($query)use($productId,$extension_two_rate){ + $query->where('product_id',$productId)->whereRaw('price * '.$extension_two_rate.' > extension_two'); + })->count(); + return $count ? false : true; + } + + public function search(array $where) + { + $query = ($this->getModel()::getDb()) + ->when(isset($where['product_id']) && $where['product_id'] !== '',function($query)use($where){ + $query->where('product_id',$where['product_id']); + }) + ->when(isset($where['sku']) && $where['sku'] !== '',function($query)use($where){ + $query->where('sku',$where['sku']); + }) + ->when(isset($where['unique']) && $where['unique'] !== '',function($query)use($where){ + $query->where('unique',$where['unique']); + }); + return $query; + } + + public function updates(array $ids, array $data) + { + $this->getModel()::getDb()->whereIn('product_id',$ids)->update($data); + } + + public function updatesExtension(array $ids, array $data) + { + app()->make(ProductRepository::class)->updates($ids,['extension_type' => 1]); + $query = $this->getModel()::getDb()->where('product_id','in',$ids); + $query->chunk(100, function($list) use($data){ + foreach ($list as $item) { + $arr['extension_one'] = bcmul($item->price,$data['extension_one'],2); + $arr['extension_two'] = bcmul($item->price,$data['extension_two'],2); + $this->getModel()::getDb()->where('unique',$item->unique)->update($arr); + } + },'product_id'); + } +} diff --git a/app/common/dao/store/product/ProductCateDao.php b/app/common/dao/store/product/ProductCateDao.php new file mode 100644 index 00000000..c343477a --- /dev/null +++ b/app/common/dao/store/product/ProductCateDao.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductCate as model; + +class ProductCateDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $productId + * @return mixed + */ + public function clearAttr(int $productId) + { + return ($this->getModel())::where('product_id',$productId)->delete(); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + * @return mixed + */ + public function insert(array $data) + { + return ($this->getModel()::getDB())->insertAll($data); + } + + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id',$merId)->update(['is_del' => 1]); + } +} diff --git a/app/common/dao/store/product/ProductContentDao.php b/app/common/dao/store/product/ProductContentDao.php new file mode 100644 index 00000000..a4309efc --- /dev/null +++ b/app/common/dao/store/product/ProductContentDao.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductContent as model; + +class ProductContentDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $productId + * @return mixed + */ + public function clearAttr(int $productId, ?int $type) + { + $query = ($this->getModel())::where('product_id', $productId); + if (!is_null($type)) $query->where('type', $type); + return $query->delete(); + } + +} diff --git a/app/common/dao/store/product/ProductCopyDao.php b/app/common/dao/store/product/ProductCopyDao.php new file mode 100644 index 00000000..07249361 --- /dev/null +++ b/app/common/dao/store/product/ProductCopyDao.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductCopy as model; + +class ProductCopyDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + public function search(array $where) + { + return $this->getModel()::getDB() + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('mer_id',$where['mer_id']); + }) + ->when(isset($where['type']) && $where['type'] !== '',function($query)use($where){ + if($where['type'] == 'copy'){ + $query->where('type','in',['taobao','jd','copy']); + } else { + $query->where('type',$where['type']); + } + }) + ->order('create_time DESC'); + } + + public function get2() + { + return $data = model::where('store_product_copy_id','>',398) + ->where('store_product_copy_id','<',467)->field('info')->select(); + + } +} diff --git a/app/common/dao/store/product/ProductDao.php b/app/common/dao/store/product/ProductDao.php new file mode 100644 index 00000000..a90a7233 --- /dev/null +++ b/app/common/dao/store/product/ProductDao.php @@ -0,0 +1,627 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\Product as model; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\StoreCategoryRepository; +use think\db\BaseQuery; +use think\db\exception\DbException; +use think\facade\Db; + +class ProductDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $id + * @param array $data + */ + public function createAttr(int $id, array $data) + { + ($this->getModel()::withTrashed()->find($id))->attr()->saveAll($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $id + * @param array $data + */ + public function createAttrValue(int $id, array $data) + { + ($this->getModel()::withTrashed()->find($id))->attrValue()->saveAll($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $id + * @param array $data + */ + public function createContent(int $id, array $data) + { + ($this->getModel()::withTrashed()->find($id))->content()->save($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists(?int $merId, $field, $value, $except = null) + { + return model::withTrashed()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->where($field, $value)->count() > 0; + } + + public function apiFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->when($merId, function ($query, $merId) { + $query->where('mer_id', $merId); + })->where(['status' => 1])->where($field, $value)->count() > 0; + } + + /** + * @param int $merId + * @param int $productId + * @return bool + * @author Qinii + */ + public function getDeleteExists(int $merId, int $productId) + { + return ($this->getModel())::onlyTrashed()->where('mer_id', $merId)->where($this->getPk(), $productId)->count() > 0; + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param array $where + * @return mixed + */ + public function search(?int $merId, array $where) + { + $keyArray = $whereArr = []; + unset($where['type']); + $out = ['soft','us_status','mer_labels','sys_labels','order','hot_type']; + foreach ($where as $key => $item) { + if ($item !== '' && !in_array($key,$out)) { + $keyArray[] = $key; + $whereArr[$key] = $item; + } + } + $query = isset($where['soft']) ? model::onlyTrashed()->alias('Product') : model::alias('Product'); + if (isset($where['is_trader']) && $where['is_trader'] !== '') { + $query->hasWhere('merchant', function ($query) use ($where) { + $query->where('is_trader', $where['is_trader']); + }); + } + $query->withSearch($keyArray, $whereArr) + ->Join('StoreSpu U', 'Product.product_id = U.product_id')->where('U.product_type', $where['product_type'] ?? 0) + ->when(($merId !== null), function ($query) use ($merId) { + $query->where('Product.mer_id', $merId); + }) + ->when(isset($where['hot_type']) && $where['hot_type'] !== '', function ($query) use ($where) { + if ($where['hot_type'] == 'new') + $query->where('is_new', 1); + else if ($where['hot_type'] == 'hot') + $query->where('is_hot', 1); + else if ($where['hot_type'] == 'best') + $query->where('is_best', 1); + else if ($where['hot_type'] == 'good') + $query->where('is_benefit', 1); + }) + ->when(isset($where['us_status']) && $where['us_status'] !== '', function ($query) use ($where) { + if ($where['us_status'] == 0) { + $query->where('Product.is_show', 0)->where('Product.is_used', 1)->where('Product.status',1); + } + if ($where['us_status'] == 1) { + $query->where('Product.is_show', 1)->where('Product.is_used', 1)->where('Product.status',1); + } + if ($where['us_status'] == -1) { + $query->where(function($query){ + $query->where('Product.is_used',0)->whereOr('Product.status','<>',1); + }); + } + }) + ->when(isset($where['mer_labels']) && $where['mer_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.mer_labels', "%,{$where['mer_labels']},%"); + }) + ->when(isset($where['sys_labels']) && $where['sys_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.sys_labels', "%,{$where['sys_labels']},%"); + }) + ->when(isset($where['svip_price_type']) && $where['svip_price_type'] !== '', function ($query) use ($where) { + $query->where('Product.svip_price_type',$where['svip_price_type']); + }) + ->when(isset($where['order']), function ($query) use ($where, $merId) { + if(in_array($where['order'], ['is_new', 'price_asc', 'price_desc', 'rate', 'sales']) ){ + if ($where['order'] == 'price_asc') { + $where['order'] = 'price ASC'; + } else if ($where['order'] == 'price_desc') { + $where['order'] = 'price DESC'; + } else { + $where['order'] = $where['order'] . ' DESC'; + } + $query->order($where['order'] . ',rank DESC ,create_time DESC '); + } else if($where['order'] !== ''){ + $query->order('U.'.$where['order'].' DESC,U.create_time DESC'); + } else { + $query->order('U.create_time DESC'); + } + }) + ->when(isset($where['star']),function($query)use($where){ + $query->when($where['star'] !== '', function ($query) use ($where) { + $query->where('U.star', $where['star']); + }); + $query->order('U.star DESC,U.rank DESC,Product.create_time DESC'); + }); + return $query; + } + + /** + * TODO + * @param array $where + * @return BaseQuery + * @author Qinii + * @day 2020-08-04 + */ + public function seckillSearch(array $where) + { + $query = model::hasWhere('seckillActive', function ($query) use ($where) { + $query->where('status', 1); + $query->whereTime('start_day', '<=', $where['day'])->whereTime('end_day', '>=', $where['day']); + $query->where('start_time', '<=', $where['start_time']) + ->where('end_time', '>', $where['start_time']) + ->where('end_time', '<=', $where['end_time']); + }); + $query->where([ + 'Product.is_show' => 1, + 'Product.status' => 1, + 'Product.is_used' => 1, + 'Product.mer_status' => 1, + 'Product.product_type' => 1, + 'Product.is_gift_bag' => 0, + ]) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('Product.mer_id',$where['mer_id']); + }) + ->when(isset($where['star']),function($query)use($where){ + $query->Join('StoreSpu U', 'Product.product_id = U.product_id')->where('U.product_type', 1); + $query->when($where['star'] !== '', function ($query) use ($where) { + $query->where('U.star', $where['star']); + }); + $query->order('U.star DESC,U.rank DESC'); + }); + return $query; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @param bool $soft + * @return int|mixed + */ + public function delete(int $id, $soft = false) + { + if ($soft) { + (($this->getModel())::onlyTrashed()->find($id))->force()->delete(); + } else { + $this->getModel()::where($this->getPk(), $id)->update(['is_del' => 1]); + } + app()->make(SpuRepository::class)->getSearch(['product_id' => $id])->update(['is_del' => 1, 'status' => 0]); + event('product.delete',compact('id')); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-03 + */ + public function restore($id) + { + $res = ($this->getModel())::onlyTrashed()->find($id); + app()->make(SpuRepository::class)->delProduct($id, 0); + return $res->restore(); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @param array $status + * @return mixed + */ + public function switchStatus(int $id, array $status) + { + return ($this->getModel()::getDB())->where($this->getPk(), $id)->update($status); + } + + /** + * @param int $merId + * @param array $productIds + * @return array + * @author xaboy + * @day 2020/5/26 + */ + public function productIdByImage(int $merId, array $productIds) + { + return model::getDB()->where('mer_id', $merId)->whereIn('product_id', $productIds)->column('product_id,image'); + } + + /** + * @param array $ids + * @return array + * @author xaboy + * @day 2020/5/30 + */ + public function intersectionKey(array $ids): array + { + return model::getDB()->whereIn('product_id', $ids)->column('product_id'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @return mixed + */ + public function productIdByMerId($id) + { + return model::getDB()->where('product_id', $id)->value('mer_id'); + } + + + /** + * @param int $productId + * @param int $desc + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function descStock(int $productId, int $desc) + { + return model::getDB()->where('product_id', $productId)->update([ + 'stock' => Db::raw('stock-' . $desc), + 'sales' => Db::raw('sales+' . $desc) + ]); + } + + /** + * @param int $productId + * @param int $inc + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/8 + */ + public function incStock(int $productId, int $inc) + { + model::getDB()->where('product_id', $productId)->inc('stock', $inc)->update(); + model::getDB()->where('product_id', $productId)->where('sales', '>=', $inc)->dec('sales', $inc)->update(); + } + + public function descIntegral(int $productId, $integral_total, $integral_price_total) + { + return model::getDB()->where('product_id', $productId)->update([ + 'integral_total' => Db::raw('integral_total-' . $integral_total), + 'integral_price_total' => Db::raw('integral_price_total-' . $integral_price_total), + ]); + } + + public function incIntegral(int $productId, $integral_total, $integral_price_total) + { + model::getDB()->where('product_id', $productId)->inc('integral_total', $integral_total)->inc('integral_price_total', $integral_price_total)->update(); + } + + public function visitProductGroup($date, $merId = null, $limit = 7) + { + return model::getDB()->alias('A')->leftJoin('UserRelation B', 'A.product_id = B.type_id') + ->field(Db::raw('count(B.type_id) as total,A.product_id,A.store_name,A.image')) + ->when($date, function ($query, $date) { + getModelTime($query, $date, 'B.create_time'); + })->when($merId, function ($query, $merId) { + $query->where('A.mer_id', $merId); + })->where('B.type', 1)->group('A.product_id')->limit($limit)->order('total DESC')->select(); + } + + public function cartProductGroup($date, $merId = null, $limit = 7) + { + return model::getDB()->alias('A')->leftJoin('StoreCart B', 'A.product_id = B.product_id') + ->field(Db::raw('sum(B.cart_num) as total,A.product_id,A.store_name,A.image')) + ->when($date, function ($query, $date) { + getModelTime($query, $date, 'B.create_time'); + })->when($merId, function ($query, $merId) { + $query->where('A.mer_id', $merId); + })->where('B.product_type', 0)->where('B.is_pay', 0)->where('B.is_del', 0) + ->where('B.is_new', 0)->where('B.is_fail', 0)->group('A.product_id')->limit($limit)->order('total DESC')->select(); + } + + public function changeMerchantProduct($merId, $data) + { + ($this->getModel()::getDB())->where('mer_id', $merId)->update($data); + } + + /** + * TODO + * @param int $productId + * @author Qinii + * @day 2020-07-09 + */ + public function incCareCount(int $productId) + { + ($this->getModel()::getDB())->where($this->getPk(), $productId)->inc('care_count', 1)->update(); + } + + /** + * TODO + * @param int $productId + * @author Qinii + * @day 2020-07-09 + */ + public function decCareCount(array $productId) + { + ($this->getModel()::getDB())->whereIn($this->getPk(), $productId)->where('care_count', '>', 0)->dec('care_count', 1)->update(); + } + + + /** + * TODO api展示的商品条件 + * @return array + * @author Qinii + * @day 2020-08-18 + */ + public function productShow() + { + return [ + 'is_show' => 1, + 'status' => 1, + 'is_used' => 1, + 'product_type' => 0, + 'mer_status' => 1, + 'is_gift_bag' => 0, + ]; + } + + /** + * TODO api展示的礼包商品条件 + * @return array + * @author Qinii + * @day 2020-08-18 + */ + public function bagShow() + { + return [ + 'is_show' => 1, + 'status' => 1, + 'is_used' => 1, + 'mer_status' => 1, + 'product_type' => 0, + 'is_gift_bag' => 1, + ]; + } + + /** + * TODO api展示的秒杀商品条件 + * @return array + * @author Qinii + * @day 2020-08-18 + */ + public function seckillShow() + { + return [ + 'is_show' => 1, + 'status' => 1, + 'is_used' => 1, + 'mer_status' => 1, + 'product_type' => 1, + 'is_gift_bag' => 0, + ]; + } + + public function getProductTypeById(int $productId, ?int $exsistType) + { + $product_type = $this->getModel()::getDB() + ->when($exsistType, function ($query) use ($exsistType) { + $query->where('product_type', $exsistType); + }) + ->where($this->getPk(), $productId)->where('is_del', 0)->value('product_type'); + return $product_type == 0 ? true : false; + } + + public function getFailProduct(int $productId) + { + return $this->getModel()::withTrashed()->field('product_id,image,store_name,is_show,status,is_del,unit_name,price,mer_status,is_used')->find($productId); + } + + public function geTrashedtProduct(int $id) + { + return model::withTrashed()->where($this->getPk(),$id); + } + + + /** + * TODO 获取各种有效时间内的活动 + * @param int $productType + * @return array + * @author Qinii + * @day 2/1/21 + */ + public function activitSearch(int $productType) + { + $query = model::getDB()->alias('P') + ->where('P.is_del', 0) + ->where('P.mer_status', 1) + ->where('P.product_type', $productType); + switch ($productType) { + case 0: + // $query->where('P.is_show',1) + // ->where('P.is_used',1) + // ->field('product_id,product_type,mer_id,store_name,keyword,price,rank,sort,image,status,temp_id'); + break; + case 1: + $query->join('StoreSeckillActive S', 'S.product_id = P.product_id') + ->field('P.*,S.status,S.seckill_active_id,S.end_time'); + break; + case 2: + $query->join('StoreProductPresell R', 'R.product_id = P.product_id') + ->where('R.is_del',0) + ->field('P.*,R.product_presell_id,R.store_name,R.price,R.status,R.is_show,R.product_status,R.action_status'); + break; + case 3: + $query->join('StoreProductAssist A', 'A.product_id = P.product_id') + ->where('A.is_del',0) + ->field('P.*,A.product_assist_id,A.store_name,A.status,A.is_show,A.product_status,A.action_status'); + break; + case 4: + $query->join('StoreProductGroup G', 'G.product_id = P.product_id') + ->where('G.is_del',0) + ->field('P.*,G.product_group_id,G.price,G.status,G.is_show,G.product_status,G.action_status'); + break; + default: + break; + } + $data = $query->select()->toArray(); + $ret = $this->commandChangeProductStatus($data); + return $ret; + } + + + public function commandChangeProductStatus($data) + { + $ret = []; + + foreach ($data as $item) { + $status = 0; + switch ($item['product_type']) { + case 0: + if ($item['is_show'] && $item['is_used']) $status = 1; + $ret[] = [ + 'activity_id' => 0, + 'product_id' => $item['product_id'], + 'mer_id' => $item['mer_id'], + 'keyword' => $item['keyword'], + 'price' => $item['price'], + 'rank' => $item['rank'], + 'sort' => $item['sort'], + 'image' => $item['image'], + 'status' => $status, + 'temp_id' => $item['temp_id'], + 'store_name' => $item['store_name'], + 'product_type' => $item['product_type'], + ]; + break; + case 1: + if ($item['is_show'] && $item['is_used'] && $item['status'] && ($item['end_time'] > time())) $status = 1; + $ret[] = [ + 'activity_id' => $item['seckill_active_id'], + 'product_id' => $item['product_id'], + 'mer_id' => $item['mer_id'], + 'keyword' => $item['keyword'], + 'price' => $item['price'], + 'rank' => $item['rank'], + 'sort' => $item['sort'], + 'image' => $item['image'], + 'status' => $status, + 'temp_id' => $item['temp_id'], + 'store_name' => $item['store_name'], + 'product_type' => $item['product_type'], + ]; + break; + case 2: + if ($item['is_show'] && $item['action_status'] && $item['status'] && $item['product_status']) $status = 1; + $ret[] = [ + 'activity_id' => $item['product_presell_id'], + 'product_id' => $item['product_id'], + 'mer_id' => $item['mer_id'], + 'keyword' => $item['keyword'], + 'price' => $item['price'], + 'rank' => $item['rank'], + 'sort' => $item['sort'], + 'image' => $item['image'], + 'status' => $status, + 'temp_id' => $item['temp_id'], + 'store_name' => $item['store_name'], + 'product_type' => $item['product_type'], + ]; + break; + case 3: + if ($item['is_show'] && $item['action_status'] && $item['status'] && $item['product_status']) $status = 1; + $ret[] = [ + 'activity_id' => $item['product_assist_id'], + 'product_id' => $item['product_id'], + 'mer_id' => $item['mer_id'], + 'keyword' => $item['keyword'], + 'price' => $item['price'], + 'rank' => $item['rank'], + 'sort' => $item['sort'], + 'image' => $item['image'], + 'status' => $status, + 'temp_id' => $item['temp_id'], + 'store_name' => $item['store_name'], + 'product_type' => $item['product_type'], + ]; + break; + case 4: + if ($item['is_show'] && $item['action_status'] && $item['status'] && $item['product_status']) $status = 1; + $ret[] = [ + 'activity_id' => $item['product_group_id'], + 'product_id' => $item['product_id'], + 'mer_id' => $item['mer_id'], + 'keyword' => $item['keyword'], + 'price' => $item['price'], + 'rank' => $item['rank'], + 'sort' => $item['sort'], + 'image' => $item['image'], + 'status' => $status, + 'temp_id' => $item['temp_id'], + 'store_name' => $item['store_name'], + 'product_type' => $item['product_type'], + ]; + break; + } + } + return $ret; + } + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id', $merId)->update(['is_del' => 1]); + } +} diff --git a/app/common/dao/store/product/ProductGroupBuyingDao.php b/app/common/dao/store/product/ProductGroupBuyingDao.php new file mode 100644 index 00000000..2ff74d48 --- /dev/null +++ b/app/common/dao/store/product/ProductGroupBuyingDao.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductGroupBuying; + +class ProductGroupBuyingDao extends BaseDao +{ + public function getModel(): string + { + return ProductGroupBuying::class; + } + + + public function search($where) + { + $query = ProductGroupBuying::getDb()->alias('B')->join('StoreProductGroup G','B.product_group_id = G.product_group_id'); + + $query + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function($query)use($where){ + $query->where('B.mer_id',$where['mer_id']); + }) + ->when(isset($where['date']) && $where['date'] , function($query)use($where){ + getModelTime($query,$where['date'],'B.create_time'); + }) + ->when(isset($where['status']) && $where['status'] !== '', function($query)use($where){ + $query->where('B.status',$where['status']); + }) + ->when(isset($where['user_name']) && $where['user_name'] !== '', function($query)use($where){ + $query->join('StoreProductGroupUser U','U.group_buying_id = B.group_buying_id')->where('is_initiator',1) + ->whereLike('uid|nickname',"%{$where['user_name']}%"); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '' , function($query)use($where){ + $query->join('StoreProduct P','G.product_id = P.product_id') + ->whereLike('B.group_buying_id|P.product_id|store_name',"%{$where['keyword']}%"); + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '', function($query)use($where){ + $query->join('Merchant M','M.mer_id = B.mer_id')->where('is_trader',$where['is_trader']); + }) + ; + + return $query; + } +} diff --git a/app/common/dao/store/product/ProductGroupDao.php b/app/common/dao/store/product/ProductGroupDao.php new file mode 100644 index 00000000..e0b25a56 --- /dev/null +++ b/app/common/dao/store/product/ProductGroupDao.php @@ -0,0 +1,162 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductGroup; +use app\common\repositories\store\product\SpuRepository; + +class ProductGroupDao extends BaseDao +{ + public function getModel(): string + { + return ProductGroup::class; + } + + public function search($where) + { + $query = ProductGroup::hasWhere('product',function($query)use($where){ + $query->where('status',1); + $query->when(isset($where['keyword']) && $where['keyword'] !== '',function($query)use($where){ + $query->whereLike('store_name',"%{$where['keyword']}%"); + }); + }); + $query->when(isset($where['is_show']) && $where['is_show'] !== '',function($query)use($where){ + $query->where('ProductGroup.is_show',$where['is_show']); + }) + ->when(isset($where['product_status']) && $where['product_status'] !== '',function($query)use($where){ + if($where['product_status'] == -1){ + $query->where('ProductGroup.product_status','in',[-1,-2]); + }else{ + $query->where('ProductGroup.product_status',$where['product_status']); + } + }) + ->when(isset($where['status']) && $where['status'] !== '',function($query)use($where){ + $query->where('ProductGroup.status',$where['status']); + }) + ->when(isset($where['end_time']) && $where['end_time'] !== '',function($query)use($where){ + $query->whereTime('ProductGroup.end_time','>',$where['end_time']); + }) + ->when(isset($where['active_type']) && $where['active_type'] !== '',function($query)use($where){ + $query->where('ProductGroup.action_status',$where['active_type']); + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '',function($query)use($where){ + $query->join('Merchant M','M.mer_id = ProductGroup.mer_id')->where('is_trader',$where['is_trader']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('ProductGroup.mer_id',$where['mer_id']); + }) + ->when(isset($where['product_group_id']) && $where['product_group_id'] !== '',function($query)use($where){ + $query->where('ProductGroup.product_group_id',$where['product_group_id']); + }) + ->when(isset($where['store_category_id']) && $where['store_category_id'] !== '',function($query)use($where){ + $query->join('StoreCategory C','Product.cate_id = C.store_category_id') + ->whereLike('path',"/{$where['store_category_id']}/%"); + }) + ->when(isset($where['us_status']) && $where['us_status'] !== '',function($query)use($where){ + if($where['us_status'] == 0) { + $query->where('ProductGroup.is_show',0)->where('ProductGroup.status',1)->where('ProductGroup.product_status',1); + } + if($where['us_status'] == 1) { + $query->where('ProductGroup.is_show',1)->where('ProductGroup.status',1)->where('ProductGroup.product_status',1); + } + if($where['us_status'] == -1) { + $query->where(function($query){ + $query->where('ProductGroup.status',0)->whereOr('ProductGroup.product_status','<>',1); + }); + } + }); + + $query->join('StoreSpu U','ProductGroup.product_group_id = U.activity_id')->where('U.product_type',4); + + $query->when(isset($where['star']) && $where['star'] !== '',function($query)use($where){ + $query->where('U.star',$where['star']); + }) + ->when(isset($where['level']) && $where['level'] !== '',function($query)use($where) { + $query->where('U.star',$where['level']); + }) + ->when(isset($where['mer_labels']) && $where['mer_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.mer_labels', "%,{$where['mer_labels']},%"); + }) + ->when(isset($where['sys_labels']) && $where['sys_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.sys_labels', "%,{$where['sys_labels']},%"); + }); + if(isset($where['order'])) { + switch ($where['order']) { + case 'sort': + $order = 'U.sort DESC'; + break; + case 'rank': + $order = 'U.rank DESC'; + break; + case 'star': + $order = 'U.star DESC,U.rank DESC'; + break; + default: + $order = 'U.star DESC,U.rank DESC,U.sort DES'; + break; + } + $query->order($order.',ProductGroup.create_time DESC'); + } + + return $query->where('ProductGroup.is_del',0); + } + + public function actionShow() + { + return [ + 'is_show' => 1, + 'action_status' => 1, + 'product_status' => 1, + 'status' => 1, + 'end_time' => time() + ]; + } + + public function category() + { + $query = ProductGroup::alias('G')->join('StoreProduct P','G.product_id = P.product_id') + ->join('StoreCategory C','P.cate_id = C.store_category_id'); + $query->where('G.is_show',1)->where('G.action_status',1)->where('G.product_status',1); + $query->group('G.product_id'); + return $query->column('path'); + } + + /** + * TODO + * @author Qinii + * @day 1/27/21 + */ + public function valActiveStatus() + { + $query = $this->getModel()::getDB()->whereTime('end_time','<=',time())->where('action_status',1); + $id = $query->column($this->getPk()); + if($id) { + $this->getModel()::getDB()->where($this->getPk(),'in',$id)->update(['action_status' => -1]); + $where = [ + 'product_type' => 4, + 'activity_ids' => $id + ]; + app()->make(SpuRepository::class)->getSearch($where)->update(['status' => 0]); + } + } + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id', $merId)->update(['is_del' => 1]); + } +} diff --git a/app/common/dao/store/product/ProductGroupSkuDao.php b/app/common/dao/store/product/ProductGroupSkuDao.php new file mode 100644 index 00000000..c0e0ca60 --- /dev/null +++ b/app/common/dao/store/product/ProductGroupSkuDao.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductGroupSku; + +class ProductGroupSkuDao extends BaseDao +{ + public function getModel(): string + { + return ProductGroupSku::class; + } + + public function clear($id) + { + return $this->getModel()::getDB()->where('product_group_id', $id)->delete(); + } + + public function incStock($product_group_id, $unique, $inc) + { + return ProductGroupSku::getDB()->where('product_group_id', $product_group_id)->where('unique', $unique)->inc('stock', $inc)->update(); + } + + public function descStock($product_group_id, $unique, $inc) + { + return ProductGroupSku::getDB()->where('product_group_id', $product_group_id)->where('unique', $unique)->dec('stock', $inc)->update(); + } + +} diff --git a/app/common/dao/store/product/ProductGroupUserDao.php b/app/common/dao/store/product/ProductGroupUserDao.php new file mode 100644 index 00000000..7a1b81b8 --- /dev/null +++ b/app/common/dao/store/product/ProductGroupUserDao.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductGroupUser; + +class ProductGroupUserDao extends BaseDao +{ + public function getModel(): string + { + return ProductGroupUser::class; + } + + public function successUser($id) + { + $query = ProductGroupUser::hasWhere('groupBuying',function($query){ + $query->where('status',10); + }); + $query->where('ProductGroupUser.product_group_id',$id); + return $query->setOption('field',[])->field('nickname,avatar')->select(); + } + + public function updateStatus(int $groupId) + { + return $this->getModel()::getDb()->where('group_buying_id',$groupId)->update(['status' => 10]); + } + + public function groupOrderIds($productGroupId) + { + return ProductGroupUser::getDB()->where('group_buying_id', $productGroupId)->where('order_id', '>', 0)->select(); + } +} diff --git a/app/common/dao/store/product/ProductLabelDao.php b/app/common/dao/store/product/ProductLabelDao.php new file mode 100644 index 00000000..f163d2cc --- /dev/null +++ b/app/common/dao/store/product/ProductLabelDao.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductLabel; + +class ProductLabelDao extends BaseDao +{ + protected function getModel(): string + { + return ProductLabel::class; + } +} diff --git a/app/common/dao/store/product/ProductPresellDao.php b/app/common/dao/store/product/ProductPresellDao.php new file mode 100644 index 00000000..485152c5 --- /dev/null +++ b/app/common/dao/store/product/ProductPresellDao.php @@ -0,0 +1,203 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductPresell; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\merchant\MerchantRepository; + +class ProductPresellDao extends BaseDao +{ + protected function getModel(): string + { + return ProductPresell::class; + } + + public function search(array $where) + { + $query = ProductPresell::hasWhere('product',function($query)use($where){ + $query->when(isset($where['product_show']) && $where['product_show'] !== '',function($query)use($where){ + $query->where('is_del',0)->where('mer_status',1); + }) + ->when(isset($where['product_type']) && $where['product_type'] !== '',function($query)use($where){ + $query->where('product_type',2); + }) + ->where('status',1); + }); + $query->Join('StoreSpu U', 'ProductPresell.product_presell_id = U.activity_id')->where('U.product_type', 2); + $query->when(isset($where['product_presell_id']) && $where['product_presell_id'] !== '',function($query)use($where){ + $query->where('product_presell_id',$where['product_presell_id']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('ProductPresell.mer_id',$where['mer_id']); + }) + ->when(isset($where['action_status']) && $where['action_status'] !== '',function($query)use($where){ + $query->where('ProductPresell.action_status',$where['action_status']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '',function($query)use($where){ + $query->whereLike('ProductPresell.store_name|ProductPresell.product_id|ProductPresell.product_presell_id',"%{$where['keyword']}%"); + }) + ->when(isset($where['product_status']) && $where['product_status'] !== '',function($query)use($where){ + if($where['product_status'] == -1){ + $query->where('ProductPresell.product_status','in',[-1,-2]); + }else{ + $query->where('ProductPresell.product_status',$where['product_status']); + } + }) + ->when(isset($where['presell_type']) && $where['presell_type'] !== '',function($query)use($where){ + $query->where('ProductPresell.presell_type',$where['presell_type']); + }) + ->when(isset($where['type']) && $where['type'] !== '',function($query)use($where){ + switch ($where['type']){ + case 0: //未开始 + if(isset($where['api_type'])){ + $query->where('product_status',1); + } + $query->where('action_status',1); + $query->where(function($query){ + $query->whereTime('start_time','>',time())->whereOr(function ($query){ + $query->whereTime('start_time','<',time())->whereTime('end_time','>',time())->where(function($query){ + $query->where('ProductPresell.product_status','<>',1)->whereOr('ProductPresell.is_show','<>',1)->whereOr('ProductPresell.status','<>',1); + }); + }); + }); + break; + case 1: //进行中 + $query->where('action_status',1) + ->whereTime('start_time','<=',time()) + ->whereTime('end_time','>',time()) + ->where('product_status',1) + ->where('ProductPresell.status',1) + ->where('ProductPresell.is_show',1); + break; + case 2: //已结束 + $query->where(function($query){ + $query->where('action_status',-1)->whereOr('end_time','<= TIME',time()); + }); + break; + case 3: //已关闭 + $query->where(function($query){ + $query->where(function($query){ + $query->where('ProductPresell.presell_type',1)->whereTime('end_time','<',time()); + })->whereOr(function($query){ + $query->where('ProductPresell.presell_type',2)->whereTime('final_end_time','<',time()); + }); + }); + break; + default: + $query->where(function($query){ + $query->where(function($query){ + $query->where('ProductPresell.presell_type',1)->whereTime('end_time','>',time()); + })->whereOr(function($query){ + $query->where('ProductPresell.presell_type',2)->whereTime('final_end_time','>',time()); + }); + }); + break; + } + }) + ->when(isset($where['status']) && $where['status'] !== '',function($query)use($where){ + $query->where('ProductPresell.status',$where['status']); + }) + ->when(isset($where['is_show']) && $where['is_show'] !== '',function($query)use($where){ + $query->where('ProductPresell.is_show',$where['is_show']); + }) + ->when(isset($where['mer_name']) && $where['mer_name'] !== '',function($query)use($where){ + $make = app()->make(MerchantRepository::class); + $mer_id = $make->search(['keyword' => $where['mer_name']])->column('mer_id'); + $query->whereIn('ProductPresell.mer_id',$mer_id); + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '',function($query)use($where){ + $make = app()->make(MerchantRepository::class); + $mer_id = $make->search(['is_trader' => $where['is_trader']])->column('mer_id'); + $query->whereIn('ProductPresell.mer_id',$mer_id); + }) + ->when(isset($where['us_status']) && $where['us_status'] !== '',function($query)use($where){ + if($where['us_status'] == 0) { + $query->where('ProductPresell.is_show',0)->where('ProductPresell.status',1)->where('ProductPresell.product_status',1); + } + if($where['us_status'] == 1) { + $query->where('ProductPresell.is_show',1)->where('ProductPresell.status',1)->where('ProductPresell.product_status',1); + } + if($where['us_status'] == -1) { + $query->where(function($query){ + $query->where('ProductPresell.status',0)->whereOr('ProductPresell.product_status','<>',1); + }); + } + }); + $query->when(isset($where['mer_labels']) && $where['mer_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.mer_labels', "%,{$where['mer_labels']},%"); + }) + ->when(isset($where['sys_labels']) && $where['sys_labels'] !== '', function ($query) use ($where) { + $query->whereLike('U.sys_labels', "%,{$where['sys_labels']},%"); + }) + ->when(isset($where['star']),function($query)use($where){ + $query->when($where['star'] !== '', function ($query) use ($where) { + $query->where('U.star', $where['star']); + }); + $query->order('U.star DESC,U.rank DESC,ProductPresell.create_time DESC'); + }); + $query->where('ProductPresell.is_del',0); + return $query; + } + + /** + * TODO 移动端展示 条件 + * @return array + * @author Qinii + * @day 2020-10-19 + */ + public function actionShow() + { + return [ + 'product_show' => 1, + //'product_status' => 1, + 'status' => 1, + 'is_show' => 1, + 'api_type' => 1 + ]; + } + + /** + * TODO + * @author Qinii + * @day 1/27/21 + */ + public function valActiveStatus() + { + $query = $this->getModel()::getDB()->whereTime('end_time','<=',time())->where('action_status',1); + $id = $query->column($this->getPk()); + if($id){ + $this->getModel()::getDB()->where($this->getPk(),'in',$id)->update(['action_status' => -1]); + $where = [ + 'product_type' => 2, + 'activity_ids' => $id + ]; + app()->make(SpuRepository::class)->getSearch($where)->update(['status' => 0]); + } + } + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id', $merId)->update(['is_del' => 1]); + } + +} + diff --git a/app/common/dao/store/product/ProductPresellSkuDao.php b/app/common/dao/store/product/ProductPresellSkuDao.php new file mode 100644 index 00000000..fd2986a5 --- /dev/null +++ b/app/common/dao/store/product/ProductPresellSkuDao.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductPresellSku; +use think\facade\Db; + +class ProductPresellSkuDao extends BaseDao +{ + protected function getModel(): string + { + return ProductPresellSku::class; + } + + public function clear($id) + { + $this->getModel()::getDB()->where('product_presell_id', $id)->delete(); + } + + public function descStock(int $product_presell_id, string $unique, int $desc) + { + return $this->getModel()::getDB()->where('product_presell_id', $product_presell_id)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock-' . $desc), + 'seles' => Db::raw('seles+' . $desc), + ]); + } + + public function incStock(int $product_presell_id, string $unique, int $desc) + { + return $this->getModel()::getDB()->where('product_presell_id', $product_presell_id)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock+' . $desc), + 'seles' => Db::raw('seles-' . $desc), + ]); + } + + /** + * TODO 增加 参与或支付成功 人数 + * @param int $product_presell_id + * @param string $unique + * @param string $field + * @return mixed + * @author Qinii + * @day 2020-11-27 + */ + public function incCount(int $product_presell_id,string $unique,string $field,$inc = 1) + { + return $this->getModel()::getDB()->where('product_presell_id', $product_presell_id)->where('unique', $unique) + ->update([ + $field => Db::raw($field.'+' . $inc) + ]); + } + + /** + * TODO 减少 参与或支付成功 人数 + * @param int $product_presell_id + * @param string $unique + * @param string $field + * @return mixed + * @author Qinii + * @day 2020-11-27 + */ + public function desCount(int $product_presell_id,string $unique,$inc = 1) + { + $res = $this->getModel()::getDB()->where('product_presell_id', $product_presell_id)->where('unique',$unique)->find(); + if($res->presell->presell_type == 1 ){ + $res->one_pay = ($res->one_pay > 0) ? $res->one_pay - $inc : 0; + }else{ + $res->two_pay = ($res->two_pay > 0) ? $res->two_pay - $inc : 0; + } + return $res->save(); + } +} + diff --git a/app/common/dao/store/product/ProductReplyDao.php b/app/common/dao/store/product/ProductReplyDao.php new file mode 100644 index 00000000..028adde3 --- /dev/null +++ b/app/common/dao/store/product/ProductReplyDao.php @@ -0,0 +1,177 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\product; + + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductReply; +use crmeb\jobs\UpdateProductReplyJob; +use think\db\BaseQuery; +use think\db\exception\DbException; +use think\facade\Db; +use think\facade\Queue; + +/** + * Class ProductReplyDao + * @package app\common\dao\store\product + * @author xaboy + * @day 2020/5/30 + */ +class ProductReplyDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/30 + */ + protected function getModel(): string + { + return ProductReply::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/6/1 + */ + public function search(array $where) + { + return ProductReply::getDB()->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['is_reply']) && $where['is_reply'] !== '', function ($query) use ($where) { + $query->where('is_reply', $where['is_reply']); + })->when(isset($where['is_virtual']) && $where['is_virtual'] !== '', function ($query) use ($where) { + $query->where('is_virtual', $where['is_virtual']); + })->when(isset($where['nickname']) && $where['nickname'] !== '', function ($query) use ($where) { + $query->whereLike('nickname', "%{$where['nickname']}%"); + })->when(isset($where['product_id']) && $where['product_id'] !== '', function ($query) use ($where) { + $query->where('product_id', $where['product_id']); + })->when(isset($where['product_type']) && $where['product_type'] !== '', function ($query) use ($where) { + $query->where('product_type', 'product_type'); + })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) { + $query->where('is_del', $where['is_del']); + })->order('sort DESC'); + } + + public function searchJoinQuery(array $where) + { + return ProductReply::getDB()->alias('A') + ->join('StoreProduct B', 'A.product_id = B.product_id') + ->when(isset($where['is_reply']) && $where['is_reply'] !== '', function ($query) use ($where) { + $query->where('A.is_reply', $where['is_reply']); + }) + ->when(isset($where['nickname']) && $where['nickname'] !== '', function ($query) use ($where) { + $query->whereLike('A.nickname', "%{$where['nickname']}%"); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->where(function ($query) use ($where) { + $query->where('B.store_name', 'like', "%{$where['keyword']}%") + ->whereOr('B.product_id', $where['keyword']); + }); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'A.create_time'); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('A.mer_id', $where['mer_id']); + }) + ->when(isset($where['product_id']) && $where['product_id'] !== '', function ($query) use ($where) { + $query->where('A.product_id', $where['product_id']); + }) + ->order('A.sort DESC, A.create_time DESC') + ->where('A.is_del', 0) + ->field('A.reply_id,A.is_reply,A.uid,A.product_score,A.service_score,A.postage_score,A.comment,A.pics,A.create_time,A.merchant_reply_content,A.nickname,A.avatar,B.store_name,B.image,B.product_id,A.sort'); + } + + /** + * @param array $data + * @return int + * @author xaboy + * @day 2020/5/30 + */ + public function insertAll(array $data) + { + return ProductReply::getDB()->insertAll($data); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020/5/30 + */ + public function exists(int $id) + { + return ProductReply::getDB()->where($this->getPk(), $id)->where('is_del', 0)->count() > 0; + } + + /** + * @param $merId + * @param int $id + * @return bool + * @author xaboy + * @day 2020/6/28 + */ + public function merExists($merId, int $id) + { + return ProductReply::getDB()->where($this->getPk(), $id)->where('is_del', 0)->where('mer_id', $merId)->count() > 0; + } + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020/5/30 + */ + public function delete(int $id) + { + $reply = ProductReply::getDB()->where('reply_id', $id)->find(); + $reply->is_del = 1; + $reply->save(); + Queue::push(UpdateProductReplyJob::class, $reply['product_id']); + } + + /** + * 返回评论数 + * @Author:Qinii + * @Date: 2020/6/2 + * @param int $productId + * @param array $where + * @return mixed + */ + public function getProductReplay(int $productId, $where = [0, 5]) + { + return $this->getModel()::getDB()->where('product_id', $productId)->whereBetween('rate', $where)->select(); + } + + public function productTotalRate($productId) + { + return ProductReply::getDB()->where('product_id', $productId)->where('is_del', 0)->field('sum(rate) as total_rate,count(reply_id) as total_count')->find(); + } + + /** + * 计算商铺平均分 + * @param $merId + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function merchantTotalRate($merId) + { + return ($this->getModel()::getDB())->where('mer_id', $merId)->field('avg(product_score) product_score ,avg(service_score) service_score,avg(postage_score) postage_score')->find()->toArray(); + } +} diff --git a/app/common/dao/store/product/ProductSkuDao.php b/app/common/dao/store/product/ProductSkuDao.php new file mode 100644 index 00000000..bcb4f79e --- /dev/null +++ b/app/common/dao/store/product/ProductSkuDao.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductSku; +use think\facade\Db; + +class ProductSkuDao extends BaseDao +{ + protected function getModel(): string + { + return ProductSku::class; + } + + public function clear(int $id, int $type) + { + $this->getModel()::getDB()->where('active_id', $id)->where('active_type', $type)->delete(); + } + + public function descStock(int $active_id, string $unique, int $desc) + { + return $this->getModel()::getDB()->where('active_id', $active_id)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock-' . $desc) + ]); + } + + public function incStock(int $active_id, string $unique, int $desc) + { + return $this->getModel()::getDB()->where('active_id', $active_id)->where('unique', $unique)->update([ + 'stock' => Db::raw('stock+' . $desc) + ]); + } +} + diff --git a/app/common/dao/store/product/ProductTakeDao.php b/app/common/dao/store/product/ProductTakeDao.php new file mode 100644 index 00000000..1e2b20ea --- /dev/null +++ b/app/common/dao/store/product/ProductTakeDao.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductTake; +use think\facade\Db; + +class ProductTakeDao extends BaseDao +{ + + protected function getModel(): string + { + return ProductTake::class; + } + + public function changeStatus($id) + { + $this->getSearch(['product_id' => $id,'status' => 0])->update(['status' => 1]); + } +} diff --git a/app/common/dao/store/product/SpuDao.php b/app/common/dao/store/product/SpuDao.php new file mode 100644 index 00000000..8a437bf3 --- /dev/null +++ b/app/common/dao/store/product/SpuDao.php @@ -0,0 +1,207 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductCate; +use app\common\model\store\product\Spu; +use app\common\model\store\StoreCategory; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\services\VicWordService; + +class SpuDao extends BaseDao +{ + public function getModel(): string + { + return Spu::class; + } + + public function search($where) + { + $order = 'P.sort DESC'; + if(isset($where['order'])){ + if(in_array($where['order'], ['is_new', 'price_asc', 'price_desc', 'rate', 'sales'])){ + if ($where['order'] == 'price_asc') { + $order = 'S.price ASC'; + } else if ($where['order'] == 'price_desc') { + $order = 'S.price DESC'; + } else { + $order = 'P.'.$where['order'] . ' DESC'; + } + }elseif($where['order'] == 'star'){ + $order = 'S.star DESC,S.rank DESC'; + }else{ + $order = 'S.'. (($where['order'] !== '') ?$where['order']: 'star' ).' DESC'; + } + } + + $order .= ',S.create_time DESC'; + if(isset($where['order']) && $where['order'] === 'none'){ + $order = ''; + } + $query = Spu::getDB()->alias('S')->join('StoreProduct P','S.product_id = P.product_id', 'left')->where('P.product_type',$where['product_type']); + $query->when(isset($where['is_del']) && $where['is_del'] !== '',function($query)use($where){ + $query->where('P.is_del',$where['is_del']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('P.mer_id',$where['mer_id']); + }) + ->when(isset($where['mer_ids']) && $where['mer_ids'] !== '',function($query)use($where){ + $query->whereIn('P.mer_id',$where['mer_ids']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '',function($query)use($where){ + if (is_numeric($where['keyword'])) { + $query->whereLike("S.store_name|S.keyword|S.product_id", "%{$where['keyword']}%"); + } else { + $word = app()->make(VicWordService::class)->getWord($where['keyword']); + $query->where(function ($query) use ($word) { + foreach ($word as $item) { + $query->whereOr('S.store_name|S.keyword', 'LIKE', "%$item%"); + } + }); + } + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '',function($query)use($where){ + $merId = app()->make(MerchantRepository::class)->search([ + 'is_trader' => $where['is_trader'], + 'status' => 1, + 'mer_state' => 1, + 'is_del' => 1, + ])->column('mer_id'); + + $query->whereIn('P.mer_id',$merId); + }) + ->when(isset($where['cate_pid']) && $where['cate_pid'], function ($query) use ($where) { + $storeCategoryRepository = app()->make(StoreCategoryRepository::class); + if (is_array($where['cate_pid'])) { + $cateIds = $storeCategoryRepository->selectChildrenId($where['cate_pid']); + } else { + $cateIds = $storeCategoryRepository->findChildrenId((int)$where['cate_pid']); + $where['cate_pid'] = [$where['cate_pid']]; + } + $cate = array_merge($cateIds, $where['cate_pid']); + $query->whereIn('P.cate_id', $cate); + }) + ->when(isset($where['cate_id']) && $where['cate_id'] !== '', function ($query) use ($where) { + is_array($where['cate_id']) ? $query->whereIn('P.cate_id', $where['cate_id']) : $query->where('P.cate_id', $where['cate_id']); + }) + ->when(isset($where['spu_id']) && $where['spu_id'] !== '', function ($query) use ($where) { + $query->where('S.spu_id',$where['spu_id']); + }) + ->when(isset($where['spu_ids']) && $where['spu_ids'] !== '', function ($query) use ($where) { + $query->whereIn('S.spu_id',$where['spu_ids']); + }) + ->when(isset($where['product_ids']) && !empty($where['product_ids']), function ($query) use ($where) { + $query->whereIn('P.product_id',$where['product_ids']); + }) + ->when(isset($where['is_stock']) && !empty($where['is_stock']), function ($query) use ($where) { + $query->where('P.stock','>',0); + }) + ->when(isset($where['is_coupon']) && !empty($where['is_coupon']), function ($query) use ($where) { + $query->whereIn('P.product_type','0,2'); + }) + ->when(isset($where['common']) && $where['common'] !== '', function ($query) use ($where) { + $query->whereIn('S.product_type', [0, 1]); + }) + ->when(isset($where['price_on']) && $where['price_on'] !== '',function($query)use($where){ + $query->where('S.price','>=',$where['price_on']); + }) + ->when(isset($where['price_off']) && $where['price_off'] !== '',function($query)use($where){ + $query->where('S.price','<=',$where['price_off']); + }) + ->when(isset($where['brand_id']) && $where['brand_id'] !== '', function ($query) use ($where) { + $query->whereIn('P.brand_id', array_map('intval', explode(',', $where['brand_id']))); + }) + ->when(isset($where['is_gift_bag']) && $where['is_gift_bag'] !== '',function($query)use($where){ + $query->where('P.is_gift_bag',$where['is_gift_bag']); + }) + ->when(isset($where['product_type']) && $where['product_type'] !== '',function($query)use($where){ + $query->where('S.product_type',$where['product_type']); + }) + ->when(isset($where['action']) && $where['action'] !== '',function($query)use($where){ + $query->where('S.product_type','>',0); + }) + ->when(isset($where['mer_cate_id']) && $where['mer_cate_id'] !== '',function($query)use($where){ + $ids = (StoreCategory::where('path','like','%/'.$where['mer_cate_id'].'/%'))->column('store_category_id'); + $ids[] = intval($where['mer_cate_id']); + $ids = array_unique($ids); + $productId = ProductCate::where('mer_cate_id', 'in', $ids)->column('product_id'); + $productId = array_unique($productId); + $query->where('P.product_id','in',$productId); + }) + ->when(isset($where['mer_status']) && $where['mer_status'] !== '',function($query)use($where){ + $query->where('mer_status',$where['mer_status']); + }) + ->when(isset($where['spu_status']) && $where['spu_status'] !== '',function($query)use($where){ + $query->where('S.status',$where['spu_status']); + }) + ->when(isset($where['sys_labels']) && $where['sys_labels'] !== '',function($query)use($where){ + $query->whereLike('S.sys_labels',"%,{$where['sys_labels']},%"); + }) + ->when(isset($where['mer_labels']) && $where['mer_labels'] !== '',function($query)use($where){ + $query->whereLike('S.mer_labels',"%,{$where['mer_labels']},%"); + }) + ->when(isset($where['pid']) && $where['pid'] !== '', function ($query) use ($where) { + $query->join('StoreCategory CT','P.cate_id = CT.store_category_id')->where('CT.pid',$where['pid']); + }) + ->when(isset($where['delivery_way']) && $where['delivery_way'] !== '', function ($query) use ($where) { + $query->whereLike('P.delivery_way',"%{$where['delivery_way']}%"); + }) + ->when(isset($where['hot_type']) && $where['hot_type'] !== '', function ($query) use ($where) { + if ($where['hot_type'] == 'new') $query->where('P.is_new', 1); + else if ($where['hot_type'] == 'hot') $query->where('P.is_hot', 1); + else if ($where['hot_type'] == 'best') $query->where('P.is_best', 1); + else if ($where['hot_type'] == 'good') $query->where('P.is_benefit', 1); + }) + ->when(isset($where['svip']) && $where['svip'] !== '',function($query)use($where){ + $query->where('svip_price_type','>',0)->where('mer_svip_status',1); + }); + return $query->order($order); + } + + public function findOrCreateAll(array $where) + { + foreach ($where as $item) { + $item['activity_id'] = $item['activity_id'] ?? 0; + $data = $this->getModel()::getDB()->where('product_id', $item['product_id']) + ->where('product_type', $item['product_type']) + ->where('activity_id', $item['activity_id']) + ->find(); + if (!$data) $this->create($item); + } + } + + public function delProduct($id, $isDel = 1) + { + $this->getModel()::getDb()->where('product_id', $id)->update(['is_del' => $isDel]); + } + + public function getActivecategory($type) + { + $query = Spu::getDB()->alias('S')->join('StoreProduct P','S.product_id = P.product_id') + ->join('StoreCategory C','C.store_category_id = P.cate_id'); + + $query->where('S.status',1)->where('S.product_type',$type)->where('C.is_show',1); + return $query->group('S.product_id')->column('C.path'); + } + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id', $merId)->update(['is_del' => 1]); + } +} diff --git a/app/common/dao/store/product/SpuDao.php.bak b/app/common/dao/store/product/SpuDao.php.bak new file mode 100644 index 00000000..542dbc5e --- /dev/null +++ b/app/common/dao/store/product/SpuDao.php.bak @@ -0,0 +1,207 @@ + +// +---------------------------------------------------------------------- +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\ProductCate; +use app\common\model\store\product\Spu; +use app\common\model\store\StoreCategory; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\services\VicWordService; + +class SpuDao extends BaseDao +{ + public function getModel(): string + { + return Spu::class; + } + + public function search($where) + { + $order = 'P.sort DESC'; + if(isset($where['order'])){ + if(in_array($where['order'], ['is_new', 'price_asc', 'price_desc', 'rate', 'sales'])){ + if ($where['order'] == 'price_asc') { + $order = 'S.price ASC'; + } else if ($where['order'] == 'price_desc') { + $order = 'S.price DESC'; + } else { + $order = 'P.'.$where['order'] . ' DESC'; + } + }elseif($where['order'] == 'star'){ + $order = 'S.star DESC,S.rank DESC'; + }else{ + $order = 'S.'. (($where['order'] !== '') ?$where['order']: 'star' ).' DESC'; + } + } + + $order .= ',S.create_time DESC'; + if(isset($where['order']) && $where['order'] === 'none'){ + $order = ''; + } + $query = Spu::getDB()->alias('S')->join('StoreProduct P','S.product_id = P.product_id', 'left'); + $query->when(isset($where['is_del']) && $where['is_del'] !== '',function($query)use($where){ + $query->where('P.is_del',$where['is_del']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '',function($query)use($where){ + $query->where('P.mer_id',$where['mer_id']); + }) + ->when(isset($where['mer_ids']) && $where['mer_ids'] !== '',function($query)use($where){ + $query->whereIn('P.mer_id',$where['mer_ids']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '',function($query)use($where){ + if (is_numeric($where['keyword'])) { + $query->whereLike("S.store_name|S.keyword|S.product_id", "%{$where['keyword']}%"); + } else { + $word = app()->make(VicWordService::class)->getWord($where['keyword']); + $query->where(function ($query) use ($word) { + foreach ($word as $item) { + $query->whereOr('S.store_name|S.keyword', 'LIKE', "%$item%"); + } + }); + } + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '',function($query)use($where){ + $merId = app()->make(MerchantRepository::class)->search([ + 'is_trader' => $where['is_trader'], + 'status' => 1, + 'mer_state' => 1, + 'is_del' => 1, + ])->column('mer_id'); + + $query->whereIn('P.mer_id',$merId); + }) + ->when(isset($where['cate_pid']) && $where['cate_pid'], function ($query) use ($where) { + $storeCategoryRepository = app()->make(StoreCategoryRepository::class); + if (is_array($where['cate_pid'])) { + $cateIds = $storeCategoryRepository->selectChildrenId($where['cate_pid']); + } else { + $cateIds = $storeCategoryRepository->findChildrenId((int)$where['cate_pid']); + $where['cate_pid'] = [$where['cate_pid']]; + } + $cate = array_merge($cateIds, $where['cate_pid']); + $query->whereIn('P.cate_id', $cate); + }) + ->when(isset($where['cate_id']) && $where['cate_id'] !== '', function ($query) use ($where) { + is_array($where['cate_id']) ? $query->whereIn('P.cate_id', $where['cate_id']) : $query->where('P.cate_id', $where['cate_id']); + }) + ->when(isset($where['spu_id']) && $where['spu_id'] !== '', function ($query) use ($where) { + $query->where('S.spu_id',$where['spu_id']); + }) + ->when(isset($where['spu_ids']) && $where['spu_ids'] !== '', function ($query) use ($where) { + $query->whereIn('S.spu_id',$where['spu_ids']); + }) + ->when(isset($where['product_ids']) && !empty($where['product_ids']), function ($query) use ($where) { + $query->whereIn('P.product_id',$where['product_ids']); + }) + ->when(isset($where['is_stock']) && !empty($where['is_stock']), function ($query) use ($where) { + $query->where('P.stock','>',0); + }) + ->when(isset($where['is_coupon']) && !empty($where['is_coupon']), function ($query) use ($where) { + $query->whereIn('P.product_type','0,2'); + }) + ->when(isset($where['common']) && $where['common'] !== '', function ($query) use ($where) { + $query->whereIn('S.product_type', [0, 1]); + }) + ->when(isset($where['price_on']) && $where['price_on'] !== '',function($query)use($where){ + $query->where('S.price','>=',$where['price_on']); + }) + ->when(isset($where['price_off']) && $where['price_off'] !== '',function($query)use($where){ + $query->where('S.price','<=',$where['price_off']); + }) + ->when(isset($where['brand_id']) && $where['brand_id'] !== '', function ($query) use ($where) { + $query->whereIn('P.brand_id', array_map('intval', explode(',', $where['brand_id']))); + }) + ->when(isset($where['is_gift_bag']) && $where['is_gift_bag'] !== '',function($query)use($where){ + $query->where('P.is_gift_bag',$where['is_gift_bag']); + }) + ->when(isset($where['product_type']) && $where['product_type'] !== '',function($query)use($where){ + $query->where('S.product_type',$where['product_type']); + }) + ->when(isset($where['action']) && $where['action'] !== '',function($query)use($where){ + $query->where('S.product_type','>',0); + }) + ->when(isset($where['mer_cate_id']) && $where['mer_cate_id'] !== '',function($query)use($where){ + $ids = (StoreCategory::where('path','like','%/'.$where['mer_cate_id'].'/%'))->column('store_category_id'); + $ids[] = intval($where['mer_cate_id']); + $ids = array_unique($ids); + $productId = ProductCate::where('mer_cate_id', 'in', $ids)->column('product_id'); + $productId = array_unique($productId); + $query->where('P.product_id','in',$productId); + }) + ->when(isset($where['mer_status']) && $where['mer_status'] !== '',function($query)use($where){ + $query->where('mer_status',$where['mer_status']); + }) + ->when(isset($where['spu_status']) && $where['spu_status'] !== '',function($query)use($where){ + $query->where('S.status',$where['spu_status']); + }) + ->when(isset($where['sys_labels']) && $where['sys_labels'] !== '',function($query)use($where){ + $query->whereLike('S.sys_labels',"%,{$where['sys_labels']},%"); + }) + ->when(isset($where['mer_labels']) && $where['mer_labels'] !== '',function($query)use($where){ + $query->whereLike('S.mer_labels',"%,{$where['mer_labels']},%"); + }) + ->when(isset($where['pid']) && $where['pid'] !== '', function ($query) use ($where) { + $query->join('StoreCategory CT','P.cate_id = CT.store_category_id')->where('CT.pid',$where['pid']); + }) + ->when(isset($where['delivery_way']) && $where['delivery_way'] !== '', function ($query) use ($where) { + $query->whereLike('P.delivery_way',"%{$where['delivery_way']}%"); + }) + ->when(isset($where['hot_type']) && $where['hot_type'] !== '', function ($query) use ($where) { + if ($where['hot_type'] == 'new') $query->where('P.is_new', 1); + else if ($where['hot_type'] == 'hot') $query->where('P.is_hot', 1); + else if ($where['hot_type'] == 'best') $query->where('P.is_best', 1); + else if ($where['hot_type'] == 'good') $query->where('P.is_benefit', 1); + }) + ->when(isset($where['svip']) && $where['svip'] !== '',function($query)use($where){ + $query->where('svip_price_type','>',0)->where('mer_svip_status',1); + }); + return $query->order($order); + } + + public function findOrCreateAll(array $where) + { + foreach ($where as $item) { + $item['activity_id'] = $item['activity_id'] ?? 0; + $data = $this->getModel()::getDB()->where('product_id', $item['product_id']) + ->where('product_type', $item['product_type']) + ->where('activity_id', $item['activity_id']) + ->find(); + if (!$data) $this->create($item); + } + } + + public function delProduct($id, $isDel = 1) + { + $this->getModel()::getDb()->where('product_id', $id)->update(['is_del' => $isDel]); + } + + public function getActivecategory($type) + { + $query = Spu::getDB()->alias('S')->join('StoreProduct P','S.product_id = P.product_id') + ->join('StoreCategory C','C.store_category_id = P.cate_id'); + + $query->where('S.status',1)->where('S.product_type',$type)->where('C.is_show',1); + return $query->group('S.product_id')->column('C.path'); + } + + /** + * TODO 软删除商户的所有商品 + * @param $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearProduct($merId) + { + $this->getModel()::getDb()->where('mer_id', $merId)->update(['is_del' => 1]); + } +} diff --git a/app/common/dao/store/product/StoreDiscountDao.php b/app/common/dao/store/product/StoreDiscountDao.php new file mode 100644 index 00000000..461f720a --- /dev/null +++ b/app/common/dao/store/product/StoreDiscountDao.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\StoreDiscounts; + +class StoreDiscountDao extends BaseDao +{ + protected function getModel(): string + { + return StoreDiscounts::class; + } + + public function incStock($id) + { + $res = $this->getModel()::getDb()->find($id); + if ($res) { + if ($res['is_limit']) $res->limit_num++; + if ($res->sales > 1) $res->sales--; + $res->save(); + } + + } + + public function decStock($id) + { + $res = $this->getModel()::getDb()->find($id); + if (!$res) { + return false; + } + $res->sales++; + + if ($res['is_limit']) { + if ($res['limit_num'] > 0) { + $res->limit_num--; + } else { + return false; + } + } + $res->save(); + return true; + } + +} + diff --git a/app/common/dao/store/product/StoreDiscountProductDao.php b/app/common/dao/store/product/StoreDiscountProductDao.php new file mode 100644 index 00000000..22caf722 --- /dev/null +++ b/app/common/dao/store/product/StoreDiscountProductDao.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\product; + +use app\common\dao\BaseDao; +use app\common\model\store\product\StoreDiscounts; +use app\common\model\store\product\StoreDiscountProduct; +use app\common\repositories\store\product\ProductSkuRepository; +use think\facade\Db; + +class StoreDiscountProductDao extends BaseDao +{ + protected function getModel(): string + { + return StoreDiscountProduct::class; + } + + public function clear($id) + { + $this->getModel()::getDb()->where('discount_id',$id)->delete(); + } +} + diff --git a/app/common/dao/store/service/StoreServiceDao.php b/app/common/dao/store/service/StoreServiceDao.php new file mode 100644 index 00000000..0e3e832a --- /dev/null +++ b/app/common/dao/store/service/StoreServiceDao.php @@ -0,0 +1,199 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\service; + + +use app\common\dao\BaseDao; +use app\common\model\store\service\StoreService; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class StoreServiceDao + * @package app\common\dao\store\service + * @author xaboy + * @day 2020/5/29 + */ +class StoreServiceDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/29 + */ + protected function getModel(): string + { + return StoreService::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/5/29 + */ + public function search(array $where) + { + return StoreService::getDB()->where('is_del', 0)->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('nickname', "%{$where['keyword']}%"); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['customer']) && $where['customer'] !== '', function ($query) use ($where) { + $query->where('customer', $where['customer']); + })->when(isset($where['is_verify']) && $where['is_verify'] !== '', function ($query) use ($where) { + $query->where('is_verify', $where['is_verify']); + })->when(isset($where['is_goods']) && $where['is_goods'] !== '', function ($query) use ($where) { + $query->where('is_goods', $where['is_goods']); + })->when(isset($where['is_open']) && $where['is_open'] !== '', function ($query) use ($where) { + $query->where('is_open', $where['is_open']); + })->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->when(isset($where['service_id']) && $where['service_id'] !== '', function ($query) use ($where) { + $query->where('service_id', $where['service_id']); + }); + } + + public function getService($uid, $merId = null) + { + return StoreService::getDB()->where('uid', $uid)->when(!is_null($merId), function ($query) use($merId) { + $query->where('mer_id', $merId); + })->where('is_del', 0)->find(); + } + + + /** + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-30 + */ + public function fieldExists($field, $value, ?int $except = null): bool + { + $query = ($this->getModel())::getDB()->where($field, $value)->where('is_del', 0); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->count() > 0; + } + + /** + * @param int $merId + * @param int $id + * @return bool + * @author xaboy + * @day 2020-05-13 + */ + public function merExists(int $merId, int $id) + { + return StoreService::getDB()->where($this->getPk(), $id)->where('mer_id', $merId)->where('is_del', 0)->count($this->getPk()) > 0; + } + + /** + * @param $merId + * @param $uid + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020/5/29 + */ + public function issetService($merId, $uid, ?int $except = null) + { + return StoreService::getDB()->where('uid', $uid)->when($except, function ($query, $except) { + $query->where($this->getPk(), '<>', $except); + })->where('mer_id', $merId)->where('is_del', 0)->count($this->getPk()) > 0; + } + + /** + * @param $uid + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020/5/29 + */ + public function isBindService($uid, ?int $except = null) + { + return StoreService::getDB()->where('uid', $uid)->when($except, function ($query, $except) { + $query->where($this->getPk(), '<>', $except); + })->where('is_del', 0)->count($this->getPk()) > 0; + } + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function delete(int $id) + { + return StoreService::getDB()->where($this->getPk(), $id)->update(['is_del' => 1]); + } + + /** + * @param $merId + * @return array|Model|null + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function getChatService($merId) + { + return StoreService::getDB()->where('mer_id', $merId)->where('is_del', 0)->where('status', 1)->order('status DESC, sort DESC, create_time ASC') + ->hidden(['is_del'])->find(); + } + + public function getRandService($merId) + { + $services = StoreService::getDB()->where('mer_id', $merId)->where('is_open',1)->where('is_del', 0)->where('status', 1)->order('status DESC, sort DESC, create_time ASC') + ->hidden(['is_del'])->select(); + if (!$services || !count($services)) return null; + if (count($services) === 1) $services[0]; + return $services[max(random_int(0, count($services) - 1), 0)]; + } + + /** + * @param $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function getValidServiceInfo($id) + { + return StoreService::getDB()->where('service_id', $id)->where('is_open',1)->where('status', 1)->where('is_del', 0)->hidden(['is_del'])->find(); + } + + /** + * @param $merId + * @return array + * @author xaboy + * @day 2020/7/1 + */ + public function getNoticeServiceInfo($merId) + { + return StoreService::getDB()->where('mer_id', $merId)->where('status', 1)->where('notify', 1) + ->where('is_del', 0)->column('uid,phone,nickname'); + } + +} diff --git a/app/common/dao/store/service/StoreServiceLogDao.php b/app/common/dao/store/service/StoreServiceLogDao.php new file mode 100644 index 00000000..20b63a72 --- /dev/null +++ b/app/common/dao/store/service/StoreServiceLogDao.php @@ -0,0 +1,183 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\service; + + +use app\common\dao\BaseDao; +use app\common\model\store\service\StoreServiceLog; +use think\db\BaseQuery; + +/** + * Class StoreServiceLogDao + * @package app\common\dao\store\service + * @author xaboy + * @day 2020/5/29 + */ +class StoreServiceLogDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/29 + */ + protected function getModel(): string + { + return StoreServiceLog::class; + } + + /** + * @param $merId + * @param $uid + * @return int + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/6/16 + */ + public function userRead($merId, $uid) + { + return StoreServiceLog::getDB()->where('mer_id', $merId)->where('uid', $uid)->where('type', '<>', 1)->update(['type' => 1]); + } + + /** + * @param $uid + * @param $merId + * @return bool + * @author xaboy + * @day 2020/6/16 + */ + public function issetLog($uid, $merId) + { + return StoreServiceLog::getDB()->where('mer_id', $merId)->where('uid', $uid)->where('send_type', 0)->limit(1)->count() > 0; + } + + /** + * @param $merId + * @param $uid + * @param $serviceId + * @return int + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/10/15 + */ + public function serviceRead($merId, $uid, $serviceId) + { + return StoreServiceLog::getDB()->where('mer_id', $merId)->where('uid', $uid)->where('service_id', $serviceId)->where('service_type', '<>', 1)->update(['service_type' => 1]); + } + + /** + * @param array $where + * @return \think\db\BaseQuery + * @author xaboy + * @day 2020/6/16 + */ + public function search(array $where) + { + return StoreServiceLog::getDB()->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['last_id']) && $where['last_id'] !== '', function ($query) use ($where) { + $query->where('service_log_id', '<', $where['last_id']); + })->when(isset($where['service_id']) && $where['service_id'] !== '', function ($query) use ($where) { + $query->where('service_id', $where['service_id']); + }); + } + + /** + * @param $merId + * @param $uid + * @return mixed + * @author xaboy + * @day 2020/5/29 + */ + public function getLastServiceId($merId, $uid) + { + return StoreServiceLog::getDB()->where('mer_id', $merId)->order('service_log_id DESC')->where('uid', $uid)->value('service_id'); + } + + /** + * @param $uid + * @return BaseQuery + * @author xaboy + * @day 2020/6/16 + */ + public function getMerchantListQuery($uid) + { + return StoreServiceLog::getDB()->where('uid', $uid)->group('mer_id'); + } + + /** + * TODO 客服的所有用户 + * @param $serviceId + * @return BaseQuery + * @author xaboy + * @day 2020/6/16 + */ + public function getUserListQuery($serviceId) + { + return StoreServiceLog::getDB()->where('service_id', $serviceId); + } + + /** + * TODO 商户的所有用户 + * @param $merId + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function getMerchantUserList($merId) + { + return StoreServiceLog::getDB()->where('mer_id', $merId); + } + + /** + * @param $merId + * @param $uid + * @return array|\think\Model|null + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/19 + */ + public function getLastLog($merId, $uid) + { + return StoreServiceLog::getDB()->where('mer_id', $merId)->where('uid', $uid)->order('service_log_id DESC')->find(); + } + + /** + * @param $merId + * @param $uid + * @param $sendType + * @return int + * @author xaboy + * @day 2020/6/19 + */ + public function getUnReadNum($merId, $uid, $sendType) + { + return StoreServiceLog::getDB()->where('uid', $uid)->where('mer_id', $merId)->where('send_type', $sendType)->where($sendType ? 'type' : 'service_type', 0)->count(); + } + + /** + * @param $uid + * @return int + * @author xaboy + * @day 2020/6/19 + */ + public function totalUnReadNum($uid) + { + return StoreServiceLog::getDB()->where('uid', $uid)->where('send_type', 1)->where('type', 0)->count(); + } +} diff --git a/app/common/dao/store/service/StoreServiceReplyDao.php b/app/common/dao/store/service/StoreServiceReplyDao.php new file mode 100644 index 00000000..a52d68d1 --- /dev/null +++ b/app/common/dao/store/service/StoreServiceReplyDao.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\service; + + +use app\common\dao\BaseDao; +use app\common\model\store\service\StoreServiceReply; + +/** + * Class StoreServiceDao + * @package app\common\dao\store\service + * @author xaboy + * @day 2020/5/29 + */ +class StoreServiceReplyDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/29 + */ + protected function getModel(): string + { + return StoreServiceReply::class; + } + + public function search(array $where) + { + return StoreServiceReply::getDB()->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('keyword', "%{$where['keyword']}%"); + })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + }); + } + + public function keywordByValidData($key, $merId) + { + return StoreServiceReply::getDB()->where(function ($query) use ($key) { + $query->where('keyword', 'like',"%{$key}%")->whereFieldRaw('CONCAT(\',\',`keyword`,\',\')', 'LIKE', '%,' . $key . ',%', 'OR'); + })->where('status', 1)->where('mer_id', $merId)->find(); + } +} diff --git a/app/common/dao/store/service/StoreServiceUserDao.php b/app/common/dao/store/service/StoreServiceUserDao.php new file mode 100644 index 00000000..7ac027c4 --- /dev/null +++ b/app/common/dao/store/service/StoreServiceUserDao.php @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\store\service; + + +use app\common\dao\BaseDao; +use app\common\model\store\service\StoreServiceUser; +use app\common\repositories\system\ExtendRepository; +use app\common\repositories\user\UserRepository; + +/** + * Class StoreServiceDao + * @package app\common\dao\store\service + * @author xaboy + * @day 2020/5/29 + */ +class StoreServiceUserDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/29 + */ + protected function getModel(): string + { + return StoreServiceUser::class; + } + + public function search(array $where) + { + return StoreServiceUser::getDB()->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['service_id']) && $where['service_id'] !== '', function ($query) use ($where) { + $query->where('service_id', $where['service_id']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $uid = app()->make(UserRepository::class)->search(['keyword' => $where['keyword']])->limit(30)->column('uid'); + $uid = array_merge($uid, app()->make(ExtendRepository::class)->search([ + 'keyword' => $where['keyword'], + 'type' => ExtendRepository::TYPE_SERVICE_USER_MARK, + 'mer_id' => $where['mer_id'] ?? null + ])->column('link_id'), [0]); + $query->whereIn('uid', array_unique($uid)); + }); + } + +} diff --git a/app/common/dao/store/shipping/CityDao.php b/app/common/dao/store/shipping/CityDao.php new file mode 100644 index 00000000..1dc84d32 --- /dev/null +++ b/app/common/dao/store/shipping/CityDao.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use app\common\dao\BaseDao; +use app\common\model\store\shipping\City as model; + +class CityDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + public function getAll(array $where) + { + return ($this->getModel()::getDB())->where($where) + ->order('city_id ASC')->field('city_id,name,merger_name,parent_id,level')->select(); + } +} diff --git a/app/common/dao/store/shipping/ExpressDao.php b/app/common/dao/store/shipping/ExpressDao.php new file mode 100644 index 00000000..5736dbbb --- /dev/null +++ b/app/common/dao/store/shipping/ExpressDao.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use app\common\dao\BaseDao; +use app\common\model\store\shipping\Express as model; + +class ExpressDao extends BaseDao +{ + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @return string + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists($field, $value, $except = null, $id = null, $isUser = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->when($id, function ($query) use ($id) { + $query->where($this->getPk(), '<>', $id); + })->when($isUser, function ($query) { + $query->where('is_show', 1); + })->where($field, $value)->count() > 0; + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $where + * @return mixed + */ + public function search(array $where) + { + $query = ($this->getModel()::getDB()) + ->when(isset($where['keyword']) && $where['keyword'],function($query) use ($where){ + $query->where('name|code','like','%'.$where['keyword'].'%'); + }) + ->where(isset($where['code']) && $where['code'],function($query)use($where){ + $query->where('code',$where['name']); + }) + ->where(isset($where['is_show']) && $where['is_show'],function($query)use($where){ + $query->where('is_show',$where['is_show']); + }) + ->where(isset($where['id']) && $where['id'],function($query)use($where){ + $query->where('id',$where['id']); + }); + return $query->order('sort DESC'); + } +} diff --git a/app/common/dao/store/shipping/ExpressPartnerDao.php b/app/common/dao/store/shipping/ExpressPartnerDao.php new file mode 100644 index 00000000..fb04330e --- /dev/null +++ b/app/common/dao/store/shipping/ExpressPartnerDao.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use app\common\dao\BaseDao; +use app\common\model\store\shipping\ExpressPartner as model; + +class ExpressPartnerDao extends BaseDao +{ + /** + * TODO + * @return string + * @author Qinii + * @day 7/23/21 + */ + protected function getModel(): string + { + return model::class; + } +} diff --git a/app/common/dao/store/shipping/ShippingTemplateDao.php b/app/common/dao/store/shipping/ShippingTemplateDao.php new file mode 100644 index 00000000..3243f924 --- /dev/null +++ b/app/common/dao/store/shipping/ShippingTemplateDao.php @@ -0,0 +1,94 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use think\facade\Db; +use app\common\dao\BaseDao; +use app\common\model\store\shipping\ShippingTemplate as model; + +class ShippingTemplateDao extends BaseDao +{ + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/7 + * @param int $merId + * @param array $where + * @return mixed + */ + public function search(int $merId,array $where) + { + $query = ($this->getModel()::getDB())->where('mer_id',$merId)->order('sort desc'); + if(isset($where['name']) && !empty($where['name'])) + $query->where('name','like','%'.$where['name'].'%'); + if(isset($where['type']) && !empty($where['type'])) + $query->where('type',$where['type']); + return $query->order('sort DESC,create_time DESC'); + } + + /** + * 查询是否存在 + * @Author:Qinii + * @Date: 2020/5/7 + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where('mer_id', $merId)->where($field, $value)->count() > 0; + } + + /** + * 关联删除 + * @Author:Qinii + * @Date: 2020/5/7 + * @param int $id + * @return int|void + */ + public function delete(int $id) + { + $result = $this->getModel()::with(['free','region','undelives'])->find($id); + $result->together(['free','region','undelives'])->delete(); + } + + /** + * 批量删除 + * @Author:Qinii + * @Date: 2020/5/8 + * @param int $id + * @return mixed + */ + public function batchRemove(int $id) + { + return ($this->getModel())::getDB()->where($this->getPk(),'in',$id)->delete(); + } + + public function getList($merId) + { + return ($this->getModel())::getDB()->where('mer_id',$merId)->field('shipping_template_id,name')->order('sort DESC,create_time DESC')->select(); + } +} diff --git a/app/common/dao/store/shipping/ShippingTemplateFreeDao.php b/app/common/dao/store/shipping/ShippingTemplateFreeDao.php new file mode 100644 index 00000000..f7138b94 --- /dev/null +++ b/app/common/dao/store/shipping/ShippingTemplateFreeDao.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use think\facade\Db; +use app\common\dao\BaseDao; +use app\common\model\store\shipping\ShippingTemplateFree as model; + +class ShippingTemplateFreeDao extends BaseDao +{ + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + protected function getModel(): string + { + return model::class; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists($field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where($field, $value)->count() > 0; + } + + /** + * 批量删除 + * @Author:Qinii + * @Date: 2020/5/8 + * @param array $id + * @param array $temp_id + */ + public function batchRemove(array $id,array $temp_id) + { + if($id) + ($this->getModel())::getDB()->where($this->getPk(),'in',$id)->delete(); + if($temp_id) + ($this->getModel())::getDB()->where('temp_id','in',$temp_id)->delete(); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + * @return mixed + */ + public function insertAll(array $data) + { + return ($this->getModel()::getDB())->insertAll($data); + } +} diff --git a/app/common/dao/store/shipping/ShippingTemplateRegionDao.php b/app/common/dao/store/shipping/ShippingTemplateRegionDao.php new file mode 100644 index 00000000..856ef566 --- /dev/null +++ b/app/common/dao/store/shipping/ShippingTemplateRegionDao.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use think\facade\Db; +use app\common\dao\BaseDao; +use app\common\model\store\shipping\ShippingTemplateRegion as model; + +class ShippingTemplateRegionDao extends BaseDao +{ + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists($field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where($field, $value)->count() > 0; + } + + /** + * 批量删除 + * @Author:Qinii + * @Date: 2020/5/8 + * @param array $id + * @param array $temp_id + */ + public function batchRemove(array $id,array $temp_id) + { + if($id) + ($this->getModel())::getDB()->where($this->getPk(),'in',$id)->delete(); + if($temp_id) + ($this->getModel())::getDB()->where('temp_id','in',$temp_id)->delete(); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + * @return mixed + */ + public function insertAll(array $data) + { + return ($this->getModel()::getDB())->insertAll($data); + } + +} diff --git a/app/common/dao/store/shipping/ShippingTemplateUndeliveryDao.php b/app/common/dao/store/shipping/ShippingTemplateUndeliveryDao.php new file mode 100644 index 00000000..221c5589 --- /dev/null +++ b/app/common/dao/store/shipping/ShippingTemplateUndeliveryDao.php @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\store\shipping; + +use app\common\dao\BaseDao; +use app\common\model\store\shipping\ShippingTemplateUndelivery as model; + +class ShippingTemplateUndeliveryDao extends BaseDao +{ + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $field + * @param $value + * @param null $except + * @return bool + */ + public function merFieldExists($field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where($field, $value)->count() > 0; + } + + + /** + * 批量删除 + * @Author:Qinii + * @Date: 2020/5/8 + * @param array $id + * @param array $temp_id + */ + public function batchRemove(array $id,array $temp_id) + { + if($id) + ($this->getModel())::getDB()->where($this->getPk(),'in',$id)->delete(); + if($temp_id) + ($this->getModel())::getDB()->where('temp_id','in',$temp_id)->delete(); + } +} diff --git a/app/common/dao/system/CacheDao.php b/app/common/dao/system/CacheDao.php new file mode 100644 index 00000000..64bf47aa --- /dev/null +++ b/app/common/dao/system/CacheDao.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\Cache; +use think\db\exception\DbException; + +/** + * Class CacheDao + * @package app\common\dao\system + * @author xaboy + * @day 2020-04-24 + */ +class CacheDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Cache::class; + } + + /** + * @param $key + * @return mixed + * @author xaboy + * @day 2020-04-24 + */ + public function getResult($key) + { + $val = Cache::getDB()->where('key', $key)->value('result'); + return $val ? json_decode($val, true) : null; + } + + /** + * @param string $key + * @param $data + * @throws DbException + * @author xaboy + * @day 2020-04-24 + */ + public function keyUpdate(string $key, $data) + { + if (isset($data['result'])) + $data['result'] = json_encode($data['result'], JSON_UNESCAPED_UNICODE); + Cache::getDB()->where('key', $key)->update($data); + } + + public function search(array $keys) + { + $cache = $this->getModel()::getDB()->whereIn('key',$keys)->column('result','key'); + $ret = []; + + foreach ($cache as $k => $v) { + $ret[$k] = json_decode($v); + } + return $ret; + } + + +} diff --git a/app/common/dao/system/ExtendDao.php b/app/common/dao/system/ExtendDao.php new file mode 100644 index 00000000..6bfd6f75 --- /dev/null +++ b/app/common/dao/system/ExtendDao.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\Extend; + +/** + * Class ExtendDao + * @package app\common\dao\system + * @author xaboy + * @day 2020-04-24 + */ +class ExtendDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Extend::class; + } + + public function search(array $where) + { + return Extend::getDB()->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('extend_value', "%{$where['keyword']}%"); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('extend_type', $where['type']); + })->when(isset($where['link_id']) && $where['link_id'] !== '', function ($query) use ($where) { + $query->where('link_id', (int)$where['link_id']); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', (int)$where['mer_id']); + }); + } + +} diff --git a/app/common/dao/system/RelevanceDao.php b/app/common/dao/system/RelevanceDao.php new file mode 100644 index 00000000..abeadb4f --- /dev/null +++ b/app/common/dao/system/RelevanceDao.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system; + +use app\common\dao\BaseDao; +use app\common\model\system\Relevance; +use app\common\repositories\system\RelevanceRepository; + +class RelevanceDao extends BaseDao +{ + + protected function getModel(): string + { + return Relevance::class; + } + + public function clear(int $id, $type, string $field) + { + if (is_string($type)) $type = [$type]; + return $this->getModel()::getDb()->where($field, $id)->whereIn('type', $type)->delete(); + } + + + public function joinUser($where) + { + $query = Relevance::hasWhere('community',function($query) use($where){ + $query->where('status',1)->where('is_show',1)->where('is_del',0); + $query->when(isset($where['is_type']) && $where['is_type'] !== '',function($query) use($where){ + $query->where('is_type',$where['is_type']); + }); + }); + + $query->where('left_id',$where['uid'])->where('type',RelevanceRepository::TYPE_COMMUNITY_START); + return $query; + } + + +} diff --git a/app/common/dao/system/admin/AdminDao.php b/app/common/dao/system/admin/AdminDao.php new file mode 100644 index 00000000..33ad7b5c --- /dev/null +++ b/app/common/dao/system/admin/AdminDao.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\admin; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\admin\Admin; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +class AdminDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Admin::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-04-09 + */ + public function search(array $where = [], $is_del = 0,$level = true) + { + $query = Admin::getDB(); + if($level) $query->where('level', '<>', 0); + $query->when($is_del !== null, function ($query) use ($is_del) { + $query->where('is_del', $is_del); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + }); + if (isset($where['keyword']) && $where['keyword'] !== '') { + $query = $query->whereLike('real_name|account', '%' . $where['keyword'] . '%'); + } + if (isset($where['status']) && $where['status'] !== '') { + $query = $query->where('status', intval($where['status'])); + } + return $query; + } + + public function exists(int $id) + { + $query = ($this->getModel())::getDB()->where($this->getPk(), $id)->where('is_del', 0); + return $query->count() > 0; + } + + + /** + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function get( $id) + { + return Admin::getInstance()->where('is_del', 0)->find($id); + } + + + /** + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-30 + */ + public function fieldExists($field, $value, ?int $except = null): bool + { + $query = ($this->getModel())::getDB()->where($field, $value)->where('is_del', 0); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->count() > 0; + } + + /** + * @param string $account + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function accountByAdmin(string $account) + { + return Admin::getInstance()->where('account', $account) + ->where('is_del', 0) + ->field(['account', 'pwd', 'real_name', 'login_count', 'admin_id', 'status']) + ->find(); + } +} + diff --git a/app/common/dao/system/admin/LogDao.php b/app/common/dao/system/admin/LogDao.php new file mode 100644 index 00000000..c8b52947 --- /dev/null +++ b/app/common/dao/system/admin/LogDao.php @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\admin; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\admin\Log; +use think\db\BaseQuery; + +/** + * Class LogDao + * @package app\common\dao\system\admin + * @author xaboy + * @day 2020-04-16 + */ +class LogDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Log::class; + } + + /** + * @param array $where + * @param $merId + * @return BaseQuery + * @author xaboy + * @day 2020-04-16 + */ + public function search(array $where, $merId) + { + $query = Log::getDB()->where('mer_id', $merId)->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + }); + if (isset($where['method']) && $where['method'] !== '') $query->where('method', $where['method']); + if (isset($where['admin_id']) && $where['admin_id'] !== '') $query->where('admin_id', $where['admin_id']); + if (isset($where['section_startTime']) && $where['section_startTime'] && isset($where['section_endTime']) && $where['section_endTime']) + $query->where('create_time', '>', $where['section_startTime'])->where('create_time', '<', $where['section_endTime']); + + return $query; + } +} diff --git a/app/common/dao/system/attachment/AttachmentCategoryDao.php b/app/common/dao/system/attachment/AttachmentCategoryDao.php new file mode 100644 index 00000000..a73e46ec --- /dev/null +++ b/app/common/dao/system/attachment/AttachmentCategoryDao.php @@ -0,0 +1,183 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\attachment; + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\attachment\AttachmentCategory; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\Model; + +/** + * Class AttachmentCategoryDao + * @package app\common\dao\system\attachment + * @author xaboy + * @day 2020-04-22 + */ +class AttachmentCategoryDao extends BaseDao +{ + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return AttachmentCategory::class; + } + + /** + * @param int $mer_id + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function getAll($mer_id = 0) + { + return AttachmentCategory::getDB()->where('mer_id', $mer_id)->order('sort DESC')->select(); + } + + /** + * 通过 $attachmentCategoryEName 获取主键 + * @param string $attachmentCategoryEName 需要检测的数据 + * @return int + * @author 张先生 + * @date 2020-03-30 + */ + public function getPkByAttachmentCategoryEName($attachmentCategoryEName) + { + return AttachmentCategory::getInstance()->where('attachment_category_enname', $attachmentCategoryEName)->value($this->getPk()); + } + + /** + * 通过id 获取path + * @param int $id 需要检测的数据 + * @return string + * @author 张先生 + * @date 2020-03-30 + */ + public function getPathById($id) + { + return AttachmentCategory::getInstance()->where($this->getPk(), $id)->value('path'); + } + + /** + * 通过id获取所有子集的id + * @param int $id 需要检测的数据 + * @return array + * @author 张先生 + * @date 2020-03-30 + */ + public function getIdListContainsPath($id) + { + return AttachmentCategory::getInstance() + ->where($this->getPk(), $id) + ->whereOrRaw("locate ('/{$id}/', path)") + ->column($this->getPk()); + } + + /** + * @param int $mer_id + * @return array + * @author xaboy + * @day 2020-04-20 + */ + public function getAllOptions($mer_id = 0) + { + return AttachmentCategory::getDB()->where('mer_id', $mer_id)->order('sort DESC')->column('pid,attachment_category_name', 'attachment_category_id'); + } + + /** + * @param int $merId + * @param int $id + * @param null $except + * @return bool + * @author xaboy + * @day 2020-04-15 + */ + public function merExists(int $merId, int $id, $except = null) + { + return $this->merFieldExists($merId, $this->getPk(), $id, $except); + } + + /** + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + * @author xaboy + * @day 2020-04-15 + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where('mer_id', $merId)->where($field, $value)->count() > 0; + } + + + /** + * @param int $id + * @param int $merId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function get($id, $merId = 0) + { + return ($this->getModel())::getDB()->where('mer_id', $merId)->find($id); + } + + /** + * @param int $id + * @param int $merId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-15 + */ + public function delete(int $id, $merId = 0) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->where('mer_id', $merId)->delete(); + } + + /** + * @param string $oldPath + * @param string $path + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-30 + */ + public function updatePath(string $oldPath, string $path) + { + AttachmentCategory::getDB()->whereLike('path', $oldPath . '%')->field('attachment_category_id,path')->select()->each(function ($val) use ($oldPath, $path) { + $newPath = str_replace($oldPath, $path, $val['path']); + if (substr_count(trim($newPath, '/'), '/') > 1) throw new ValidateException('素材分类最多添加三级'); + AttachmentCategory::getDB()->where('attachment_category_id', $val['attachment_category_id'])->update(['path' => $newPath]); + }); + } +} diff --git a/app/common/dao/system/attachment/AttachmentDao.php b/app/common/dao/system/attachment/AttachmentDao.php new file mode 100644 index 00000000..f3119dc3 --- /dev/null +++ b/app/common/dao/system/attachment/AttachmentDao.php @@ -0,0 +1,140 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\attachment; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\attachment\Attachment; +use crmeb\services\UploadService; +use think\db\BaseQuery; +use think\db\exception\DbException; +use think\Exception; +use think\facade\Log; + +/** + * Class AttachmentDao + * @package app\common\dao\system\attachment + * @author xaboy + * @day 2020-04-16 + */ +class AttachmentDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Attachment::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-04-15 + */ + public function search(array $where) + { + $query = Attachment::getDB()->order('create_time DESC'); + if (isset($where['user_type'])) $query->where('user_type', (int)$where['user_type']); + if (isset($where['upload_type'])) $query->where('upload_type', (int)$where['upload_type']); + if (isset($where['attachment_category_id']) && $where['attachment_category_id']) + $query->where('attachment_category_id', (int)$where['attachment_category_id']); + if (isset($where['attachment_name']) && $where['attachment_name']) + $query->whereLike('attachment_name', "%{$where['attachment_name']}%"); + + $query->order('create_time DESC'); + + return $query; + } + + /** + * @param int $id + * @param int $userType + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-16 + */ + public function delete(int $id, $userType = 0) + { + return ($this->getModel())::getDB()->where('user_type', $userType)->where($this->getPk(), $id)->delete(); + } + + /** + * @param array $ids + * @param int $userType + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-15 + */ + public function batchDelete(array $ids, $userType = 0) + { + $data = ($this->getModel())::getDB()->whereIn($this->getPk(), $ids)->select(); + foreach ($data as $datum) { + try { + if ($datum['upload_type'] < 1) { + $url = systemConfig('site_url'); + $info = str_replace($url, '', $datum['attachment_src']); + $key = public_path() . $info; + } else { + $info = parse_url($datum['attachment_src']); + $key = ltrim($info['path'], '/'); + } + $upload = UploadService::create($datum['upload_type']); + $upload->delete($key); + } catch (Exception $e) { + Log::info('删除存储图片失败,类型:' . $datum['upload_type'] . ',KEY:' . $key); + } + } + return ($this->getModel())::getDB()->where('user_type', $userType)->whereIn($this->getPk(), $ids)->delete(); + } + + /** + * @param int $id + * @param int $userType + * @return bool + * @author xaboy + * @day 2020-04-16 + */ + public function exists(int $id, $userType = 0) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->count() > 0; + } + + /** + * @param array $ids + * @param array $data + * @param int $user_type + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-16 + */ + public function batchChange(array $ids, array $data, int $user_type = 0) + { + return ($this->getModel())::getDB()->where('user_type', $user_type)->whereIn($this->getPk(), $ids)->update($data); + } + + public function clearCache() + { + return Attachment::getDB()->where('user_type', -1)->delete(); + } +} + diff --git a/app/common/dao/system/config/SystemConfigClassifyDao.php b/app/common/dao/system/config/SystemConfigClassifyDao.php new file mode 100644 index 00000000..01cfe07b --- /dev/null +++ b/app/common/dao/system/config/SystemConfigClassifyDao.php @@ -0,0 +1,176 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\config; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\config\SystemConfigClassify; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class SystemConfigClassifyDao + * @package app\common\dao\system\config + * @author xaboy + * @day 2020-03-27 + */ +class SystemConfigClassifyDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return SystemConfigClassify::class; + } + + /** + * @return array + * @author xaboy + * @day 2020-03-27 + */ + public function getOptions() + { + return SystemConfigClassify::column('pid,classify_name', 'config_classify_id'); + } + + /** + * @return array + * @author xaboy + * @day 2020-04-22 + */ + public function getTopOptions() + { + return SystemConfigClassify::getDB()->where('pid', 0)->column('classify_name', 'config_classify_id'); + } + + public function search(array $where) + { + return SystemConfigClassify::getDB()->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + })->when(isset($where['classify_name']) && $where['classify_name'] !== '', function ($query) use ($where) { + $query->where('classify_name', 'LIKE', "%{$where['classify_name']}%"); + }); + } + + /** + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function all() + { + return SystemConfigClassify::getDB()->select(); + } + + /** + * @return int + * @author xaboy + * @day 2020-03-31 + */ + public function count() + { + return SystemConfigClassify::getDB()->count(); + } + + /** + * @param int $pid + * @param string $field + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function children(int $pid, string $field = 'config_classify_id,classify_name') + { + return SystemConfigClassify::getDB()->where('pid', $pid)->field($field)->select(); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function existsChild(int $id): bool + { + return $this->fieldExists('pid', $id); + } + + /** + * @param $key + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function keyExists($key, ?int $except = null): bool + { + return $this->fieldExists('classify_key', $key, $except); + } + + /** + * @param int $pid + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function pidExists(int $pid, ?int $except = null): bool + { + return $this->fieldExists('config_classify_id', $pid, $except); + } + + /** + * @param string $key + * @return mixed + * @author xaboy + * @day 2020-04-22 + */ + public function keyById(string $key) + { + return SystemConfigClassify::getDB()->where('classify_key', $key)->value('config_classify_id'); + } + + /** + * @param string $key + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-22 + */ + public function keyByData(string $key) + { + return SystemConfigClassify::getDB()->where('classify_key', $key)->find(); + } + + public function getOption() + { + return SystemConfigClassify::column('classify_name,pid,config_classify_id'); + } +} diff --git a/app/common/dao/system/config/SystemConfigDao.php b/app/common/dao/system/config/SystemConfigDao.php new file mode 100644 index 00000000..61768c91 --- /dev/null +++ b/app/common/dao/system/config/SystemConfigDao.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\config; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\config\SystemConfig; +use think\Collection; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class SystemConfigDao + * @package app\common\dao\system\config + * @author xaboy + * @day 2020-03-27 + */ +class SystemConfigDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return SystemConfig::class; + } + + /** + * @param int $classify_id + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function classifyIdExists(int $classify_id) + { + return $this->fieldExists('config_classify_id', $classify_id); + } + + /** + * @param $key + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function keyExists($key, ?int $except = null): bool + { + return $this->fieldExists('config_key', $key, $except); + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-03-31 + */ + public function search(array $where) + { + $query = SystemConfig::getDB(); + if (isset($where['keyword']) && $where['keyword'] !== '' ) + $query->whereLike('config_name|config_key', '%' . $where['keyword'] . '%'); + if (isset($where['pid']) && $where['pid'] !== '') + $query->where('config_classify_id', $where['pid']); + if (isset($where['config_classify_id']) && $where['config_classify_id'] !== '') + $query->where('config_classify_id', $where['config_classify_id']); + if (isset($where['user_type']) && $where['user_type'] !== '') + $query->where('user_type', $where['user_type']); + return $query; + } + + /** + * @param int $cid + * @param int $user_type + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-23 + */ + public function cidByConfig(int $cid, int $user_type) + { + return SystemConfig::getDB()->where('config_classify_id', $cid)->where('user_type', $user_type)->where('status', 1) + ->order('sort DESC, config_id ASC')->select(); + } + + /** + * @param int|array $cid + * @param $keys + * @return array + * @author xaboy + * @day 2020-04-22 + */ + public function intersectionKey($cid, $keys): array + { + return SystemConfig::where('config_classify_id', is_array($cid) ? 'IN' : '=', $cid)->whereIn('config_key', $keys)->where('status', 1)->column('config_type,config_name', 'config_key'); + } + + +} diff --git a/app/common/dao/system/config/SystemConfigValueDao.php b/app/common/dao/system/config/SystemConfigValueDao.php new file mode 100644 index 00000000..1bbb690e --- /dev/null +++ b/app/common/dao/system/config/SystemConfigValueDao.php @@ -0,0 +1,115 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\config; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\config\SystemConfigValue; +use think\db\exception\DbException; + +/** + * Class SystemConfigValueDao + * @package app\common\dao\system\config + * @author xaboy + * @day 2020-03-27 + */ +class SystemConfigValueDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return SystemConfigValue::class; + } + + /** + * @param int $merId + * @param string $key + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function merUpdate(int $merId, string $key, array $data) + { + if (isset($data['value'])) $data['value'] = json_encode($data['value']); + return SystemConfigValue::getDB()->where('mer_id', $merId)->where('config_key', $key)->update($data); + } + + /** + * @param array $keys + * @param int $merId + * @return array + * @author xaboy + * @day 2020-04-22 + */ + public function fields(array $keys, int $merId) + { + $result = SystemConfigValue::getDB()->whereIn('config_key', $keys)->where('mer_id', $merId)->withAttr('value', function ($val, $data) { + return json_decode($val, true); + })->column('value', 'config_key'); + foreach ($result as $k => $val) { + $result[$k] = json_decode($val, true); + } + return $result; + } + + /** + * @param array $keys + * @param int $merId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-18 + */ + public function clear(array $keys, int $merId) + { + return SystemConfigValue::getDB()->whereIn('config_key', $keys)->where('mer_id', $merId)->delete(); + } + + + /** + * @param string $key + * @param int $merId + * @return mixed|null + * @author xaboy + * @day 2020-05-08 + */ + public function value(string $key, int $merId) + { + $value = SystemConfigValue::getDB()->where('config_key', $key)->where('mer_id', $merId)->value('value'); + $value = is_null($value) ? null : json_decode($value, true); + return $value; + } + + /** + * @param string $key + * @param int $merId + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function merExists(string $key, int $merId): bool + { + return SystemConfigValue::getDB()->where('config_key', $key)->where('mer_id', $merId)->count() > 0; + } + + +} diff --git a/app/common/dao/system/diy/DiyDao.php b/app/common/dao/system/diy/DiyDao.php new file mode 100644 index 00000000..06ffca24 --- /dev/null +++ b/app/common/dao/system/diy/DiyDao.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\diy; + +use app\common\dao\BaseDao; +use app\common\model\system\diy\Diy; +use think\facade\Db; + +class DiyDao extends BaseDao +{ + + protected function getModel(): string + { + return Diy::class; + } + + public function setUsed($id, $merId) + { + $res = $this->getModel()::getDb()->find($id); + $this->getModel()::getDb()->where('mer_id', $merId)->where('is_default' ,0)->update(['status'=>0]); + if (!$res['is_default']) { + $this->getModel()::getDb()->where('mer_id', $merId)->where('id',$id)->update(['status'=> 1]); + } + } + public function merExists(int $merId, int $id) + { + return ($this->getModel()::getDb()->where('mer_id', $merId)->where($this->getPk(), $id)->count() > 0 ); + } + +} diff --git a/app/common/dao/system/diy/PageCategoryDao.php b/app/common/dao/system/diy/PageCategoryDao.php new file mode 100644 index 00000000..b44f476b --- /dev/null +++ b/app/common/dao/system/diy/PageCategoryDao.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\diy; + +use app\common\dao\BaseDao; +use app\common\model\system\diy\PageCategory; +use app\common\model\system\diy\PageLink; + +class PageCategoryDao extends BaseDao +{ + + protected function getModel(): string + { + return PageCategory::class; + } + +} diff --git a/app/common/dao/system/diy/PageLinkDao.php b/app/common/dao/system/diy/PageLinkDao.php new file mode 100644 index 00000000..2ff224b1 --- /dev/null +++ b/app/common/dao/system/diy/PageLinkDao.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\diy; + +use app\common\dao\BaseDao; +use app\common\model\system\diy\PageLink; + +class PageLinkDao extends BaseDao +{ + + protected function getModel(): string + { + return PageLink::class; + } + +} diff --git a/app/common/dao/system/financial/FinancialDao.php b/app/common/dao/system/financial/FinancialDao.php new file mode 100644 index 00000000..959bcd3e --- /dev/null +++ b/app/common/dao/system/financial/FinancialDao.php @@ -0,0 +1,82 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\financial; + + +use app\common\dao\BaseDao; +use app\common\model\system\financial\Financial; + +class FinancialDao extends BaseDao +{ + + protected function getModel(): string + { + return Financial::class; + } + + public function search(array $where) + { + $query = Financial::hasWhere('merchant',function($query) use ($where){ + $query->when(isset($where['is_trader']) && $where['is_trader'] !=='',function($query) use($where){ + $query->where('is_trader',$where['is_trader']); + }); + $query->when(isset($where['type_id']) && $where['type_id'] !=='',function($query) use($where){ + $query->where('type_id',$where['type_id']); + }); + $query->when(isset($where['category_id']) && $where['category_id'] !=='',function($query) use($where){ + $query->where('category_id',$where['category_id']); + }); + $query->where('is_del',0); + }); + + $query->when(isset($where['status']) && $where['status'] !=='',function($query) use($where){ + $query->where('Financial.status',$where['status']); + }) + ->when(isset($where['financial_type']) && $where['financial_type'] !=='',function($query) use($where){ + $query->where('Financial.financial_type',$where['financial_type']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !=='',function($query) use($where){ + $query->where('Financial.mer_id',$where['mer_id']); + }) + ->when(isset($where['financial_status']) && $where['financial_status'] !=='',function($query) use($where){ + $query->where('Financial.financial_status',$where['financial_status']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !=='',function($query) use($where){ + $query->join('SystemAdmin A','Financial.admin_id = A.admin_id') + ->field('A.real_name,A.admin_id,A.account') + ->whereLike('A.real_name|A.account',"%{$where['keyword']}%"); + }) + ->when(isset($where['keywords_']) && $where['keywords_'] !=='',function($query) use($where){ + $query->join('MerchantAdmin M','Financial.mer_admin_id = M.merchant_admin_id') + ->field('M.real_name,M.account,M.merchant_admin_id') + ->whereLike('M.real_name|M.account',"%{$where['keywords_']}%"); + }) + ->when(isset($where['financial_id']) && $where['financial_id'] !=='',function($query) use($where){ + $query->where('Financial.financial_id',$where['financial_id']); + }) + ->when(isset($where['date']) && $where['date'] !=='',function($query) use($where){ + getModelTime($query,$where['date'],'Financial.create_time'); + }) + ->when(isset($where['is_del']) && $where['is_del'] !=='',function($query) use($where){ + $query->where('Financial.is_del',$where['is_del']); + }) + ->when(isset($where['type']) && $where['type'] !=='',function($query) use($where){ + $query->where('Financial.type',$where['type']); + });; + $query->order('Financial.create_time DESC'); + + return $query; + } + +} diff --git a/app/common/dao/system/groupData/GroupDao.php b/app/common/dao/system/groupData/GroupDao.php new file mode 100644 index 00000000..cb8cdf1d --- /dev/null +++ b/app/common/dao/system/groupData/GroupDao.php @@ -0,0 +1,114 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\groupData; + + +use app\common\dao\BaseDao; +use app\common\model\system\groupData\SystemGroup; +use think\Collection; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + + +/** + * Class GroupDao + * @package app\common\dao\system\groupData + * @author xaboy + * @day 2020-03-27 + */ +class GroupDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return SystemGroup::class; + } + + + /** + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-01 + */ + public function all() + { + return SystemGroup::getDB()->select(); + } + + /** + * @return int + * @author xaboy + * @day 2020-04-01 + */ + public function count() + { + return SystemGroup::getDB()->count(); + } + + /** + * @param $page + * @param $limit + * @return BaseQuery + * @author xaboy + * @day 2020-04-01 + */ + public function page($page, $limit) + { + return SystemGroup::getDB()->page($page, $limit); + } + + /** + * @param $key + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-27 + */ + public function keyExists($key, ?int $except = null): bool + { + return parent::fieldExists('group_key', $key, $except); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020-04-02 + */ + public function fields($id, $field = 'group_id') + { + return json_decode(SystemGroup::getDB()->where($field, $id)->value('fields'), true); + } + + /** + * @param string $key + * @return mixed + * @author xaboy + * @day 2020/5/27 + */ + public function keyById(string $key) + { + return SystemGroup::getDB()->where('group_key', $key)->value('group_id'); + } +} diff --git a/app/common/dao/system/groupData/GroupDataDao.php b/app/common/dao/system/groupData/GroupDataDao.php new file mode 100644 index 00000000..0e221796 --- /dev/null +++ b/app/common/dao/system/groupData/GroupDataDao.php @@ -0,0 +1,184 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\groupData; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\groupData\SystemGroupData; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class GroupDataDao + * @package app\common\dao\system\groupData + * @author xaboy + * @day 2020-03-27 + */ +class GroupDataDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return SystemGroupData::class; + } + + /** + * @param $merId + * @param $groupId + * @return BaseQuery + * @author xaboy + * @day 2020-03-30 + */ + public function getGroupDataWhere($merId, $groupId): BaseQuery + { + return SystemGroupData::getDB()->withAttr('value', function ($val) { + return json_decode($val, true); + })->where('mer_id', $merId)->where('group_id', $groupId)->order('sort DESC'); + } + + /** + * @param $merId + * @param $groupId + * @param int|null $page + * @param int|null $limit + * @return array + * @author xaboy + * @day 2020/5/27 + */ + public function getGroupData($merId, $groupId, ?int $page = null, ?int $limit = 10) + { + $query = SystemGroupData::getDB() + ->where('mer_id', $merId)->where('group_id', $groupId) + ->where('status', 1) + ->where('') + ->order('sort DESC'); + + if (!is_null($page)) $query->page($page, $limit); + $groupData = []; + foreach ($query->column('value,mer_id', 'group_data_id') as $k => $v) { + $groupData[] = json_decode($v['value'], true) + ['group_data_id' => $k, 'group_mer_id' => $v['mer_id']]; + } + return $groupData; + } + + public function getData($id) + { + $res = SystemGroupData::getDB()->where('group_data_id', (int)$id)->find(); + if (!$res) return null; + return $res['value'] + ['group_data_id' => $res['group_data_id'], 'group_mer_id' => $res['mer_id']]; + } + + public function groupDataCount($merId, $groupId) + { + return SystemGroupData::getDB()->where('mer_id', $merId)->where('group_id', $groupId)->where('status', 1)->count(); + } + + /** + * @param $merId + * @param $groupId + * @param int|null $page + * @param int|null $limit + * @return array + * @author xaboy + * @day 2020/6/3 + */ + public function getGroupDataId($merId, $groupId, ?int $page = null, ?int $limit = 10) + { + $query = SystemGroupData::getDB()->where('mer_id', $merId)->where('group_id', $groupId)->where('status', 1)->order('sort DESC'); + if (!is_null($page)) $query->page($page, $limit); + $groupData = []; + foreach ($query->column('value', 'group_data_id') as $k => $v) { + $groupData[] = ['id' => $k, 'data' => json_decode($v, true)]; + } + return $groupData; + } + + /** + * @param $merId + * @param $id + * @param $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-30 + */ + public function merUpdate($merId, $id, $data) + { + $data['value'] = json_encode($data['value']); + return SystemGroupData::getDB()->where('group_data_id', $id)->where('mer_id', $merId)->update($data); + } + + /** + * @param $merId + * @param $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-30 + */ + public function merDelete($merId, $id) + { + return SystemGroupData::getDB()->where('mer_id', $merId)->where('group_data_id', $id)->delete(); + } + + /** + * @param int $merId + * @param int $id + * @return bool + * @author xaboy + * @day 2020-04-02 + */ + public function merExists(int $merId, int $id) + { + return ($this->getModel())::getDB()->where('mer_id', $merId)->where($this->getPk(), $id)->count() > 0; + } + + /** + * @param int $groupId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-16 + */ + public function clearGroup(int $groupId) + { + return SystemGroupData::getDB()->where('group_id', $groupId)->delete(); + } + + /** + * @param $id + * @param $merId + * @return array|Model|null + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/2 + */ + public function merGet($id, $merId) + { + $data = SystemGroupData::getDB()->where('group_data_id', $id)->where('mer_id', $merId)->find(); + return $data ? $data['value'] : null; + } + +} diff --git a/app/common/dao/system/menu/MenuDao.php b/app/common/dao/system/menu/MenuDao.php new file mode 100644 index 00000000..7739185f --- /dev/null +++ b/app/common/dao/system/menu/MenuDao.php @@ -0,0 +1,395 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\menu; + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\auth\Menu; +use app\common\repositories\system\RelevanceRepository; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class MenuDao + * @package app\common\dao\system\menu + * @author xaboy + * @day 2020-04-08 + */ +class MenuDao extends BaseDao +{ + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Menu::class; + } + + /** + * @param array $where + * @param int $is_mer + * @return BaseQuery + * @author xaboy + * @day 2020-04-08 + */ + public function search(array $where, int $is_mer = 0) + { + $query = Menu::getDB()->where('is_mer', $is_mer)->order('sort DESC,menu_id ASC'); + if (isset($where['pid'])) $query->where('pid', (int)$where['pid']); + if (isset($where['keyword'])) $query->whereLike('menu_name|route', "%{$where['keyword']}%"); + if (isset($where['is_menu'])) $query->where('is_menu', (int)$where['is_menu']); + return $query; + } + + + /** + * @param int $is_mer + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-08 + */ + public function getAllMenu($is_mer = 0) + { + return Menu::getDB()->where('is_mer', $is_mer)->where('is_menu', 1)->order('sort DESC,menu_id ASC')->select()->toArray(); + } + + /** + * @param int $is_mer + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-08 + */ + public function getAll($is_mer = 0) + { + return Menu::getInstance()->where('is_mer', $is_mer)->order('sort DESC,menu_id ASC')->select()->toArray(); + } + + /** + * @param int $id + * @param int $is_mer + * @return bool + * @author xaboy + * @day 2020-04-08 + */ + public function menuExists(int $id, $is_mer = 0) + { + return Menu::getDB()->where($this->getPk(), $id)->where('is_menu', 1)->where('is_mer', $is_mer)->count() > 0; + } + + /** + * @param int $id + * @param int $is_mer + * @return bool + * @author xaboy + * @day 2020-04-16 + */ + public function merExists(int $id, $is_mer = 0) + { + return Menu::getDB()->where($this->getPk(), $id)->where('is_mer', $is_mer)->count() > 0; + } + + /** + * @param int $id + * @param int $is_mer + * @return bool + * @author xaboy + * @day 2020-04-08 + */ + public function authExists(int $id, $is_mer = 0) + { + return Menu::getDB()->where($this->getPk(), $id)->where('is_menu', 0)->where('is_mer', $is_mer)->count() > 0; + } + + /** + * @param string $route + * @param int $is_mer + * @return bool + * @author xaboy + * @day 2020-04-08 + */ + public function routeExists(string $route, $is_mer = 0) + { + return Menu::getDB()->where('route', $route)->where('is_menu', 0)->where('is_mer', $is_mer)->count() > 0; + } + + /** + * @param int $is_mer + * @return array + * @author xaboy + * @day 2020-04-08 + */ + public function getAllMenuOptions($is_mer = 0) + { + return Menu::getDB()->where('is_menu', 1)->where('is_mer', $is_mer)->order('sort DESC,menu_id ASC')->column('menu_name,pid', 'menu_id'); + } + + /** + * @param array $rule + * @param int $is_mer + * @return array + * @author xaboy + * @day 2020-04-10 + */ + public function ruleByMenuList(array $rule, $is_mer = 0) + { + $paths = Menu::getDB()->whereIn($this->getPk(), $rule)->column('path', 'menu_id'); + $ids = []; + foreach ($paths as $id => $path) { + $ids = array_merge($ids, explode('/', trim($path, '/'))); + array_push($ids, $id); + } + return Menu::getDB()->where('is_menu', 1)->where('is_show', 1)->order('sort DESC,menu_id ASC')->where('is_mer', $is_mer) + ->whereIn('menu_id', array_unique(array_filter($ids))) + ->column('menu_name,route,params,icon,pid,menu_id'); + } + + /** + * @param int $is_mer + * @return array + * @author xaboy + * @day 2020-04-10 + */ + public function getValidMenuList($is_mer = 0) + { + return Menu::getDB()->where('is_menu', 1)->where('is_show', 1)->order('sort DESC,menu_id ASC')->where('is_mer', $is_mer) + ->column('menu_name,route,params,icon,pid,menu_id'); + } + + public function typesByValidMenuList($typeId) + { + $paths = Menu::getDB()->alias('A')->leftJoin('Relevance B', 'A.menu_id = B.right_id')->where('is_menu', 1)->where('is_show', 1) + ->order('sort DESC,menu_id ASC') + ->where('B.left_id', $typeId)->where('B.type', RelevanceRepository::TYPE_MERCHANT_AUTH) + ->column('path', 'menu_id'); + $ids = []; + foreach ($paths as $id => $path) { + $ids = array_merge($ids, explode('/', trim($path, '/'))); + array_push($ids, $id); + } + return Menu::getDB()->where('is_menu', 1)->where('is_show', 1)->order('sort DESC,menu_id ASC')->where('is_mer', 1) + ->whereIn('menu_id', array_unique(array_filter($ids))) + ->column('menu_name,route,params,icon,pid,menu_id'); + } + + /** + * @param int $is_mer + * @return array + * @author xaboy + * @day 2020-04-08 + */ + public function getAllOptions($is_mer = 0, $all = false, $where = [], $filed = 'menu_name,pid') + { + return Menu::getDB()->where('is_mer', $is_mer ? 1 : 0) + ->when(isset($where['ids']) && !empty($where['ids']), function($query) use($where) { + $query->whereIn('menu_id', $where['ids']); + }) + ->when(!$all, function ($query) { + $query->where(function ($query) { + $query->where(function ($query) { + $query->where('is_show', 1)->where('is_menu', 1); + })->whereOr('is_menu', 0); + }); + }) + ->order('sort DESC,menu_id ASC')->column($filed, 'menu_id'); + } + + public function merchantTypeByOptions($typeId, $all = false) + { + return Menu::getDB()->alias('A')->leftJoin('Relevance B', 'A.menu_id = B.right_id')->where('is_mer', 1) + ->where('B.left_id', $typeId)->where('B.type', RelevanceRepository::TYPE_MERCHANT_AUTH)->when(!$all, function ($query) { + $query->where(function ($query) { + $query->where(function ($query) { + $query->where('is_show', 1)->where('is_menu', 1); + })->whereOr('is_menu', 0); + }); + })->order('sort DESC,menu_id ASC')->column('menu_name,pid', 'menu_id'); + } + + /** + * @param $id + * @param int $is_mer + * @return mixed + * @author xaboy + * @day 2020-04-09 + */ + public function getPath($id, $is_mer = 0) + { + return Menu::getDB()->where('is_mer', $is_mer)->where('menu_id', $id)->value('path'); + } + + /** + * @param int $id + * @param int $is_mer + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-08 + */ + public function getMenu(int $id, $is_mer = 0) + { + return Menu::getDB()->where('is_mer', $is_mer)->where('is_menu', 1)->where($this->getPk(), $id)->find(); + } + + /** + * @param int $id + * @param int $is_mer + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-08 + */ + public function getAuth(int $id, $is_mer = 0) + { + return Menu::getDB()->where('is_mer', $is_mer)->where('is_menu', 0)->where($this->getPk(), $id)->find(); + } + + /** + * @param int $id + * @param int $is_mer + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-08 + */ + public function delete(int $id, $is_mer = 0) + { + return Menu::getDB()->where('is_mer', $is_mer)->delete($id); + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020-04-08 + */ + public function pidExists(int $id) + { + return $this->fieldExists('pid', $id); + } + + /** + * @param array $ids + * @return array + * @author xaboy + * @day 2020-04-10 + */ + public function idsByRoutes(array $ids) + { + return Menu::getDB()->where('is_menu', 0)->whereIn($this->getPk(), $ids)->column('params,route'); + } + + public function typesByRoutes($typeId, array $ids) + { + return Menu::getDB()->alias('A')->leftJoin('Relevance B', 'A.menu_id = B.right_id')->where('is_menu', 0) + ->where('B.left_id', $typeId)->whereIn('B.right_id', $ids)->where('B.type', RelevanceRepository::TYPE_MERCHANT_AUTH)->column('params,route'); + } + + public function merchantTypeByRoutes($typeId) + { + return Menu::getDB()->alias('A')->leftJoin('Relevance B', 'A.menu_id = B.right_id')->where('is_menu', 0) + ->where('B.left_id', $typeId)->where('B.type', RelevanceRepository::TYPE_MERCHANT_AUTH)->column('params,route'); + } + + /** + * TODO 商户顶级管理员权限 + * @return array + * @author Qinii + * @day 9/6/21 + */ + public function merAdminRoutes() + { + return Menu::getDB()->where('is_menu', 0)->where('is_show', 1)->column('params,route'); + } + + /** + * @param string $oldPath + * @param string $path + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-30 + */ + public function updatePath(string $oldPath, string $path) + { + Menu::getDB()->whereLike('path', $oldPath . '%')->field('menu_id,path')->select()->each(function ($val) use ($oldPath, $path) { + $newPath = str_replace($oldPath, $path, $val['path']); + Menu::getDB()->where('menu_id', $val['menu_id'])->update(['path' => $newPath]); + }); + } + + /** + * @Author:Qinii + * @Date: 2020/5/26 + * @param $field + * @param $value + * @return array|Model|null + */ + public function getFieldExists($field,$value) + { + return (($this->getModel()::getDB())->where($field,$value)->find()); + } + + /** + * @Author:Qinii + * @Date: 2020/5/26 + * @param array $data + * @return int + */ + public function insertAll(array $data) + { + return ($this->getModel()::getDB())->insertAll($data); + } + + public function deleteCommandMenu($where) + { + $this->getModel()::getDB()->where($where)->delete(); + } + + public function all() + { + return ($this->getModel()::getDB())->select(); + } + + /** + * 根据每个路由分组获取是否存在父级 + * @Author:Qinii + * @Date: 2020/9/8 + * @param array $data + * @return mixed + */ + public function getMenuPid(string $route, $isMer, $isMenu) + { + return ($this->getModel()::getDB()) + ->where('route',$route) + ->where('is_mer',$isMer) + ->where('is_menu',$isMenu) + ->order('path ASC')->find(); + } +} diff --git a/app/common/dao/system/menu/RoleDao.php b/app/common/dao/system/menu/RoleDao.php new file mode 100644 index 00000000..0d14fe77 --- /dev/null +++ b/app/common/dao/system/menu/RoleDao.php @@ -0,0 +1,106 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\menu; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\auth\Role; + +/** + * Class RoleDao + * @package app\common\dao\system\menu + * @author xaboy + * @day 2020-04-18 + */ +class RoleDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return Role::class; + } + + /** + * @param $merId + * @param array $where + * @return BaseModel|Role + * @author xaboy + * @day 2020-04-18 + */ + public function search($merId, array $where = []) + { + $roleModel = Role::getInstance(); + + if (isset($where['role_name'])) { + $roleModel = $roleModel->whereLike('role_name', '%' . $where['role_name'] . '%'); + } + + if (isset($where['status'])) { + $roleModel = $roleModel->where('status', intval($where['status'])); + } + + if (isset($where['role_ids']) && $where['role_ids'] !== '') { + $roleModel = $roleModel->whereIn('role_id', $where['role_ids']); + } + + return $roleModel->where('mer_id', $merId); + } + + /** + * @param int $merId + * @return array + * @author xaboy + * @day 2020-04-18 + */ + public function getAllOptions(int $merId) + { + return Role::getDB()->where('status', 1)->where('mer_id', $merId)->column('role_name', 'role_id'); + } + + /** + * @param $merId + * @param array $ids + * @return array + * @author xaboy + * @day 2020-04-18 + */ + public function idsByRules($merId, array $ids) + { + $rules = Role::getDB()->where('status', 1)->where('mer_id', $merId)->whereIn($this->getPk(), $ids)->column('rules'); + $data = []; + foreach ($rules as $rule) { + $data = array_merge(explode(',', $rule), $data); + } + return array_unique($data); + } + + /** + * @param int $merId + * @param int $id + * @return bool + * @author xaboy + * @day 2020-04-18 + */ + public function merExists(int $merId, int $id) + { + return Role::getDB()->where($this->getPk(), $id)->where('mer_id', $merId)->count() > 0; + } +} + diff --git a/app/common/dao/system/merchant/FinancialRecordDao.php b/app/common/dao/system/merchant/FinancialRecordDao.php new file mode 100644 index 00000000..6d2b1323 --- /dev/null +++ b/app/common/dao/system/merchant/FinancialRecordDao.php @@ -0,0 +1,114 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\model\system\merchant\FinancialRecord; + +class FinancialRecordDao extends BaseDao +{ + + protected function getModel(): string + { + return FinancialRecord::class; + } + + /** + * @return string + * @author xaboy + * @day 2020/6/9 + */ + public function getSn() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = 'jy' . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + public function inc(array $data, $merId) + { + $data['mer_id'] = $merId; + $data['financial_pm'] = 1; + $data['financial_record_sn'] = $this->getSn(); + return $this->create($data); + } + + public function dec(array $data, $merId) + { + $data['mer_id'] = $merId; + $data['financial_pm'] = 0; + $data['financial_record_sn'] = $this->getSn(); + return $this->create($data); + } + + public function search(array $where) + { + $query = $this->getModel()::getDB() + ->when(isset($where['financial_type']) && $where['financial_type'] !== '', function ($query) use ($where) { + $query->whereIn('financial_type', $where['financial_type']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + }) + ->when(isset($where['user_info']) && $where['user_info'] !== '', function ($query) use ($where) { + $query->where('user_info', $where['user_info']); + }) + ->when(isset($where['user_id']) && $where['user_id'] !== '', function ($query) use ($where) { + $query->where('user_id', $where['user_id']); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('order_sn|user_info|financial_record_sn', "%{$where['keyword']}%"); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'create_time'); + }) + ->when(isset($where['is_mer']) && $where['is_mer'] !== '', function ($query) use ($where) { + if($where['is_mer']){ + $query->where('mer_id',$where['is_mer'])->where('type','in',[0,1]); + }else{ + $query->where('type','in',[1,2]); + } + }); + return $query; + } + + /** + * TODO 根据条件和时间查询出相对类型的数量个金额 + * @param int $type + * @param array $where + * @param string $date + * @param array $financialType + * @return array + * @author Qinii + * @day 4/14/22 + */ + public function getDataByType(int $type, array $where, string $date, array $financialType) + { + if (empty($financialType)) return [0,0]; + $query = $this->search($where)->where('financial_type','in',$financialType); + + if($type == 1) { + $query->whereDay('create_time',$date); + } else { + $query->whereMonth('create_time',$date); + } + + $count = $query->group('order_id')->count(); + $number = $query->sum('number'); + + return [$count,$number]; + } +} diff --git a/app/common/dao/system/merchant/MerchantAdminDao.php b/app/common/dao/system/merchant/MerchantAdminDao.php new file mode 100644 index 00000000..bcd8f1e2 --- /dev/null +++ b/app/common/dao/system/merchant/MerchantAdminDao.php @@ -0,0 +1,218 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\model\system\merchant\MerchantAdmin; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\Model; + +/** + * Class MerchantAdminDao + * @package app\common\dao\system\merchant + * @author xaboy + * @day 2020-04-17 + */ +class MerchantAdminDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020-04-16 + */ + protected function getModel(): string + { + return MerchantAdmin::class; + } + + /** + * @param int $merId + * @param array $where + * @param int|null $level + * @return BaseQuery + * @author xaboy + * @day 2020-04-18 + */ + public function search(int $merId, array $where = [], ?int $level = null) + { + $query = MerchantAdmin::getDB()->where('is_del', 0)->where('mer_id', $merId) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + }); + + if (!is_null($level)) $query->where('level', $level); + + if (isset($where['keyword']) && $where['keyword'] !== '') { + $query = $query->whereLike('real_name|account', '%' . $where['keyword'] . '%'); + } + + if (isset($where['status']) && $where['status'] !== '') { + $query = $query->where('status', intval($where['status'])); + } + + return $query; + } + + /** + * @param int $merId + * @return string + * @author xaboy + * @day 2020-04-16 + */ + public function merIdByAccount(int $merId): string + { + return MerchantAdmin::getDB()->where('mer_id', $merId)->where('level', 0)->value('account'); + } + + /** + * @param int $merId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/7/7 + */ + public function merIdByAdmin(int $merId) + { + return MerchantAdmin::getDB()->where('mer_id', $merId)->where('level', 0)->find(); + } + + /** + * @param string $account + * @param int $merId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-20 + */ + public function accountByAdmin(string $account, int $merId) + { + return MerchantAdmin::getInstance()->where('account', $account) + ->where('is_del', 0)->where('mer_id', $merId) + ->field(['account', 'pwd', 'real_name', 'login_count', 'merchant_admin_id', 'status', 'mer_id']) + ->find(); + } + + /** + * @param string $account + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-20 + */ + public function accountByTopAdmin(string $account) + { + return MerchantAdmin::getInstance()->where('account', $account) + ->where('is_del', 0)->where('level', 0) + ->field(['account', 'pwd', 'real_name', 'login_count', 'merchant_admin_id', 'status', 'mer_id']) + ->find(); + } + + /** + * @param string $account + * @return mixed + * @author xaboy + * @day 2020-04-20 + */ + public function accountByMerchantId(string $account) + { + return MerchantAdmin::getInstance()->where('account', $account)->value('mer_id'); + } + + + /** + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-17 + */ + public function get( $id) + { + return MerchantAdmin::getInstance()->where('is_del', 0)->find($id); + } + + /** + * @param int $id + * @param int $merId + * @param int|null $level + * @return bool + * @author xaboy + * @day 2020-04-18 + */ + public function exists(int $id, int $merId = 0, ?int $level = null) + { + $query = MerchantAdmin::getDB()->where($this->getPk(), $id)->where('is_del', 0); + if ($merId) $query->where('mer_id', $merId); + if (!is_null($level)) $query->where('level', $level); + return $query->count() > 0; + } + + /** + * @param int $merId + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-04-18 + */ + public function merFieldExists(int $merId, $field, $value, ?int $except = null): bool + { + $query = MerchantAdmin::getDB()->where($field, $value)->where('mer_id', $merId); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->count() > 0; + } + + /** + * @param int $id + * @return bool + * @author xaboy + * @day 2020-04-18 + */ + public function topExists(int $id) + { + $query = MerchantAdmin::getDB()->where($this->getPk(), $id)->where('is_del', 0)->where('level', 0); + return $query->count() > 0; + } + + /** + * @param int $merId + * @return mixed + * @author xaboy + * @day 2020-04-17 + */ + public function merchantIdByTopAdminId(int $merId) + { + return MerchantAdmin::getDB()->where('mer_id', $merId)->where('is_del', 0)->where('level', 0)->value('merchant_admin_id'); + } + + public function deleteMer($merId) + { + MerchantAdmin::getDB()->where('mer_id', $merId)->update(['account' => Db::raw('CONCAT(`account`,\'$del\')')]); + } +} diff --git a/app/common/dao/system/merchant/MerchantAppymentsDao.php b/app/common/dao/system/merchant/MerchantAppymentsDao.php new file mode 100644 index 00000000..67ba404d --- /dev/null +++ b/app/common/dao/system/merchant/MerchantAppymentsDao.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + +use app\common\dao\BaseDao; +use app\common\model\system\merchant\MerchantApplyments; + +class MerchantAppymentsDao extends BaseDao +{ + protected function getModel(): string + { + return MerchantApplyments::class; + } + + public function search(array $where) + { + $query = $this->getModel()::getDB() + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + }) + ->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + }) + ->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', (int)$where['status']); + }) + ->when(isset($where['mer_applyments_id']) && $where['mer_applyments_id'] !== '', function ($query) use ($where) { + $query->where('mer_applyments_id', $where['mer_applyments_id']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + }) + ->where('is_del', 0); + + return $query; + } + + + +} diff --git a/app/common/dao/system/merchant/MerchantCategoryDao.php b/app/common/dao/system/merchant/MerchantCategoryDao.php new file mode 100644 index 00000000..c9a091e2 --- /dev/null +++ b/app/common/dao/system/merchant/MerchantCategoryDao.php @@ -0,0 +1,82 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\merchant\MerchantCategory; +use think\db\BaseQuery; +use think\facade\Db; + +/** + * Class MerchantCategoryDao + * @package app\common\dao\system\merchant + * @author xaboy + * @day 2020-05-06 + */ +class MerchantCategoryDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return MerchantCategory::class; + } + + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-06 + */ + public function search(array $where = []) + { + return MerchantCategory::getDB(); + } + + /** + * @return array + * @author xaboy + * @day 2020-05-06 + */ + public function allOptions() + { + $data = MerchantCategory::getDB()->column('category_name', 'merchant_category_id'); + $options = []; + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + } + + public function dateMerchantPriceGroup($date, $limit = 4) + { + return MerchantCategory::getDB()->alias('A')->leftJoin('Merchant B', 'A.merchant_category_id = B.category_id') + ->leftJoin('StoreOrder C', 'C.mer_id = B.mer_id')->field(Db::raw('sum(C.pay_price) as pay_price,A.category_name')) + ->when($date, function ($query, $date) { + getModelTime($query, $date, 'C.pay_time'); + })->group('A.merchant_category_id')->where('pay_price', '>', 0)->order('pay_price DESC')->limit($limit)->select(); + } + + public function names(array $ids) + { + return MerchantCategory::getDB()->whereIn('merchant_category_id', $ids)->column('category_name'); + } +} diff --git a/app/common/dao/system/merchant/MerchantDao.php b/app/common/dao/system/merchant/MerchantDao.php new file mode 100644 index 00000000..ae6db49c --- /dev/null +++ b/app/common/dao/system/merchant/MerchantDao.php @@ -0,0 +1,298 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\model\system\merchant\Merchant; +use crmeb\services\VicWordService; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\Model; + +class MerchantDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020-04-16 + */ + protected function getModel(): string + { + return Merchant::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-04-16 + */ + public function search(array $where, $is_del = 0) + { + $query = Merchant::getDB() + ->when($is_del !== null, function ($query) use ($is_del) { + $query->where('is_del', $is_del); + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '', function ($query) use ($where) { + $query->where('is_trader', $where['is_trader']); + }) + ->when(isset($where['street_id']) && $where['street_id'] !== '', function ($query) use ($where) { + $mer_id = Db::name('merchant_address')->where('street_id', $where['street_id'])->column('mer_id'); + $query->whereIn('mer_id',$mer_id ?: '' ); + }) + ->when(isset($where['is_best']) && $where['is_best'] !== '', function ($query) use ($where) { + $query->where('is_best', $where['is_best']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + }) + ->when(isset($where['mer_state']) && $where['mer_state'] !== '', function ($query) use ($where) { + $query->where('mer_state', $where['mer_state']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + }) + ->when(isset($where['category_id']) && $where['category_id'] !== '', function ($query) use ($where) { + $query->whereIn('category_id', is_array($where['category_id']) ? $where['category_id'] : explode(',', $where['category_id'])); + }) + ->when(isset($where['type_id']) && $where['type_id'] !== '', function ($query) use ($where) { + $query->whereIn('type_id', is_array($where['type_id']) ? $where['type_id'] : explode(',', $where['type_id'])); + }) + ->when(isset($where['delivery_way']) && $where['delivery_way'] !== '', function ($query) use ($where) { + $query->whereLike('delivery_way', "%{$where['delivery_way']}%"); + }); + + + if (isset($where['keyword']) && $where['keyword']) { + if (is_numeric($where['keyword'])) { + $query->whereLike('mer_name|mer_keyword|mer_phone', "%{$where['keyword']}%"); + } else { + $word = app()->make(VicWordService::class)->getWord($where['keyword']); + $query->where(function ($query) use ($word, $where) { + foreach ($word as $item) { + if(mb_strlen($item) > 1) { + $query->whereOr('mer_name', 'LIKE', "%$item%"); + } + } + $query->whereOr('mer_name|mer_keyword', 'LIKE', "%{$where['keyword']}%"); + }); + } + } + if (isset($where['status']) && $where['status'] !== '') + $query->where('status', $where['status']); + $order = $where['order'] ?? ''; + $query->when($order, function ($query) use ($where, $order) { + if ($order == 'rate') { + $query->order('is_best DESC, product_score DESC,service_score DESC,postage_score DESC'); + } else if ($order == 'location' && isset($where['location']['long'], $where['location']['lat'])) { + $lng = (float)$where['location']['long']; + $lat = (float)$where['location']['lat']; + $query->whereNotNull('lat')->whereNotNull('long') + ->order(Db::raw("(2 * 6378.137 * ASIN( + SQRT( + POW( SIN( PI( ) * ( $lng- `long` ) / 360 ), 2 ) + COS( PI( ) * $lat / 180 ) * COS( `lat` * PI( ) / 180 ) * POW( SIN( PI( ) * ( $lat- `lat` ) / 360 ), 2 ) + ) + ) + ) ASC ")); + } else { + $query->order('is_best DESC, sales DESC,sort DESC'); + } + }, function ($query) use ($order) { + $query->order('is_best DESC, sort DESC,sales DESC'); + }); + return $query; + } + + /** + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-17 + */ + public function get($id) + { + return Merchant::getInstance()->where('is_del', 0)->find($id); + } + + /** + * @param $id + * @author Qinii + */ + public function apiGetOne($id) + { + return Merchant::getInstance()->where(['is_del' => 0, 'status' => 1, 'mer_state' => 1])->find($id); + } + + /** + * @param int $merId + * @author Qinii + */ + public function incCareCount(int $merId) + { + ($this->getModel()::getDB())->where($this->getPk(), $merId)->inc('care_count', 1)->update(); + } + + /** + * @param int $merId + * @param int $inc + * @author xaboy + * @day 2020/9/25 + */ + public function incSales($merId, $inc) + { + ($this->getModel()::getDB())->where($this->getPk(), $merId)->inc('sales', $inc)->update(); + } + + /** + * @param int $merId + * @author Qinii + */ + public function decCareCount(array $merId) + { + ($this->getModel()::getDB())->whereIn($this->getPk(), $merId)->where('care_count', '>', 0)->dec('care_count', 1)->update(); + } + + public function dateMerchantNum($date) + { + return Merchant::getDB()->where('is_del', 0)->when($date, function ($query, $date) { + getModelTime($query, $date); + })->count(); + } + + /** + * TODO 获取复制商品次数 + * @param int $merId + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function getCopyNum(int $merId) + { + return Merchant::getDB()->where('mer_id', $merId)->value('copy_product_num'); + } + + /** + * TODO 变更复制次数 + * @param int $merId + * @param int $num 正负数 + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function changeCopyNum(int $merId, int $num) + { + return $this->getModel()::where('mer_id', $merId)->inc('copy_product_num', $num)->update(); + } + + /** + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-30 + */ + public function fieldExists($field, $value, ?int $except = null): bool + { + $query = ($this->getModel())::getDB()->where($field, $value); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->where('is_del', 0)->count() > 0; + } + + public function names(array $ids) + { + return Merchant::getDB()->whereIn('mer_id',$ids)->column('mer_name'); + } + + /** + * TODO 增加商户余额 + * @param int $merId + * @param float $num + * @author Qinii + * @day 3/19/21 + */ + public function addMoney(int $merId, float $num) + { + $field = 'mer_money'; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + if ($merchant) { + $mer_money = bcadd($merchant[$field], $num, 2); + $merchant[$field] = $mer_money; + $merchant->save(); + } + } + + /** + * TODO 减少商户余额 + * @param int $merId + * @param float $num + * @author Qinii + * @day 3/19/21 + */ + public function subMoney(int $merId, float $num) + { + $field = 'mer_money'; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + if ($merchant) { + $mer_money = bcsub($merchant[$field], $num, 2); + $merchant[$field] = $mer_money; + $merchant->save(); + } + } + + public function clearTypeId(int $typeId) + { + return Merchant::getDB()->where('type_id', $typeId)->update(['type_id' => 0]); + } + + public function addFieldNum(int $merId, int $num, string $field) + { + if ($num < 0) $num = -$num; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + $number = $merchant[$field] + $num; + $merchant[$field] = $number; + $merchant->save(); + } + + public function sumFieldNum(int $merId, int $num, string $field) + { + if ($num < 0) $num = -$num; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + $number = $merchant[$field] - $num; + $merchant[$field] = $number; + $merchant->save(); + } + + public function merIdByImage($merIds) + { + return $this->getModel()::getDB()->whereIn('mer_id', $merIds)->column('mer_id,mer_avatar'); + } + + public function updateMargin($typeId, $margin, $is_margin) + { + return $this->getModel()::where('type_id',$typeId)->where('is_margin','in',[0,1])->update([ + 'is_margin' => $is_margin, + 'margin' => $margin + ]); + } + +} diff --git a/app/common/dao/system/merchant/MerchantDao.php.bak b/app/common/dao/system/merchant/MerchantDao.php.bak new file mode 100644 index 00000000..f8618203 --- /dev/null +++ b/app/common/dao/system/merchant/MerchantDao.php.bak @@ -0,0 +1,294 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\model\system\merchant\Merchant; +use crmeb\services\VicWordService; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\Model; + +class MerchantDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020-04-16 + */ + protected function getModel(): string + { + return Merchant::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-04-16 + */ + public function search(array $where, $is_del = 0) + { + $query = Merchant::getDB() + ->when($is_del !== null, function ($query) use ($is_del) { + $query->where('is_del', $is_del); + }) + ->when(isset($where['is_trader']) && $where['is_trader'] !== '', function ($query) use ($where) { + $query->where('is_trader', $where['is_trader']); + }) + ->when(isset($where['is_best']) && $where['is_best'] !== '', function ($query) use ($where) { + $query->where('is_best', $where['is_best']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + }) + ->when(isset($where['mer_state']) && $where['mer_state'] !== '', function ($query) use ($where) { + $query->where('mer_state', $where['mer_state']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + }) + ->when(isset($where['category_id']) && $where['category_id'] !== '', function ($query) use ($where) { + $query->whereIn('category_id', is_array($where['category_id']) ? $where['category_id'] : explode(',', $where['category_id'])); + }) + ->when(isset($where['type_id']) && $where['type_id'] !== '', function ($query) use ($where) { + $query->whereIn('type_id', is_array($where['type_id']) ? $where['type_id'] : explode(',', $where['type_id'])); + }) + ->when(isset($where['delivery_way']) && $where['delivery_way'] !== '', function ($query) use ($where) { + $query->whereLike('delivery_way', "%{$where['delivery_way']}%"); + }); + + + if (isset($where['keyword']) && $where['keyword']) { + if (is_numeric($where['keyword'])) { + $query->whereLike('mer_name|mer_keyword|mer_phone', "%{$where['keyword']}%"); + } else { + $word = app()->make(VicWordService::class)->getWord($where['keyword']); + $query->where(function ($query) use ($word, $where) { + foreach ($word as $item) { + if(mb_strlen($item) > 1) { + $query->whereOr('mer_name', 'LIKE', "%$item%"); + } + } + $query->whereOr('mer_name|mer_keyword', 'LIKE', "%{$where['keyword']}%"); + }); + } + } + if (isset($where['status']) && $where['status'] !== '') + $query->where('status', $where['status']); + $order = $where['order'] ?? ''; + $query->when($order, function ($query) use ($where, $order) { + if ($order == 'rate') { + $query->order('is_best DESC, product_score DESC,service_score DESC,postage_score DESC'); + } else if ($order == 'location' && isset($where['location']['long'], $where['location']['lat'])) { + $lng = (float)$where['location']['long']; + $lat = (float)$where['location']['lat']; + $query->whereNotNull('lat')->whereNotNull('long') + ->order(Db::raw("(2 * 6378.137 * ASIN( + SQRT( + POW( SIN( PI( ) * ( $lng- `long` ) / 360 ), 2 ) + COS( PI( ) * $lat / 180 ) * COS( `lat` * PI( ) / 180 ) * POW( SIN( PI( ) * ( $lat- `lat` ) / 360 ), 2 ) + ) + ) + ) ASC ")); + } else { + $query->order('is_best DESC, sales DESC,sort DESC'); + } + }, function ($query) use ($order) { + $query->order('is_best DESC, sort DESC,sales DESC'); + }); + return $query; + } + + /** + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-17 + */ + public function get($id) + { + return Merchant::getInstance()->where('is_del', 0)->find($id); + } + + /** + * @param $id + * @author Qinii + */ + public function apiGetOne($id) + { + return Merchant::getInstance()->where(['is_del' => 0, 'status' => 1, 'mer_state' => 1])->find($id); + } + + /** + * @param int $merId + * @author Qinii + */ + public function incCareCount(int $merId) + { + ($this->getModel()::getDB())->where($this->getPk(), $merId)->inc('care_count', 1)->update(); + } + + /** + * @param int $merId + * @param int $inc + * @author xaboy + * @day 2020/9/25 + */ + public function incSales($merId, $inc) + { + ($this->getModel()::getDB())->where($this->getPk(), $merId)->inc('sales', $inc)->update(); + } + + /** + * @param int $merId + * @author Qinii + */ + public function decCareCount(array $merId) + { + ($this->getModel()::getDB())->whereIn($this->getPk(), $merId)->where('care_count', '>', 0)->dec('care_count', 1)->update(); + } + + public function dateMerchantNum($date) + { + return Merchant::getDB()->where('is_del', 0)->when($date, function ($query, $date) { + getModelTime($query, $date); + })->count(); + } + + /** + * TODO 获取复制商品次数 + * @param int $merId + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function getCopyNum(int $merId) + { + return Merchant::getDB()->where('mer_id', $merId)->value('copy_product_num'); + } + + /** + * TODO 变更复制次数 + * @param int $merId + * @param int $num 正负数 + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function changeCopyNum(int $merId, int $num) + { + return $this->getModel()::where('mer_id', $merId)->inc('copy_product_num', $num)->update(); + } + + /** + * @param $field + * @param $value + * @param int|null $except + * @return bool + * @author xaboy + * @day 2020-03-30 + */ + public function fieldExists($field, $value, ?int $except = null): bool + { + $query = ($this->getModel())::getDB()->where($field, $value); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->where('is_del', 0)->count() > 0; + } + + public function names(array $ids) + { + return Merchant::getDB()->whereIn('mer_id',$ids)->column('mer_name'); + } + + /** + * TODO 增加商户余额 + * @param int $merId + * @param float $num + * @author Qinii + * @day 3/19/21 + */ + public function addMoney(int $merId, float $num) + { + $field = 'mer_money'; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + if ($merchant) { + $mer_money = bcadd($merchant[$field], $num, 2); + $merchant[$field] = $mer_money; + $merchant->save(); + } + } + + /** + * TODO 减少商户余额 + * @param int $merId + * @param float $num + * @author Qinii + * @day 3/19/21 + */ + public function subMoney(int $merId, float $num) + { + $field = 'mer_money'; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + if ($merchant) { + $mer_money = bcsub($merchant[$field], $num, 2); + $merchant[$field] = $mer_money; + $merchant->save(); + } + } + + public function clearTypeId(int $typeId) + { + return Merchant::getDB()->where('type_id', $typeId)->update(['type_id' => 0]); + } + + public function addFieldNum(int $merId, int $num, string $field) + { + if ($num < 0) $num = -$num; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + $number = $merchant[$field] + $num; + $merchant[$field] = $number; + $merchant->save(); + } + + public function sumFieldNum(int $merId, int $num, string $field) + { + if ($num < 0) $num = -$num; + $merchant = $this->getModel()::getDB()->where('mer_id', $merId)->find(); + $number = $merchant[$field] - $num; + $merchant[$field] = $number; + $merchant->save(); + } + + public function merIdByImage($merIds) + { + return $this->getModel()::getDB()->whereIn('mer_id', $merIds)->column('mer_id,mer_avatar'); + } + + public function updateMargin($typeId, $margin, $is_margin) + { + return $this->getModel()::where('type_id',$typeId)->where('is_margin','in',[0,1])->update([ + 'is_margin' => $is_margin, + 'margin' => $margin + ]); + } + +} diff --git a/app/common/dao/system/merchant/MerchantIntentionDao.php b/app/common/dao/system/merchant/MerchantIntentionDao.php new file mode 100644 index 00000000..67a4a579 --- /dev/null +++ b/app/common/dao/system/merchant/MerchantIntentionDao.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + +use app\common\dao\BaseDao; +use app\common\model\system\merchant\MerchantIntention; + +class MerchantIntentionDao extends BaseDao +{ + protected function getModel(): string + { + return MerchantIntention::class; + } + + public function search(array $where) + { + $query = $this->getModel()::getDB()->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + })->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', (int)$where['status']); + })->when(isset($where['mer_intention_id']) && $where['mer_intention_id'] !== '', function ($query) use ($where) { + $query->where('mer_intention_id', $where['mer_intention_id']); + })->when(isset($where['category_id']) && $where['category_id'] !== '', function ($query) use ($where) { + $query->where('merchant_category_id', $where['category_id']); + })->when(isset($where['type_id']) && $where['type_id'] !== '', function ($query) use ($where) { + $query->where('mer_type_id', $where['type_id']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->where('mer_name|phone|mark', 'like', '%' . $where['keyword'] . '%'); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date']); + })->where('is_del', 0); + + return $query; + } + + public function form($id, $data) + { + $this->getModel()::getDB()->where($this->getPk(), $id)->update(['status' => $data['status'], 'mark' => $data['mark']]); + } +} diff --git a/app/common/dao/system/merchant/MerchantTypeDao.php b/app/common/dao/system/merchant/MerchantTypeDao.php new file mode 100644 index 00000000..8d69652c --- /dev/null +++ b/app/common/dao/system/merchant/MerchantTypeDao.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\merchant\MerchantType; + +class MerchantTypeDao extends BaseDao +{ + + protected function getModel(): string + { + return MerchantType::class; + } + + public function search(array $where = []) + { + return MerchantType::getDB() + ->when(isset($where['mer_type_id']) && $where['mer_type_id'] !== '',function($query) use($where){ + $query->where('mer_type_id',$where['mer_type_id']); + }); + } + + public function getOptions() + { + $data = MerchantType::getDB()->column('type_name', 'mer_type_id'); + $options = []; + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + } + + public function getMargin() + { + $data = MerchantType::getDB()->column('margin,is_margin', 'mer_type_id'); + $options = []; + foreach ($data as $value => $item) { + if ($item['is_margin'] == 1) { + $options[] = [ + 'value' => $value, + 'rule' => [ + [ + 'type' => 'div', + 'children' => [ + '保证金:' . $item['margin']. ' 元' + ], + 'style' => [ + 'paddingTop' => '100px', + ], + ] + ] + ]; + } + } + return $options; + } + + +} diff --git a/app/common/dao/system/notice/SystemNoticeConfigDao.php b/app/common/dao/system/notice/SystemNoticeConfigDao.php new file mode 100644 index 00000000..ae2307a3 --- /dev/null +++ b/app/common/dao/system/notice/SystemNoticeConfigDao.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\notice; + + +use app\common\dao\BaseDao; +use app\common\model\system\notice\SystemNoticeConfig; + +class SystemNoticeConfigDao extends BaseDao +{ + + protected function getModel(): string + { + return SystemNoticeConfig::class; + } + + + public function getNoticeStatusByKey(string $key, string $field) + { + $value = $this->getModel()::getDb()->where('notice_key',$key)->value($field); + return $value == 1 ? true : false; + } + + public function getNoticeStatusByConstKey(string $key) + { + $value = $this->getModel()::getDb()->where('const_key',$key)->field('notice_sys,notice_wechat,notice_routine,notice_sms')->find(); + return $value; + } + + public function search($where) + { + $query = $this->getModel()::getDb() + ->when(isset($where['is_sms']) && $where['is_sms'] != '', function($query){ + $query->whereIn('notice_sms',[0,1]); + }) + ->when(isset($where['is_routine']) && $where['is_routine'] != '', function($query){ + $query->whereIn('notice_routine',[0,1]); + }) + ->when(isset($where['is_wechat']) && $where['is_wechat'] != '', function($query){ + $query->whereIn('notice_wechat',[0,1]); + }) + ; + return $query; + } + + public function getSubscribe() + { + $arr = []; + $res = $this->search([])->where(['notice_routine' => 1])->with(['routineTemplate'])->select()->toArray(); + foreach ($res as $re) { + $arr[$re['const_key']] = $re['routineTemplate']['tempid'] ?? ''; + } + return $arr; + } +} diff --git a/app/common/dao/system/notice/SystemNoticeDao.php b/app/common/dao/system/notice/SystemNoticeDao.php new file mode 100644 index 00000000..fc3811d4 --- /dev/null +++ b/app/common/dao/system/notice/SystemNoticeDao.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\notice; + + +use app\common\dao\BaseDao; +use app\common\model\system\notice\SystemNotice; + +class SystemNoticeDao extends BaseDao +{ + + protected function getModel(): string + { + return SystemNotice::class; + } + + public function search(array $where) + { + return SystemNotice::getDB()->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('notice_title|notice_content', '%' . $where['keyword'] . '%'); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'create_time'); + })->where('is_del', 0); + } +} diff --git a/app/common/dao/system/notice/SystemNoticeLogDao.php b/app/common/dao/system/notice/SystemNoticeLogDao.php new file mode 100644 index 00000000..7870ad11 --- /dev/null +++ b/app/common/dao/system/notice/SystemNoticeLogDao.php @@ -0,0 +1,81 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\notice; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\notice\SystemNoticeLog; + +/** + * Class SystemNoticeLogDao + * @package app\common\dao\system\notice + * @author xaboy + * @day 2020/11/6 + */ +class SystemNoticeLogDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/11/6 + */ + protected function getModel(): string + { + return SystemNoticeLog::class; + } + + /** + * @param $id + * @param $merId + * @return int + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/11/6 + */ + public function read($id, $merId) + { + return SystemNoticeLog::getDB()->where('notice_log_id', $id)->where('mer_id', $merId)->update(['is_read' => 1, 'read_time' => date('Y-m-d H:i:s')]); + } + + public function unreadCount($merId) + { + return SystemNoticeLog::getDB()->where('mer_id', $merId)->where('is_read', 0)->count(); + } + + /** + * @param $id + * @param $merId + * @return int + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/11/6 + */ + public function del($id, $merId) + { + return SystemNoticeLog::getDB()->where('notice_log_id', $id)->where('mer_id', $merId)->delete(); + } + + public function search(array $where) + { + return SystemNoticeLog::getDB()->alias('A')->join('SystemNotice B', 'A.notice_id = B.notice_id')->where('mer_id', $where['mer_id'])->when(isset($where['is_read']) && $where['is_read'] !== '', function ($query) use ($where) { + $query->where('A.is_read', intval($where['is_read'])); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'B.create_time'); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('B.notice_title|B.notice_content', "%{$where['keyword']}%"); + })->where('A.is_del', 0); + } +} diff --git a/app/common/dao/system/serve/ServeMealDao.php b/app/common/dao/system/serve/ServeMealDao.php new file mode 100644 index 00000000..b0df408a --- /dev/null +++ b/app/common/dao/system/serve/ServeMealDao.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\system\serve; + +use app\common\dao\BaseDao; +use app\common\model\system\serve\ServeMeal; + +class ServeMealDao extends BaseDao +{ + + protected function getModel(): string + { + return ServeMeal::class; + } + + +} diff --git a/app/common/dao/system/serve/ServeOrderDao.php b/app/common/dao/system/serve/ServeOrderDao.php new file mode 100644 index 00000000..4fb1167e --- /dev/null +++ b/app/common/dao/system/serve/ServeOrderDao.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\system\serve; + +use app\common\dao\BaseDao; +use app\common\model\system\serve\ServeOrder; + +class ServeOrderDao extends BaseDao +{ + + protected function getModel(): string + { + return ServeOrder::class; + } + + public function search($where) + { + $query = ServeOrder::hasWhere('merchant',function($query) use($where) { + + $query->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use($where){ + $query->whereLike('mer_keyword|real_name|mer_name',"%{$where['keyword']}%"); + }); + $query->when(isset($where['is_trader']) && $where['is_trader'] !== '', function ($query) use($where){ + $query->where('is_trader',$where['is_trader']); + }); + $query->when(isset($where['category_id']) && $where['category_id'] !== '', function ($query) use($where){ + $query->where('category_id',$where['category_id']); + }); + $query->when(isset($where['type_id']) && $where['type_id'] !== '', function ($query) use($where){ + $query->where('type_id',$where['type_id']); + }); + $query->where('is_del',0); + }); + + $query->when(isset($where['type']) && $where['type'] !== '', function ($query) use($where){ + $query->where('ServeOrder.type',$where['type']); + }); + + $query->when(isset($where['date']) && $where['date'] !== '', function ($query) use($where){ + getModelTime($query,$where['date'],'ServeOrder.create_time'); + }); + + $query->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use($where){ + $query->where('ServeOrder.mer_id',$where['mer_id']); + }); + + $query->when(isset($where['status']) && $where['status'] !== '', function ($query) use($where){ + $query->where('ServeOrder.status',$where['status']); + }); + + $query->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use($where){ + $query->where('ServeOrder.is_del',$where['is_del']); + }); + + + return $query; + } + +} diff --git a/app/common/dao/system/sms/SmsRecordDao.php b/app/common/dao/system/sms/SmsRecordDao.php new file mode 100644 index 00000000..5982e34a --- /dev/null +++ b/app/common/dao/system/sms/SmsRecordDao.php @@ -0,0 +1,89 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\system\sms; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\system\sms\SmsRecord; +use think\db\BaseQuery; +use think\db\exception\DbException; + +/** + * Class SmsRecordDao + * @package app\common\dao\system\sms + * @author xaboy + * @day 2020-05-18 + */ +class SmsRecordDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return SmsRecord::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-18 + */ + public function search(array $where) + { + return SmsRecord::getDB()->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('resultcode', $where['type']); + })->order('create_time DESC'); + } + + /** + * @return int + * @author xaboy + * @day 2020-05-18 + */ + public function count() + { + return SmsRecord::count($this->getPk()); + } + + /** + * @param $record_id + * @param $resultcode + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-18 + */ + public function updateRecordStatus($record_id, $resultcode) + { + return SmsRecord::getDB()->where('record_id', $record_id)->update(['resultcode' => $resultcode]); + } + + + /** + * @param $time + * @return array + * @author xaboy + * @day 2020/6/9 + */ + public function getTimeOutIds($time) + { + return SmsRecord::getDB()->where('resultcode', null)->where('create_time', '<=', $time)->column('record_id'); + } +} diff --git a/app/common/dao/user/FeedbackCateoryDao.php b/app/common/dao/user/FeedbackCateoryDao.php new file mode 100644 index 00000000..0f974c1d --- /dev/null +++ b/app/common/dao/user/FeedbackCateoryDao.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\user\FeedBackCategory as model; +use crmeb\traits\CategoresDao; + +class FeedbackCateoryDao extends BaseDao +{ + + use CategoresDao; + + /** + * @return string + * @author Qinii + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @return int + * @author Qinii + */ + public function getMaxLevel() + { + return 2; + } + +} diff --git a/app/common/dao/user/FeedbackDao.php b/app/common/dao/user/FeedbackDao.php new file mode 100644 index 00000000..3cc60fb1 --- /dev/null +++ b/app/common/dao/user/FeedbackDao.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\Feedback; +use think\db\BaseQuery; + +/** + * Class FeedbackDao + * @package app\common\dao\user + * @author xaboy + * @day 2020/5/28 + */ +class FeedbackDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/28 + */ + protected function getModel(): string + { + return Feedback::class; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/5/28 + */ + public function search(array $where) + { + return Feedback::getDB()->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('content|reply|remake|realname|contact', '%'.$where['keyword'].'%'); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('type',$where['type']); + })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + })->when(isset($where['realname']) && $where['realname'] !== '', function ($query) use ($where) { + $query->where('realname','like', '%'.$where['realname'].'%'); + })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) { + $query->where('is_del',$where['is_del']); + })->order('create_time DESC'); + } + + /** + * @param $id + * @param $uid + * @return bool + * @author xaboy + * @day 2020/5/28 + */ + public function uidExists($id, $uid): bool + { + return Feedback::getDB()->where($this->getPk(), $id)->where('uid', $uid)->where('is_del', 0)->count($this->getPk()) > 0; + } + + public function merExists(int $id) + { + return $this->getModel()::getDB()->where($this->getPk(), $id)->where('is_del', 0)->count() > 0; + } +} diff --git a/app/common/dao/user/LabelRuleDao.php b/app/common/dao/user/LabelRuleDao.php new file mode 100644 index 00000000..ce2995d2 --- /dev/null +++ b/app/common/dao/user/LabelRuleDao.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\user\LabelRule; + +class LabelRuleDao extends BaseDao +{ + + protected function getModel(): string + { + return LabelRule::class; + } + + public function search(array $where) + { + return LabelRule::hasWhere('label')->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('UserLabel.label_name', "%{$where['keyword']}%"); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('LabelRule.type', intval($where['type'])); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('LabelRule.mer_id', intval($where['mer_id'])); + }); + } +} diff --git a/app/common/dao/user/MemberInterestsDao.php b/app/common/dao/user/MemberInterestsDao.php new file mode 100644 index 00000000..6d2a5758 --- /dev/null +++ b/app/common/dao/user/MemberInterestsDao.php @@ -0,0 +1,25 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\user\MemberInterests; + +class MemberInterestsDao extends BaseDao +{ + + protected function getModel(): string + { + return MemberInterests::class; + } +} diff --git a/app/common/dao/user/UserAddressDao.php b/app/common/dao/user/UserAddressDao.php new file mode 100644 index 00000000..d6159a05 --- /dev/null +++ b/app/common/dao/user/UserAddressDao.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\user\UserAddress as model; + +class UserAddressDao extends BaseDao +{ + + + /** + * @return string + * @author Qinii + */ + protected function getModel(): string + { + return model::class; + } + + + public function userFieldExists($field, $value,$uid): bool + { + return (($this->getModel()::getDB())->where('uid',$uid)->where($field,$value)->count()) > 0; + } + + public function changeDefault(int $uid) + { + return ($this->getModel()::getDB())->where('uid',$uid)->update(['is_default' => 0]); + } + + public function getAll(int $uid) + { + return (($this->getModel()::getDB())->where('uid',$uid)); + } +} diff --git a/app/common/dao/user/UserBillDao.php b/app/common/dao/user/UserBillDao.php new file mode 100644 index 00000000..088cd0fe --- /dev/null +++ b/app/common/dao/user/UserBillDao.php @@ -0,0 +1,302 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\UserBill; + +/** + * Class UserBillDao + * @package app\common\dao\user + * @author xaboy + * @day 2020/6/22 + */ +class UserBillDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return UserBill::class; + } + + /** + * @param array $where + * @param $data + * @return int + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/6/22 + */ + public function updateBill(array $where, $data) + { + return UserBill::getDB()->where($where)->limit(1)->update($data); + } + + /** + * @param $time + * @return \think\Collection + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function getTimeoutBrokerageBill($time) + { + return UserBill::getDB()->where('create_time', '<=', $time)->where('category', 'brokerage') + ->whereIn('type', ['order_one', 'order_two'])->with('user')->where('status', 0)->select(); + } + + public function getTimeoutIntegralBill($time) + { + return UserBill::getDB()->where('create_time', '<=', $time)->where('category', 'integral') + ->where('type', 'lock')->with('user')->where('status', 0)->select(); + } + + public function getTimeoutMerchantMoneyBill($time) + { + return UserBill::getDB()->where('create_time', '<=', $time)->where('category', 'mer_computed_money')->where('type','order') + ->where('status', 0)->select(); + } + + public function refundMerchantMoney($order_id, $type, $mer_id) + { + return UserBill::getDB()->where('link_id', $order_id)->where('mer_id', $mer_id) + ->where('category', 'mer_refund_money')->where('type', $type)->sum('number'); + } + + public function merchantLickMoney($merId = null) + { + $lst = UserBill::getDB()->where('category', 'mer_lock_money')->when($merId, function ($query, $val) { + $query->where('mer_id', $val); + })->where('status', 0)->select()->toArray(); + $lockMoney = 0; + if (count($lst)) { + $lockMoney = -1 * UserBill::getDB()->whereIn('link_id', array_column($lst, 'link_id')) + ->where('category', 'mer_refund_money')->sum('number'); + } + foreach ($lst as $bill) { + $lockMoney = bcadd($lockMoney, $bill['number'], 2); + } + $lockMoney = bcadd($lockMoney, UserBill::getDB() + ->where('category', 'mer_computed_money')->when($merId, function ($query, $val) { + $query->where('mer_id', $val); + })->where('status', 0)->where('type', 'order')->sum('number'), 2); + return $lockMoney; + } + + /** + * @param $uid + * @return float + * @author xaboy + * @day 2020/6/22 + */ + public function lockBrokerage($uid) + { + $lst = UserBill::getDB()->where('category', 'brokerage') + ->whereIn('type', ['order_one', 'order_two'])->where('uid', $uid)->where('status', 0)->field('link_id,number')->select()->toArray(); + $refundPrice = 0; + if (count($lst)) { + $refundPrice = -1 * UserBill::getDB()->whereIn('link_id', array_column($lst, 'link_id'))->where('uid', $uid) + ->where('category', 'brokerage')->whereIn('type', ['refund_two', 'refund_one'])->sum('number'); + } + foreach ($lst as $bill) { + $refundPrice = bcadd($refundPrice, $bill['number'], 2); + } + return $refundPrice; + } + + public function lockIntegral($uid = null, $order_id = null) + { + $lst = UserBill::getDB()->where('category', 'integral') + ->where('type', 'lock')->when($order_id, function ($query, $order_id) { + $query->where('link_id', $order_id); + })->when($uid, function ($query, $uid) { + $query->where('uid', $uid); + })->where('status', 0)->field('link_id,number')->select()->toArray(); + $lockIntegral = 0; + if (count($lst)) { + $lockIntegral = -1 * UserBill::getDB()->whereIn('link_id', array_column($lst, 'link_id'))->where('uid', $uid) + ->where('category', 'integral')->where('type', 'refund_lock')->sum('number'); + } + foreach ($lst as $bill) { + $lockIntegral = bcadd($lockIntegral, $bill['number'], 0); + } + return $lockIntegral; + } + + public function deductionIntegral($uid) + { + return UserBill::getDB()->where('uid', $uid) + ->where('category', 'integral')->where('type', 'deduction')->sum('number'); + } + + public function totalGainIntegral($uid) + { + return UserBill::getDB()->where('uid', $uid) + ->where('category', 'integral')->where('pm', 1)->whereNotIn('type', ['refund', 'cancel'])->sum('number'); + } + + /** + * @param $uid + * @return float + * @author xaboy + * @day 2020/6/22 + */ + public function totalBrokerage($uid) + { + return bcsub(UserBill::getDB()->where('category', 'brokerage') + ->whereIn('type', ['order_one', 'order_two'])->where('uid', $uid)->sum('number'), + UserBill::getDB()->where('uid', $uid) + ->where('category', 'brokerage')->whereIn('type', ['refund_two', 'refund_one'])->sum('number'), 2); + } + + /** + * @param $uid + * @return float + * @author xaboy + * @day 2020/6/22 + */ + public function yesterdayBrokerage($uid) + { + return getModelTime(UserBill::getDB()->where('category', 'brokerage') + ->whereIn('type', ['order_one', 'order_two'])->where('uid', $uid), 'yesterday')->sum('number'); + } + + /** + * @param array $where + * @return \think\db\BaseQuery + * @author xaboy + * @day 2020/6/22 + */ + public function search(array $where) + { + return UserBill::getDB() + ->when(isset($where['now_money']) && in_array($where['now_money'], [0, 1, 2]), function ($query) use ($where) { + if ($where['now_money'] == 0) + $query->where('category', 'now_money')->whereIn('type', ['pay_product', 'recharge', 'sys_inc_money', 'sys_dec_money', 'brokerage', 'presell', 'refund']); + else if ($where['now_money'] == 1) + $query->where('category', 'now_money')->whereIn('type', ['pay_product', 'sys_dec_money', 'presell']); + else if ($where['now_money'] == 2) + $query->where('category', 'now_money')->whereIn('type', ['recharge', 'sys_inc_money', 'brokerage', 'refund']); + }) + ->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid'])->where('mer_id', 0); + }) + ->when(isset($where['pm']) && $where['pm'] !== '', function ($query) use ($where) { + $query->where('pm', $where['pm']); + }) + ->when(isset($where['category']) && $where['category'] !== '', function ($query) use ($where) { + $query->where('category', $where['category']); + }) + ->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'create_time'); + }) + ->when(isset($where['day']) && $where['day'] !== '', function ($query) use ($where) { + $query->whereDay('create_time', $where['day']); + }) + ->when(isset($where['month']) && $where['month'] !== '', function ($query) use ($where) { + $query->whereMonth('create_time', $where['month']); + }) + ->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $data = explode('/', $where['type'], 2); + if (count($data) > 1) { + $query->where('category', $data[0])->where('type', $data[1]); + } else { + $query->where('type', $where['type']); + } + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + }) + ->when(isset($where['link_id']) && $where['link_id'] !== '', function ($query) use ($where) { + $query->where('link_id', $where['link_id']); + }); + } + + public function userNowMoneyIncTotal($uid) + { + return $this->search(['uid' => $uid, 'now_money' => 2])->sum('number'); + } + + public function searchJoin(array $where) + { + return UserBill::getDB()->alias('a')->leftJoin('User b', 'a.uid = b.uid') + ->field('a.bill_id,a.pm,a.title,a.number,a.balance,a.mark,a.create_time,a.status,b.nickname,a.uid,a.category') + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('a.mer_id', $where['mer_id']); + }) + ->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $data = explode('/', $where['type'], 2); + if (count($data) > 1) { + $query->where('a.category', $data[0])->where('type', $data[1]); + } else { + $query->where('a.type', $where['type']); + } + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'a.create_time'); + }) + ->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('a.uid|b.nickname|a.title', "%{$where['keyword']}%"); + }) + ->when(isset($where['category']) && $where['category'] !== '', function ($query) use ($where) { + $query->where('a.category', $where['category']); + })->where('category', '<>', 'sys_brokerage'); + + } + + public function refundBrokerage($order_id, $uid) + { + return UserBill::getDB()->where('link_id', $order_id)->where('uid', $uid) + ->where('category', 'brokerage')->whereIn('type', ['refund_two', 'refund_one'])->sum('number'); + } + + public function refundIntegral($order_id, $uid) + { + return UserBill::getDB()->where('link_id', $order_id)->where('uid', $uid) + ->where('category', 'integral')->where('type', 'refund_lock')->sum('number'); + } + + public function validIntegral($uid, $start, $end) + { + $lst = UserBill::getDB()->where('category', 'integral') + ->where('type', 'lock')->whereBetween('create_time', [$start, $end])->where('uid', $uid)->where('status', 1)->field('link_id,number')->select()->toArray(); + $integral = 0; + if (count($lst)) { + $integral = -1 * UserBill::getDB()->whereIn('link_id', array_column($lst, 'link_id'))->where('uid', $uid) + ->where('category', 'integral')->where('type', 'refund_lock')->sum('number'); + } + foreach ($lst as $bill) { + $integral = bcadd($integral, $bill['number'], 0); + } + $integral2 = UserBill::getDB()->where('uid', $uid)->whereBetween('create_time', [$start, $end]) + ->where('category', 'integral')->where('pm', 1)->whereNotIn('type', ['lock', 'refund'])->sum('number'); + $integral3 = UserBill::getDB()->where('uid', $uid)->whereBetween('create_time', [$start, $end]) + ->where('category', 'integral')->where('type', 'sys_dec')->sum('number'); + return (int)max(bcsub(bcadd($integral, $integral2, 0), $integral3, 0), 0); + } + + +} diff --git a/app/common/dao/user/UserBrokerageDao.php b/app/common/dao/user/UserBrokerageDao.php new file mode 100644 index 00000000..a46f16b2 --- /dev/null +++ b/app/common/dao/user/UserBrokerageDao.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\UserBrokerage; + +class UserBrokerageDao extends BaseDao +{ + + protected function getModel(): string + { + return UserBrokerage::class; + } + + public function search(array $where) + { + return UserBrokerage::getDB()->when(isset($where['brokerage_name']) && $where['brokerage_name'] !== '', function ($query) use ($where) { + $query->whereLike('brokerage_name', "%{$where['brokerage_name']}%"); + })->when(isset($where['brokerage_level']) && $where['brokerage_level'] !== '', function ($query) use ($where) { + $query->where('brokerage_level', $where['brokerage_level']); + })->when(isset($where['next_level']) && $where['next_level'] !== '', function ($query) use ($where) { + $query->where('brokerage_level', '>', $where['next_level']); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('type', $where['type']); + }); + } + + public function fieldExists($field, $value, ?int $except = null, int $type = 0): bool + { + $query = ($this->getModel())::getDB()->where('type',$type)->where($field, $value); + if (!is_null($except)) $query->where($this->getPk(), '<>', $except); + return $query->count() > 0; + } +} diff --git a/app/common/dao/user/UserDao.php b/app/common/dao/user/UserDao.php new file mode 100644 index 00000000..be9e9159 --- /dev/null +++ b/app/common/dao/user/UserDao.php @@ -0,0 +1,357 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\User; +use think\Collection; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\Model; + +/** + * Class UserDao + * @package app\common\dao\user + * @author xaboy + * @day 2020-04-28 + */ +class UserDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return User::class; + } + + /** + * @return string + * @author xaboy + * @day 2020/6/22 + */ + public function defaultPwd() + { + return substr(md5(time() . random_int(10, 99)), 0, 8); + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-07 + */ + public function search(array $where) + { + if (isset($where['province']) && $where['province'] !== '') { + $query = User::hasWhere('wechat', function ($query) use ($where) { + $query->where('province', $where['province']); + if ($where['city'] !== '') $query->where('city', $where['city']); + }); + } else { + $query = User::getDB()->alias('User'); + } + $query->whereNull('User.cancel_time') + ->when(isset($where['keyword']) && $where['keyword'], function (BaseQuery $query) use ($where) { + return $query->where('User.uid|User.real_name|User.nickname|User.phone', 'like', '%' . $where['keyword'] . '%'); + })->when(isset($where['user_type']) && $where['user_type'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.user_type', $where['user_type']); + })->when(isset($where['uid']) && $where['uid'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.uid', $where['uid']); + })->when(isset($where['status']) && $where['status'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.status', intval($where['status'])); + })->when(isset($where['group_id']) && $where['group_id'], function (BaseQuery $query) use ($where) { + return $query->where('User.group_id', intval($where['group_id'])); + })->when(isset($where['brokerage_level']) && $where['brokerage_level'], function (BaseQuery $query) use ($where) { + return $query->where('User.brokerage_level', intval($where['brokerage_level'])); + })->when(isset($where['label_id']) && $where['label_id'] !== '', function (BaseQuery $query) use ($where) { + return $query->whereRaw('CONCAT(\',\',User.label_id,\',\') LIKE \'%,' . $where['label_id'] . ',%\''); + })->when(isset($where['sex']) && $where['sex'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.sex', intval($where['sex'])); + })->when(isset($where['is_promoter']) && $where['is_promoter'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.is_promoter', $where['is_promoter']); + })->when(isset($where['phone']) && $where['phone'] !== '', function (BaseQuery $query) use ($where) { + return $query->whereLike('User.phone', "%{$where['phone']}%"); + })->when(isset($where['nickname']) && $where['nickname'] !== '', function (BaseQuery $query) use ($where) { + return $query->whereLike('User.nickname', "%{$where['nickname']}%"); + })->when(isset($where['spread_time']) && $where['spread_time'] !== '', function (BaseQuery $query) use ($where) { + getModelTime($query, $where['spread_time'], 'User.spread_time'); + })->when(isset($where['date']) && $where['date'] !== '', function (BaseQuery $query) use ($where) { + getModelTime($query, $where['date'], 'User.create_time'); + })->when(isset($where['promoter_date']) && $where['promoter_date'] !== '', function (BaseQuery $query) use ($where) { + getModelTime($query, $where['promoter_date'], 'User.promoter_time'); + })->when(isset($where['spread_uid']) && $where['spread_uid'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.spread_uid', intval($where['spread_uid'])); + })->when(isset($where['spread_uids']), function (BaseQuery $query) use ($where) { + return $query->whereIn('User.spread_uid', $where['spread_uids']); + })->when(isset($where['uids']), function (BaseQuery $query) use ($where) { + return $query->whereIn('User.uid', $where['uids']); + })->when(isset($where['pay_count']) && $where['pay_count'] !== '', function ($query) use ($where) { + if ($where['pay_count'] == -1) { + $query->where('User.pay_count', 0); + } else { + $query->where('User.pay_count', '>', $where['pay_count']); + } + })->when(isset($where['user_time_type']) && $where['user_time_type'] !== '' && $where['user_time'] != '', function ($query) use ($where) { + if ($where['user_time_type'] == 'visit') { + getModelTime($query, $where['user_time'], 'User.last_time'); + } + if ($where['user_time_type'] == 'add_time') { + getModelTime($query, $where['user_time'], 'User.create_time'); + } + })->when(isset($where['sort']) && in_array($where['sort'], ['pay_count ASC', 'pay_count DESC', 'pay_price DESC', 'pay_price ASC', 'spread_count ASC', 'spread_count DESC']), function (BaseQuery $query) use ($where) { + $query->order('User.' . $where['sort']); + }, function ($query) { + $query->order('User.uid DESC'); + })->when(isset($where['is_svip']) && $where['is_svip'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.is_svip','>',0); + })->when(isset($where['svip_type']) && $where['svip_type'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('User.is_svip',$where['svip_type']); + }); + + return $query; + } + + /** + * @param $keyword + * @return BaseQuery + * @author xaboy + * @day 2020/6/22 + */ + public function searchMerUser($keyword) + { + return User::getDB()->whereLike('nickname', "%$keyword%")->whereNull('cancel_time')->where('status', 1); + } + + /** + * @param array $ids + * @param int $group_id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function batchChangeGroupId(array $ids, int $group_id) + { + return User::getDB()->whereIn($this->getPk(), $ids)->update(compact('group_id')); + } + + /** + * @param array $ids + * @param array $label_id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function batchChangeLabelId(array $ids, array $label_id) + { + $label_id = implode(',', $label_id); + return User::getDB()->whereIn($this->getPk(), $ids)->update(compact('label_id')); + } + + + /** + * @param int $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function wechatUserIdBytUser(int $id) + { + return User::getDB()->where('wechat_user_id', $id)->find(); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020-04-28 + */ + public function wechatUserIdByUid($id) + { + return User::getDB()->where('wechat_user_id', $id)->value('uid'); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/7/7 + */ + public function uidByWechatUserId($id) + { + return User::getDB()->where('uid', $id)->value('wechat_user_id'); + } + + /** + * @param $account + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function accountByUser($account) + { + return User::getDB()->where('account', $account)->find(); + } + + /** + * @param $uid + * @return array + * @author xaboy + * @day 2020/6/22 + */ + public function getSubIds($uid) + { + return User::getDB()->where('spread_uid', $uid)->column('uid'); + } + + /** + * @param $uid + * @return int + * @author xaboy + * @day 2020/6/22 + */ + public function getOneLevelCount($uid) + { + return User::getDB()->where('spread_uid', $uid)->count(); + } + + /** + * @param $uid + * @return int + * @author xaboy + * @day 2020/6/22 + */ + public function getTwoLevelCount($uid) + { + $ids = $this->getSubIds($uid); + return count($ids) ? User::getDB()->whereIn('spread_uid', $ids)->count() : 0; + } + + /** + * @param $ids + * @return array + * @author xaboy + * @day 2020/6/22 + */ + public function getSubAllIds(array $ids) + { + return User::getDB()->whereIn('spread_uid', $ids)->column('uid'); + } + + /** + * @param array $ids + * @param string $field + * @return Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function users(array $ids, $field = '*') + { + return User::getDB()->whereIn('uid', $ids)->field($field)->select(); + } + + public function newUserNum($date) + { + return User::getDB()->when($date, function ($query, $date) { + getModelTime($query, $date, 'create_time'); + })->count(); + } + + public function userOrderDetail($uid) + { + return User::getDB()->alias('A') + ->join('StoreOrder B', 'A.uid = B.uid and B.paid = 1 and B.pay_time between \'' . date('Y/m/d', strtotime('first day of')) . ' 00:00:00\' and \'' . date('Y/m/d H:i:s') . '\'') + ->join('PresellOrder C', 'C.order_id = B.order_id and C.paid = 1', 'LEFT') + ->field('A.uid,A.avatar,A.nickname,A.now_money,A.pay_price,A.pay_count, sum(B.pay_price + IFNULL(C.pay_price,0)) as total_pay_price, count(B.order_id) as total_pay_count,is_svip,svip_endtime,svip_save_money') + ->where('A.uid', $uid) + ->find(); + } + + public function userNumGroup($date) + { + return User::getDB()->when($date, function ($query, $date) { + getModelTime($query, $date, 'create_time'); + })->field(Db::raw('from_unixtime(unix_timestamp(create_time),\'%m-%d\') as time, count(uid) as new')) + ->group('time')->order('time ASC')->select(); + } + + public function idsByPayCount(array $ids) + { + return User::getDB()->whereIn('uid', $ids)->column('pay_count', 'uid'); + } + + public function beforeUserNum($date) + { + return User::getDB()->where('create_time', '<', $date)->count(); + } + + public function selfUserList($phone) + { + return User::getDB()->where('phone', $phone)->field('uid,nickname,avatar,user_type')->select(); + } + + public function initSpreadLimitDay(int $day) + { + return User::getDB()->where('spread_uid', '>', 0)->update(['spread_limit' => date('Y-m-d H:i:s', strtotime("+ $day day"))]); + } + + public function clearSpreadLimitDay() + { + return User::getDB()->where('spread_uid', '>', 0)->update(['spread_limit' => null]); + } + + public function updateSpreadLimitDay(int $day) + { + User::getDB()->where('spread_uid', '>', 0)->whereNull('spread_limit')->update(['spread_limit' => date('Y-m-d H:i:s', strtotime("+ $day day"))]); + return User::getDB()->where('spread_uid', '>', 0)->whereNotNull('spread_limit')->update(['spread_limit' => Db::raw('TIMESTAMPADD(DAY, ' . $day . ', `spread_limit`)')]); + } + + public function syncSpreadStatus() + { + return User::getDB()->where('spread_uid', '>', 0)->whereNotNull('spread_limit')->where('spread_limit', '<=', date('Y-m-d H:i:s'))->update(['spread_time' => null, 'spread_uid' => 0, 'spread_limit' => null]); + } + + public function incSpreadCount($uid) + { + User::getDB()->where('uid', $uid)->update([ + 'spread_count' => Db::raw('spread_count + 1') + ]); + } + + public function decSpreadCount($uid) + { + User::getDB()->where('uid', $uid)->where('spread_count','>',0)->update([ + 'spread_count' => Db::raw('spread_count - 1') + ]); + } +} diff --git a/app/common/dao/user/UserExtractDao.php b/app/common/dao/user/UserExtractDao.php new file mode 100644 index 00000000..8323d69c --- /dev/null +++ b/app/common/dao/user/UserExtractDao.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\user\UserExtract; +use app\common\model\user\UserExtract as model; + +class UserExtractDao extends BaseDao +{ + protected function getModel(): string + { + return model::class; + } + + public function search(array $where) + { + if(isset($where['wechat']) && $where['wechat'] != '') { + $query = model::hasWhere('user',function ($query)use($where){ + $query->where('nickname',"%{$where['wechat']}%"); + }); + }else{ + $query = model::alias('UserExtract'); + } + $query->when(isset($where['uid']) && $where['uid'] != '',function($query)use($where){ + $query->where('uid',$where['uid']); + })->when(isset($where['extract_type']) && $where['extract_type'] != '',function($query)use($where){ + $query->where('extract_type',$where['extract_type']); + })->when(isset($where['keyword']) && $where['keyword'] != '',function($query)use($where){ + $query->whereLike('UserExtract.real_name|UserExtract.uid|bank_code|alipay_code|wechat',"%{$where['keyword']}%"); + })->when(isset($where['status']) && $where['status'] != '',function($query)use($where){ + $query->where('UserExtract.status',$where['status']); + })->when(isset($where['real_name']) && $where['real_name'] != '',function($query)use($where){ + $query->where('UserExtract.real_name','%'.$where['real_name'].'%'); + })->when(isset($where['date']) && $where['date'] != '',function($query)use($where){ + getModelTime($query, $where['date']); + })->order('UserExtract.create_time DESC'); + + return $query; + } + + public function getPromoterInfo(array $uids) + { + return UserExtract::getDB()->field('sum(extract_price) as total_price,count(extract_id) as total_num, uid')->whereIn('uid', $uids)->group('uid')->where('status', 1)->select()->toArray(); + } +} diff --git a/app/common/dao/user/UserGroupDao.php b/app/common/dao/user/UserGroupDao.php new file mode 100644 index 00000000..9af39e77 --- /dev/null +++ b/app/common/dao/user/UserGroupDao.php @@ -0,0 +1,62 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\UserGroup; +use think\db\BaseQuery; + +/** + * Class UserGroupDao + * @package app\common\dao\user + * @author xaboy + * @day 2020-05-07 + */ +class UserGroupDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return UserGroup::class; + } + + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-06 + */ + public function search(array $where = []) + { + return UserGroup::getDB(); + } + + /** + * @return array + * @author xaboy + * @day 2020-05-07 + */ + public function allOptions() + { + return UserGroup::getDB()->column('group_name', 'group_id'); + } +} diff --git a/app/common/dao/user/UserHistoryDao.php b/app/common/dao/user/UserHistoryDao.php new file mode 100644 index 00000000..613d5837 --- /dev/null +++ b/app/common/dao/user/UserHistoryDao.php @@ -0,0 +1,77 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\user\UserHistory; + +class UserHistoryDao extends BaseDao +{ + protected function getModel(): string + { + return UserHistory::class; + } + + + public function createOrUpdate(array $data) + { + $ret = $this->getModel()::getDB()->where($data)->find(); + if($ret){ + $ret->update_time = time(); + $ret->save(); + }else{ + $data['update_time'] = time(); + $this->create($data); + } + } + + public function search(?int $uid, int $type) + { + $query = ($this->getModel()::getDB())->when($uid, function ($query) use ($uid) { + $query->where('uid', $uid); + })->when($type, function ($query) use ($type) { + $query->where('res_type', $type); + }); + + return $query->order('update_time DESC'); + } + + + public function deleteBatch($uid,$data) + { + if(is_array($data)){ + $this->getModel()::getDB()->where($this->getPk(),'in',$data)->delete(); + }else if($data == 1){ + $this->getModel()::getDB()->where('uid',$uid)->delete(); + } + } + + public function userTotalHistory($uid) + { + return $this->getModel()::getDB()->where('uid',$uid)->count(); + } + + public function joinSpu($where) + { + $query = UserHistory::hasWhere('spu',function($query) use($where){ + $query->when(isset($where['keyword']) && $where['keyword'] !== '', function($query) use ($where){ + $query->whereLike('store_name',"%{$where['keyword']}%"); + }); + $query->where(true); + }); + $query->where('uid', $where['uid']); + $query->where('res_type', $where['type']); + return $query; + } + +} diff --git a/app/common/dao/user/UserLabelDao.php b/app/common/dao/user/UserLabelDao.php new file mode 100644 index 00000000..6f5adf03 --- /dev/null +++ b/app/common/dao/user/UserLabelDao.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\UserLabel; +use think\db\BaseQuery; + +/** + * Class UserLabelDao + * @package app\common\dao\user + * @author xaboy + * @day 2020-05-07 + */ +class UserLabelDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return UserLabel::class; + } + + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-05-06 + */ + public function search(array $where = []) + { + return UserLabel::getDB()->when(!isset($where['all']) || $where['all'] === '', function ($query) use ($where) { + $query->where('type', 0); + })->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('mer_id', $where['mer_id']); + }, function ($query) { + $query->where('mer_id', 0); + }); + } + + /** + * @param int $merId + * @return array + * @author xaboy + * @day 2020/10/20 + */ + public function allOptions($merId = 0) + { + return UserLabel::getDB()->where('mer_id', $merId)->where('type', 0)->column('label_name', 'label_id'); + } + + /** + * @param array $ids + * @param int $merId + * @return array + * @author xaboy + * @day 2020/10/20 + */ + public function labels(array $ids, $merId = 0) + { + return UserLabel::getDB()->where('mer_id', $merId)->whereIn('label_id', $ids)->column('label_name'); + } + + /** + * @param int $id + * @param int $mer_id + * @return bool + * @author xaboy + * @day 2020/10/20 + */ + public function exists(int $id, $mer_id = 0) + { + return $this->existsWhere(['label_id' => $id, 'type' => 0, 'mer_id' => $mer_id]); + } + + public function existsName($name, $mer_id = 0, $type = 0, $except = null) + { + return UserLabel::where('label_name', $name)->where('mer_id', $mer_id)->where('type', $type) + ->when($except, function ($query, $except) { + $query->where($this->getPk(), '<>', $except); + })->count() > 0; + } + + public function intersection(array $ids, $merId, $type) + { + return UserLabel::getDB()->whereIn('label_id', $ids)->where('mer_id', $merId)->when(!is_null($type), function ($query) use ($type) { + $query->where('type', $type); + })->column('label_id'); + } +} diff --git a/app/common/dao/user/UserMerchantDao.php b/app/common/dao/user/UserMerchantDao.php new file mode 100644 index 00000000..fdd06656 --- /dev/null +++ b/app/common/dao/user/UserMerchantDao.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\UserLabel; +use app\common\model\user\UserMerchant; +use think\db\BaseQuery; + +/** + * Class UserMerchantDao + * @package app\common\dao\user + * @author xaboy + * @day 2020/10/20 + */ +class UserMerchantDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/10/20 + */ + protected function getModel(): string + { + return UserMerchant::class; + } + + /** + * @param $uid + * @param $mer_id + * @return bool + * @author xaboy + * @day 2020/10/20 + */ + public function isMerUser($uid, $mer_id) + { + return $this->existsWhere(compact('uid', 'mer_id')); + } + + /** + * @param $uid + * @param $mer_id + * @return int + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/10/20 + */ + public function updateLastTime($uid, $mer_id) + { + return UserMerchant::getDB()->where(compact('uid', 'mer_id'))->update([ + 'last_time' => date('Y-m-d H:i:s') + ]); + } + + /** + * @param array $where + * @return mixed + * @author xaboy + * @day 2020/10/20 + */ + public function search(array $where) + { + return UserMerchant::getDB()->alias('A')->leftJoin('User B', 'A.uid = B.uid') + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->where('A.mer_id', $where['mer_id']); + })->when(isset($where['nickname']) && $where['nickname'], function (BaseQuery $query) use ($where) { + return $query->where('B.nickname', 'like', '%' . $where['nickname'] . '%'); + })->when(isset($where['sex']) && $where['sex'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('B.sex', intval($where['sex'])); + })->when(isset($where['is_promoter']) && $where['is_promoter'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('B.is_promoter', $where['is_promoter']); + })->when(isset($where['uids']), function (BaseQuery $query) use ($where) { + return $query->whereIn('A.uid', $where['uids']); + })->when(isset($where['user_time_type']) && $where['user_time_type'] !== '' && $where['user_time'] != '', function ($query) use ($where) { + if ($where['user_time_type'] == 'visit') { + getModelTime($query, $where['user_time'], 'A.last_time'); + } + if ($where['user_time_type'] == 'add_time') { + getModelTime($query, $where['user_time'], 'A.create_time'); + } + })->when(isset($where['pay_count']) && $where['pay_count'] !== '', function ($query) use ($where) { + if ($where['pay_count'] == -1) { + $query->where('A.pay_num', 0); + } else { + $query->where('A.pay_num', '>', $where['pay_count']); + } + })->when(isset($where['label_id']) && $where['label_id'] !== '', function (BaseQuery $query) use ($where) { + return $query->whereRaw('CONCAT(\',\',A.label_id,\',\') LIKE \'%,' . $where['label_id'] . ',%\''); + })->when(isset($where['user_type']) && $where['user_type'] !== '', function (BaseQuery $query) use ($where) { + return $query->where('B.user_type', $where['user_type']); + })->where('A.status', 1); + } + + public function numUserIds($mer_id, $min, $max = null) + { + return UserMerchant::getDB()->where('mer_id', $mer_id)->where('pay_num', '>=', $min)->when(!is_null($max), function ($query) use ($max) { + $query->where('pay_num', '<=', $max); + })->group('uid')->column('uid'); + } + + public function priceUserIds($mer_id, $min, $max = null) + { + return UserMerchant::getDB()->where('mer_id', $mer_id)->where('pay_price', '>=', $min)->when(!is_null($max), function ($query) use ($max, $min) { + $query->where('pay_price', $min == $max ? '<=' : '<', $max); + })->group('uid')->column('uid'); + } +} diff --git a/app/common/dao/user/UserOrderDao.php b/app/common/dao/user/UserOrderDao.php new file mode 100644 index 00000000..ff11ffec --- /dev/null +++ b/app/common/dao/user/UserOrderDao.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\user\LabelRule; +use app\common\model\user\UserOrder; + +class UserOrderDao extends BaseDao +{ + + protected function getModel(): string + { + return UserOrder::class; + } + + public function search(array $where) + { + return UserOrder::hasWhere('user',function($query)use($where){ + $query->when(isset($where['uid']) && $where['uid'] != '',function($query) use($where){ + $query->where('uid', $where['uid']); + }) + ->when(isset($where['keyword']) && $where['keyword'] != '',function($query) use($where){ + $query->whereLike('nickname', "%{$where['keyword']}%"); + }) + ->when(isset($where['phone']) && $where['phone'] != '',function($query) use($where){ + $query->where('phone', $where['phone']); + }); + $query->where(true); + }) + ->when(isset($where['order_sn']) && $where['order_sn'] !== '', function ($query) use ($where) { + $query->whereLike('order_sn', "%{$where['order_sn']}%"); + }) + ->when(isset($where['title']) && $where['title'] !== '', function ($query) use ($where) { + $query->whereLike('title', "%{$where['title']}%"); + }) + ->when(isset($where['order_type']) && $where['order_type'] !== '', function ($query) use ($where) { + $query->where('order_type', $where['order_type']); + }) + ->when(isset($where['paid']) && $where['paid'] !== '', function ($query) use ($where) { + $query->where('paid', $where['paid']); + }) + ->when(isset($where['pay_type']) && $where['pay_type'] !== '', function ($query) use ($where) { + $query->where('pay_type', $where['pay_type']); + }) + ->when(isset($where['pay_time']) && $where['pay_time'] !== '', function ($query) use ($where) { + $query->whereDay('pay_time', $where['pay_time']); + }) + ->when(isset($where['mer_id']) && $where['mer_id'] !== '', function ($query) use ($where) { + $query->whereDay('mer_id', $where['mer_id']); + }) + ->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'UserOrder.create_time'); + }) + ; + } +} diff --git a/app/common/dao/user/UserReceiptDao.php b/app/common/dao/user/UserReceiptDao.php new file mode 100644 index 00000000..67d78ad3 --- /dev/null +++ b/app/common/dao/user/UserReceiptDao.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\user; + +use app\common\dao\BaseDao; +use app\common\model\user\UserReceipt; +use think\facade\Db; + +class UserReceiptDao extends BaseDao +{ + + protected function getModel(): string + { + return UserReceipt::class; + } + + /** + * TODO 设置默认 + * @param int $id + * @param int $uid + * @author Qinii + * @day 2020-10-16 + */ + public function isDefault(int $id, int $uid) + { + Db::transaction(function()use($id,$uid){ + $this->clearDefault($uid); + $this->getModel()::getDB()->where($this->getPk(),$id)->update(['is_default' => 1]); + }); + } + + /** + * TODO 清楚其他默认 + * @param int $uid + * @author Qinii + * @day 2020-10-20 + */ + public function clearDefault(int $uid) + { + $this->getModel()::getDB()->where('uid',$uid)->update(['is_default' => 0]); + } +} diff --git a/app/common/dao/user/UserRechargeDao.php b/app/common/dao/user/UserRechargeDao.php new file mode 100644 index 00000000..e83ae529 --- /dev/null +++ b/app/common/dao/user/UserRechargeDao.php @@ -0,0 +1,90 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\user\UserRecharge; +use app\common\repositories\store\order\StoreOrderRepository; +use think\db\BaseQuery; + +/** + * Class UserRechargeDao + * @package app\common\dao\user + * @author xaboy + * @day 2020/6/2 + */ +class UserRechargeDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/6/2 + */ + protected function getModel(): string + { + return UserRecharge::class; + } + + public function createOrderId($uid) + { + $count = (int)UserRecharge::getDB()->where('uid', $uid)->where('create_time', '>=', date("Y-m-d"))->where('create_time', '<', date("Y-m-d", strtotime('+1 day')))->count(); + return StoreOrderRepository::TYPE_SN_USER_RECHARGE . date('YmdHis', time()) . ($uid . $count); + } + + public function userRechargePrice($uid) + { + return UserRecharge::getDB()->where('uid', $uid)->where('paid', 1)->sum('price'); + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020/6/23 + */ + public function searchJoinQuery(array $where) + { + return UserRecharge::getDB()->alias('a')->join('User b', 'a.uid = b.uid') + ->field('a.paid,a.order_id,a.recharge_id,b.nickname,b.avatar,a.price,a.give_price,a.recharge_type,a.pay_time') + ->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('b.nickname|a.order_id', "%{$where['keyword']}%"); + })->when(isset($where['paid']) && $where['paid'] !== '', function ($query) use ($where) { + $query->whereLike('a.paid', $where['paid']); + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'a.create_time'); + }); + } + + public function totalPayPrice() + { + return UserRecharge::getDB()->where('paid', 1)->sum('price'); + } + + public function totalRefundPrice() + { + return UserRecharge::getDB()->where('paid', 1)->sum('refund_price'); + } + + public function totalRoutinePrice() + { + return UserRecharge::getDB()->where('paid', 1)->where('recharge_type', 'routine')->sum('price'); + } + + public function totalWxPrice() + { + return UserRecharge::getDB()->where('paid', 1)->whereIn('recharge_type', ['h5', 'wechat'])->sum('price'); + } +} diff --git a/app/common/dao/user/UserRelationDao.php b/app/common/dao/user/UserRelationDao.php new file mode 100644 index 00000000..5d5792da --- /dev/null +++ b/app/common/dao/user/UserRelationDao.php @@ -0,0 +1,129 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\user\UserRelation; +use app\common\model\user\UserRelation as model; + +/** + * Class UserVisitDao + * @package app\common\dao\user + * @author xaboy + * @day 2020/5/27 + */ +class UserRelationDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/27 + */ + protected function getModel(): string + { + return model::class; + } + + /** + * @param $field + * @param $value + * @param null $type + * @param null $uid + * @return mixed + * @author Qinii + */ + public function apiFieldExists($field, $value, $type = null, $uid = null) + { + return $this->getModel()::getDB()->when($uid, function ($query) use ($uid) { + $query->where('uid', $uid); + })->when(!is_null($type), function ($query) use ($type) { + $query->where('type', $type); + })->where($field, $value); + } + + /** + * @param $where + * @return mixed + * @author Qinii + */ + public function search($where) + { + $query = ($this->getModel()::getDB()) + ->when((isset($where['type']) && $where['type'] !== ''), function ($query) use ($where) { + if(in_array($where['type'],[1,2,3,4])){ + $query->whereIn('type',[1,2,3,4]); + }else{ + $query->where('type',$where['type']); + } + })->when((isset($where['uid']) && $where['uid']), function ($query) use ($where) { + $query->where('uid', $where['uid']); + }); + + return $query->order('create_time DESC'); + } + + + /** + * @param array $where + * @author Qinii + */ + public function destory(array $where) + { + ($this->getModel()::getDB())->where($where)->delete(); + } + + public function dayLikeStore($day, $merId = null) + { + return getModelTime(UserRelation::getDB()->where('type', 10)->when($merId, function ($query, $merId) { + $query->where('type_id', $merId); + }), $day)->count(); + } + + public function dateVisitStore($date, $merId = null) + { + return UserRelation::getDB()->where('type', 11)->when($merId, function ($query, $merId) { + $query->where('type_id', $merId); + })->when($date, function ($query, $date) { + getModelTime($query, $date, 'create_time'); + })->count(); + } + + + /** + * @param $uid + * @param array $ids + * @return array + * @author xaboy + * @day 2020/10/20 + */ + public function intersectionPayer($uid, array $ids): array + { + return UserRelation::getDB()->where('uid', $uid)->whereIn('type', 12)->whereIn('type_id', $ids)->column('type_id'); + } + + public function getUserProductToCommunity(?string $keyword, int $uid) + { + + $query = UserRelation::hasWhere('spu', function ($query) use($keyword) { + $query->when($keyword, function ($query) use($keyword) { + $query->whereLike('store_name',"%{$keyword}%"); + }); + $query->where('status',1); + }); + $query->where('uid',$uid); + return $query; + } +} diff --git a/app/common/dao/user/UserSignDao.php b/app/common/dao/user/UserSignDao.php new file mode 100644 index 00000000..42b5fe5f --- /dev/null +++ b/app/common/dao/user/UserSignDao.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\user\UserSign; + +class UserSignDao extends BaseDao +{ + + protected function getModel(): string + { + return UserSign::class; + } +} diff --git a/app/common/dao/user/UserSpreadLogDao.php b/app/common/dao/user/UserSpreadLogDao.php new file mode 100644 index 00000000..2b1fcfaf --- /dev/null +++ b/app/common/dao/user/UserSpreadLogDao.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\user\UserSpreadLog; + +class UserSpreadLogDao extends BaseDao +{ + + protected function getModel(): string + { + return UserSpreadLog::class; + } + + public function add($uid, $spread_uid, $old_spread_uid, $admin_id = 0) + { + $this->create(compact('uid', 'spread_uid', 'admin_id', 'old_spread_uid')); + } + + public function search($where) + { + return UserSpreadLog::getDB()->when(isset($where['uid']) && $where['uid'] !== '', function ($query) use ($where) { + $query->where('uid', $where['uid']); + })->order('create_time DESC'); + } +} diff --git a/app/common/dao/user/UserVisitDao.php b/app/common/dao/user/UserVisitDao.php new file mode 100644 index 00000000..c34a84af --- /dev/null +++ b/app/common/dao/user/UserVisitDao.php @@ -0,0 +1,217 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\user; + + +use app\common\dao\BaseDao; +use app\common\model\user\UserVisit; +use think\facade\Db; +use think\Model; + +/** + * Class UserVisitDao + * @package app\common\dao\user + * @author xaboy + * @day 2020/5/27 + */ +class UserVisitDao extends BaseDao +{ + + /** + * @return string + * @author xaboy + * @day 2020/5/27 + */ + protected function getModel(): string + { + return UserVisit::class; + } + + /** + * @param int $uid + * @param string $type + * @param int $type_id + * @param string|null $content + * @return BaseDao|Model + * @author xaboy + * @day 2020/5/27 + */ + public function addVisit(int $uid, string $type, int $type_id, ?string $content = '') + { + return $this->create(compact('uid', 'type', 'type_id', 'content')); + } + + /** + * @param int $uid + * @param int $productId + * @return BaseDao|Model + * @author xaboy + * @day 2020/5/27 + */ + public function visitProduct(int $uid, int $productId) + { + return $this->addVisit($uid, 'product', $productId); + } + + /** + * @param int $uid + * @param string $page + * @return BaseDao|Model + * @author xaboy + * @day 2020/5/27 + */ + public function visitPage(int $uid, string $page) + { + return $this->addVisit($uid, 'page', 0, $page); + } + + /** + * @param int $uid + * @param string $page + * @return BaseDao|Model + * @author xaboy + * @day 2020/5/27 + */ + public function visitSmallProgram(int $uid, string $page) + { + return $this->addVisit($uid, 'smallProgram', 0, $page); + } + + /** + * @param int $uid + * @param string $keyword + * @return BaseDao|Model + * @author xaboy + * @day 2020/5/27 + */ + public function searchProduct(int $uid, string $keyword, int $merId = 0) + { + return $this->addVisit($uid, 'searchProduct', $merId, $keyword); + } + + /** + * @param int $uid + * @param string $keyword + * @return BaseDao|Model + * @author xaboy + * @day 2020/5/27 + */ + public function searchMerchant(int $uid, string $keyword) + { + return $this->addVisit($uid, 'searchMerchant', 0, $keyword); + } + + /** + * @param $uid + * @return int + * @author xaboy + * @day 2020/6/19 + */ + public function userTotalVisit($uid) + { + return UserVisit::getDB()->where('uid', $uid)->where('type', 'product')->count(); + } + + + public function search(array $where) + { + if ((isset($where['nickname']) && $where['nickname'] !== '') || (isset($where['user_type']) && $where['user_type'] !== '')) { + $query = UserVisit::hasWhere('user', function ($query) use ($where) { + $query->when(isset($where['nickname']) && $where['nickname'] !== '', function ($query) use ($where) { + $query->whereLike('User.nickname', "%{$where['nickname']}%"); + })->when(isset($where['user_type']) && $where['user_type'] !== '', function ($query) use ($where) { + $query->where('User.user_type', $where['user_type']); + }); + }); + } else { + $query = UserVisit::getDB()->alias('UserVisit'); + } + $query = $query->when(isset($where['uid']), function ($query) use ($where) { + $query->where('UserVisit.uid', $where['uid']); + })->when(isset($where['mer_id']), function ($query) use ($where) { + $query->where('UserVisit.type_id', $where['mer_id']); + })->when(isset($where['type']), function ($query) use ($where) { + if(is_array($where['type'])){ + $query->where('UserVisit.type','in', $where['type']); + }else{ + $query->where('UserVisit.type', $where['type']); + } + })->when(isset($where['date']) && $where['date'] !== '', function ($query) use ($where) { + getModelTime($query, $where['date'], 'UserVisit.create_time'); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->whereLike('UserVisit.content', "%{$where['keyword']}%"); + }); + + return $query->order('UserVisit.create_time DESC'); + } + + public function dateVisitUserNum($date, $merId = null) + { + return UserVisit::getDB()->alias('A')->join('StoreProduct B', 'A.type_id = B.product_id')->when($date, function ($query, $date) { + getModelTime($query, $date, 'A.create_time'); + })->when($merId, function ($query, $merId) { + $query->where('B.mer_id', $merId); + })->where('A.type', 'product')->group('uid')->count(); + } + + public function dateVisitMerchantNum($date, $limit = 7) + { + return UserVisit::getDB()->alias('A')->join('StoreProduct B', 'A.type_id = B.product_id') + ->join('Merchant C', 'C.mer_id = B.mer_id') + ->field(Db::raw('count(A.type) as total,B.mer_id,C.mer_name')) + ->when($date, function ($query, $date) { + getModelTime($query, $date, 'A.create_time'); + })->where('A.type', 'product')->limit($limit)->group('B.mer_id')->order('total DESC')->select(); + } + + public function dateVisitProductNum($date, $merId, $limit = 7) + { + return UserVisit::getDB()->alias('A')->join('StoreProduct B', 'A.type_id = B.product_id') + ->join('Merchant C', 'C.mer_id = B.mer_id') + ->field(Db::raw('count(A.type_id) as total,B.image,B.store_name')) + ->when($date, function ($query, $date) { + getModelTime($query, $date, 'A.create_time'); + })->where('A.type', 'product')->where('B.mer_id', $merId)->group('A.type_id')->order('total DESC') + ->limit($limit)->select(); + } + + public function dateVisitMerchantTotal($date) + { + return UserVisit::getDB()->when($date, function ($query, $date) { + getModelTime($query, $date, 'create_time'); + })->whereIn('type', 'product')->count(); + } + + public function dateVisitNum($date) + { + return UserVisit::getDB()->when($date, function ($query, $date) { + getModelTime($query, $date, 'create_time'); + })->whereIn('type', ['page', 'smallProgram'])->count(); + } + + public function dateVisitNumGroup($date) + { + return UserVisit::getDB()->when($date, function ($query, $date) { + getModelTime($query, $date, 'create_time'); + })->field(Db::raw('from_unixtime(unix_timestamp(create_time),\'%m-%d\') as time, count(DISTINCT uid) as total')) + ->group('time') + ->order('time ASC')->select(); + } + + public function batchDelete(? array $ids,?int $uid) + { + if($ids) return UserVisit::getDB()->where($this->getPk(),'in',$ids)->delete(); + if($uid) return UserVisit::getDB()->where('uid',$uid)->where('type','product')->delete(); + } +} diff --git a/app/common/dao/wechat/RoutineQrcodeDao.php b/app/common/dao/wechat/RoutineQrcodeDao.php new file mode 100644 index 00000000..723112ba --- /dev/null +++ b/app/common/dao/wechat/RoutineQrcodeDao.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\wechat; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\wechat\RoutineQrcode; + +class RoutineQrcodeDao extends BaseDao +{ + + protected function getModel(): string + { + return RoutineQrcode::class; + } + + /** + * TODO 添加二维码 存在直接获取 + * @param int $thirdId + * @param string $thirdType + * @param string $page + * @param string $qrCodeLink + * @return array|false|object|\PDOStatement|string|\think\Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function routineQrCodeForever($thirdId = 0, $thirdType = 'spread', $page = '', $qrCodeLink = '') + { + $count = RoutineQrcode::where('third_id', $thirdId)->where('third_type', $thirdType)->count(); + if ($count) return RoutineQrcode::where('third_id', $thirdId)->where('third_type', $thirdType)->field('routine_qrcode_id')->find(); + return $this->setRoutineQrcodeForever($thirdId, $thirdType, $page, $qrCodeLink); + } + + /** + * 添加二维码记录 + * @param int $thirdId + * @param string $thirdType + * @param string $page + * @param string $qrCodeLink + * @return object + */ + public static function setRoutineQrcodeForever($thirdId = 0, $thirdType = 'spread', $page = '', $qrCodeLink = '') + { + $data['third_type'] = $thirdType; + $data['third_id'] = $thirdId; + $data['status'] = 1; + $data['add_time'] = time(); + $data['page'] = $page; + $data['qrcode_url'] = $qrCodeLink; + return RoutineQrcode::create($data); + } + + /** + * 修改二维码地址 + * @param int $id + * @param array $data + * @return bool + * @throws \think\db\exception\DbException + */ + public function setRoutineQrcodeFind($id = 0, $data = array()) + { + if (!$id) return false; + $count = $this->getRoutineQrcodeFind($id); + if (!$count) return false; + return $this->update($id, $data); + } + + /** + * 获取二维码是否存在 + * @param int $id + * @return int|string + */ + public function getRoutineQrcodeFind($id = 0) + { + if (!$id) return 0; + return RoutineQrcode::where('routine_qrcode_id', $id)->count(); + } + + /** + * 获取小程序二维码信息 + * @param int $id + * @param string $field + * @return array|bool|false|\PDOStatement|string|\think\Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getRoutineQrcodeFindType($id = 0, $field = 'third_type,third_id,page') + { + if (!$id) return false; + $count = $this->getRoutineQrcodeFind($id); + if (!$count) return false; + return RoutineQrcode::where('routine_qrcode_id', $id)->where('status', 1)->field($field)->find(); + } +} diff --git a/app/common/dao/wechat/TemplateMessageDao.php b/app/common/dao/wechat/TemplateMessageDao.php new file mode 100644 index 00000000..2580f20f --- /dev/null +++ b/app/common/dao/wechat/TemplateMessageDao.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\wechat; + +use app\common\dao\BaseDao; +use app\common\model\wechat\TemplateMessage; + +class TemplateMessageDao extends BaseDao +{ + protected function getModel(): string + { + return TemplateMessage::class; + } + + + public function search(array $where) + { + return ($this->getModel()::getDB())->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) { + $query->where('status', $where['status']); + })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) { + $query->where('type', $where['type']); + })->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) { + $query->where(function($query)use($where) { + $query->where('name', 'like', '%' . $where['keyword'] . '%'); + $query->whereOr('tempid', 'like', '%' . $where['keyword'] . '%'); + }); + })->order('create_time DESC'); + } + + public function getTempId($key, $type) + { + return TemplateMessage::getDB()->where(['type' => $type, 'tempkey' => $key])->value('tempid'); + } +} diff --git a/app/common/dao/wechat/WechatNewsDao.php b/app/common/dao/wechat/WechatNewsDao.php new file mode 100644 index 00000000..cbbd62b5 --- /dev/null +++ b/app/common/dao/wechat/WechatNewsDao.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\dao\wechat; + +use app\common\dao\BaseDao; +use app\common\model\wechat\WechatNews; + +class WechatNewsDao extends BaseDao +{ + + protected function getModel(): string + { + return WechatNews::class; + } + + /** + * 根据主键查询 + * @param int $merId + * @param int $id + * @param null $except + * @return bool + * @author Qinii + */ + public function merExists(int $merId, int $id, $except = null) + { + return $this->merFieldExists($merId, $this->getPk(), $id, $except); + } + + /** + * 根据 字段名查询 + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + * @author Qinii + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB()->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + })->where('mer_id', $merId)->where($field, $value)->count() > 0; + } + + public function getAll(array $where) + { + if(isset($where['cate_name']) && $where['cate_name'] !== ''){ + $query = WechatNews::hasWhere('article',function ($query)use($where){ + $query->whereLike('title',"%{$where['cate_name']}%"); + }); + }else{ + $query = WechatNews::alias('WechatNews'); + } + $query->with('article'); + return $query->order('WechatNews.create_time DESC'); + } + + public function get( $id, int $merId = 0) + { + return ($this->getModel())::getDB()->where('mer_id',$merId)->with('article.content')->find($id); + } +} diff --git a/app/common/dao/wechat/WechatQrcodeDao.php b/app/common/dao/wechat/WechatQrcodeDao.php new file mode 100644 index 00000000..92f6c20e --- /dev/null +++ b/app/common/dao/wechat/WechatQrcodeDao.php @@ -0,0 +1,87 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\wechat; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\wechat\WechatQrcode; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class WechatQrcodeDao + * @package app\common\dao\wechat + * @author xaboy + * @day 2020-04-28 + */ +class WechatQrcodeDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return WechatQrcode::class; + } + + /** + * @param $ticket + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function ticketByQrcode($ticket) + { + return WechatQrcode::getDB()->where('ticket', $ticket)->find(); + } + + /** + * @param $type + * @param $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function getForeverQrcode($type, $id) + { + return WechatQrcode::getDB()->where('third_id', $id)->where('third_type', $type)->where('expire_seconds', 0)->find(); + } + + /** + * @param $type + * @param $id + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function getTemporaryQrcode($type, $id) + { + return WechatQrcode::getDB()->where('third_id', $id)->where('third_type', $type)->where('expire_seconds', '>', 0)->find(); + } +} diff --git a/app/common/dao/wechat/WechatReplyDao.php b/app/common/dao/wechat/WechatReplyDao.php new file mode 100644 index 00000000..be7a1f05 --- /dev/null +++ b/app/common/dao/wechat/WechatReplyDao.php @@ -0,0 +1,101 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\wechat; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\wechat\WechatReply; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class WechatReplyDao + * @package app\common\dao\wechat + * @author xaboy + * @day 2020-04-24 + */ +class WechatReplyDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return WechatReply::class; + } + + /** + * @param string $key + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-24 + */ + public function keyByReply(string $key) + { + return WechatReply::where('key', $key)->find(); + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-04-24 + */ + public function search(array $where) + { + $query = WechatReply::getDB()->where('hidden', 0); + if (isset($where['keyword']) && $where['keyword']) + $query->whereLike('key', "%{$where['keyword']}%"); + + return $query; + } + + /** + * @param int $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-24 + */ + public function delete(int $id) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->where('hidden', 0)->delete(); + } + + /** + * @param $key + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function keyByValidData($key) + { + return WechatReply::getDB()->where(function ($query) use ($key) { + $query->where('key', $key)->whereFieldRaw('CONCAT(\',\',`key`,\',\')', 'LIKE', '%,' . $key . ',%', 'OR'); + })->where('status', 1)->find(); + } +} diff --git a/app/common/dao/wechat/WechatUserDao.php b/app/common/dao/wechat/WechatUserDao.php new file mode 100644 index 00000000..a0157d94 --- /dev/null +++ b/app/common/dao/wechat/WechatUserDao.php @@ -0,0 +1,178 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\dao\wechat; + + +use app\common\dao\BaseDao; +use app\common\model\BaseModel; +use app\common\model\wechat\WechatUser; +use think\db\BaseQuery; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class WechatUserDao + * @package app\common\dao\wechat + * @author xaboy + * @day 2020-04-28 + */ +class WechatUserDao extends BaseDao +{ + + /** + * @return BaseModel + * @author xaboy + * @day 2020-03-30 + */ + protected function getModel(): string + { + return WechatUser::class; + } + + /** + * @param string $openId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function openIdByWechatUser(string $openId) + { + return WechatUser::getDB()->where('openid', $openId)->find(); + } + + /** + * @param string $unionId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function unionIdByWechatUser(string $unionId) + { + return WechatUser::getDB()->where('unionid', $unionId)->find(); + } + + /** + * @param string $openId + * @return mixed + * @author xaboy + * @day 2020-04-28 + */ + public function openIdById(string $openId) + { + return WechatUser::getDB()->where('openid', $openId)->value('wechat_user_id'); + } + + /** + * @param string $openId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function routineIdByWechatUser(string $openId) + { + return WechatUser::getDB()->where('routine_openid', $openId)->find(); + } + + /** + * @param string $unionId + * @return mixed + * @author xaboy + * @day 2020-04-28 + */ + public function unionIdById(string $unionId) + { + return WechatUser::getDB()->where('unionid', $unionId)->value('wechat_user_id'); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/5/30 + */ + public function idByOpenId(int $id) + { + return WechatUser::getDB()->where('wechat_user_id', $id)->value('openid'); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/5/30 + */ + public function idByRoutineId(int $id) + { + return WechatUser::getDB()->where('wechat_user_id', $id)->value('routine_openid'); + } + + /** + * @param string $openId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-28 + */ + public function unsubscribe(string $openId) + { + return WechatUser::getDB()->where('openid', $openId)->update(['subscribe' => 0]); + } + + /** + * @param $id + * @return bool + * @author xaboy + * @day 2020-05-11 + */ + public function isSubscribeWechatUser($id) + { + return WechatUser::getDB()->where('wechat_user_id', $id)->whereNotNull('openid')->where('subscribe', 1)->count() > 0; + } + + /** + * @param array $where + * @return BaseQuery + * @author xaboy + * @day 2020-04-29 + */ + public function search(array $where) + { + $query = WechatUser::getDB()->whereNotNull('openid')->whereNotNull('routine_openid')->order('wechat_user_id desc'); + if (isset($where['nickname']) && $where['nickname']) $query->where('nickname', 'LIKE', "%$where[nickname]%"); + if (isset($where['add_time']) && $where['add_time']) getModelTime($query, $where['add_time']); + if (isset($where['tagid_list']) && $where['tagid_list']) { + $tagid_list = explode(',', $where['tagid_list']); + foreach ($tagid_list as $v) { + $query->where('tagid_list', 'LIKE', "%$v%"); + } + } + if (isset($where['groupid']) && $where['groupid']) $query->where('groupid', $where['groupid']); + if (isset($where['sex']) && $where['sex']) $model = $query->where('sex', $where['sex']); + if (isset($where['subscribe']) && $where['subscribe']) $query->where('subscribe', $where['subscribe']); + + + return $query; + } +} diff --git a/app/common/middleware/AdminAuthMiddleware.php b/app/common/middleware/AdminAuthMiddleware.php new file mode 100644 index 00000000..815a30df --- /dev/null +++ b/app/common/middleware/AdminAuthMiddleware.php @@ -0,0 +1,90 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\system\auth\MenuRepository; +use app\common\repositories\system\auth\RoleRepository; +use app\Request; +use think\exception\ValidateException; +use think\Response; + +class AdminAuthMiddleware extends BaseMiddleware +{ + + public function before(Request $request) + { + $admin = $request->adminInfo(); + + /** @var RoleRepository $role */ + $role = app()->make(RoleRepository::class); + + /** @var MenuRepository $menu */ + $menu = app()->make(MenuRepository::class); + + if ($admin->level) { + $rules = $role->idsByRules(0, $admin->roles); + $menus = $menu->idsByRoutes($rules); + } else { + $rules = []; + $menus = []; + } + + $request->macro('adminAuth', function () use (&$menus) { + return $menus; + }); + + $request->macro('adminRule', function () use (&$rules) { + return $rules; + }); + + $request->macro('checkAuth', function ($name, $vars) use (&$admin, &$menus, &$menu) { + if (!$name || !$admin->level) return true; + $isset = false; + foreach ($menus as $_menu) { + $keys = $menu->tidyParams($_menu['params']); + if ($_menu['route'] != $name) continue; + $isset = true; + if (!count($keys)) return true; + if ($menu->checkParams($keys, $vars)) + return true; + } + if ($isset || $menu->routeExists($name)) + return false; + return true; + }); + + $rule = $request->rule(); + if (!$rule) { + return true; + } + $options = $rule->getOption(); + if (!($options['_auth'] ?? true) && !isset($options['_form'])) { + return true; + } + if (isset($options['_form'])) { + $name = $options['_form']; + $var = $options['_form_val'] ?? []; + } else { + $name = $rule->getName(); + $var = $rule->getVars(); + } + if (!$request->checkAuth($name, $var)) + throw new ValidateException('没有权限访问'); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/AdminTokenMiddleware.php b/app/common/middleware/AdminTokenMiddleware.php new file mode 100644 index 00000000..5bc54e31 --- /dev/null +++ b/app/common/middleware/AdminTokenMiddleware.php @@ -0,0 +1,105 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\system\admin\AdminRepository; +use app\Request; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use Firebase\JWT\ExpiredException; +use think\exception\ValidateException; +use think\facade\Route; +use think\Response; +use Throwable; + +class AdminTokenMiddleware extends BaseMiddleware +{ + + /** + * @param Request $request + * @throws Throwable + * @author xaboy + * @day 2020-04-10 + */ + public function before(Request $request) + { + $force = $this->getArg(0, true); + try { + $token = trim($request->header('X-Token')); + if(!$token) $token = trim($request->param('token','')); + if (strpos($token, 'Bearer') === 0) + $token = trim(substr($token, 6)); + if (!$token) + throw new ValidateException('请登录'); + + /** + * @var AdminRepository $repository + */ + $repository = app()->make(AdminRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + throw new AuthException('token 已过期'); + } + if ('admin' != $payload->jti[1]) + throw new AuthException('无效的 token'); + + $admin = $repository->get($payload->jti[0]); + if (!$admin) + throw new AuthException('账号不存在'); + if (!$admin['status']) + throw new AuthException('账号已被禁用'); + + } catch (Throwable $e) { + if ($force) + throw $e; + $request->macro('isLogin', function () { + return false; + }); + $request->macros(['tokenInfo', 'adminId', 'adminInfo', 'token'], function () { + throw new AuthException('请登录'); + }); + return; + } + $repository->updateToken($token); + + $request->macro('isLogin', function () { + return true; + }); + $request->macro('tokenInfo', function () use (&$payload) { + return $payload; + }); + $request->macro('token', function () use (&$token) { + return $token; + }); + $request->macro('adminId', function () use (&$admin) { + return $admin->admin_id; + }); + $request->macro('adminInfo', function () use (&$admin) { + return $admin; + }); + $request->macro('userType', function () { + return 2; + }); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/AllowOriginMiddleware.php b/app/common/middleware/AllowOriginMiddleware.php new file mode 100644 index 00000000..e58a25f8 --- /dev/null +++ b/app/common/middleware/AllowOriginMiddleware.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + + + +namespace app\common\middleware; + + +use app\Request; +use think\exception\HttpResponseException; +use think\facade\Config; +use think\Response; + +/** + * 跨域中间件 + * Class AllowOriginMiddleware + * @package app\http\middleware + */ +class AllowOriginMiddleware extends BaseMiddleware +{ + /** + * header头 + * @var array + */ + protected $header = [ + 'Access-Control-Allow-Origin' => '*', + 'Access-Control-Allow-Headers' => 'X-Token, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With,Form-type,Referer,Connection,Content-Length,Host,Origin,Authorization,Authori-zation,Accept,Accept-Encoding', + //,Host,Origin,Authorization,Authori-zation,Accept,Accept-Encoding + //'Access-Control-Allow-Headers' => '*', + 'Access-Control-Allow-Methods' => 'GET,POST,PATCH,PUT,DELETE,OPTIONS', + 'Access-Control-Max-Age' => '1728000' + ]; + + public function before(Request $request) + { + $cookieDomain = Config::get('cookie.domain', ''); + $origin = $request->header('origin'); + + if ($origin && $cookieDomain && strpos($origin, $cookieDomain)) + $this->header['Access-Control-Allow-Origin'] = $origin; + if ($request->method(true) == 'OPTIONS') { + throw new HttpResponseException(Response::create()->code(200)->header($this->header)); + } + } + + public function after(Response $response) + { + $response->header($this->header); + } +} diff --git a/app/common/middleware/BaseMiddleware.php b/app/common/middleware/BaseMiddleware.php new file mode 100644 index 00000000..063e32ac --- /dev/null +++ b/app/common/middleware/BaseMiddleware.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + + +use app\Request; +use crmeb\interfaces\MiddlewareInterface; +use think\Response; + +abstract class BaseMiddleware implements MiddlewareInterface +{ + + /** + * @var Request + */ + protected $request; + + protected $args = []; + + abstract public function before(Request $request); + + /** + * @param int $num + * @param mixed $default + * @return mixed + * @author xaboy + * @day 2020-04-10 + */ + public function getArg($num, $default = null) + { + return isset($this->args[$num]) ? $this->args[$num] : $default; + } + + final public function handle(Request $request, \Closure $next, ...$args): Response + { + $this->args = $args; + $this->request = $request; + $this->before($request); + $response = $next($request); + $this->after($response); + return $response; + } + + abstract public function after(Response $response); +} diff --git a/app/common/middleware/BlockerMiddleware.php b/app/common/middleware/BlockerMiddleware.php new file mode 100644 index 00000000..f56692b3 --- /dev/null +++ b/app/common/middleware/BlockerMiddleware.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\system\auth\MenuRepository; +use app\common\repositories\system\auth\RoleRepository; +use app\Request; +use Doctrine\Common\Cache\RedisCache; +use http\Exception\InvalidArgumentException; +use think\facade\Cache; +use think\Response; + +class BlockerMiddleware extends BaseMiddleware +{ + protected $key; + + public function before(Request $request) + { + $uid = request()->uid(); + $this->key = md5(request()->rule()->getRule() . $uid); + if (!$this->setMutex($this->key)) { + throw new InvalidArgumentException('请求太过频繁,请稍后再试'); + } + } + + public function setMutex(string $key, int $timeout = 10) + { + $curTime = time(); + $readMutexKey = "redis:mutex:{$key}"; + $mutexRes = Cache::store('redis')->handler()->setnx($readMutexKey, $curTime + $timeout); + if ($mutexRes) { + return true; + } + //就算意外退出,下次进来也会检查key,防止死锁 + $time = Cache::store('redis')->handler()->get($readMutexKey); + if ($curTime > $time) { + Cache::store('redis')->handler()->del($readMutexKey); + return Cache::store('redis')->handler()->setnx($readMutexKey, $curTime + $timeout); + } + return false; + } + + public function after(Response $response) + { + Cache::store('redis')->handler()->del("redis:mutex:{$this->key}"); + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/CheckSiteOpenMiddleware.php b/app/common/middleware/CheckSiteOpenMiddleware.php new file mode 100644 index 00000000..139073fd --- /dev/null +++ b/app/common/middleware/CheckSiteOpenMiddleware.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + + +use app\Request; +use crmeb\interfaces\MiddlewareInterface; +use think\Response; + +class CheckSiteOpenMiddleware implements MiddlewareInterface +{ + + public function handle(Request $request, \Closure $next): Response + { + if (systemConfig('site_open') === '0') { + return app('json')->make(501, '站点已关闭'); + } + return $next($request); + } +} diff --git a/app/common/middleware/InstallMiddleware.php b/app/common/middleware/InstallMiddleware.php new file mode 100644 index 00000000..a279df5f --- /dev/null +++ b/app/common/middleware/InstallMiddleware.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + + +use app\Request; +use think\exception\HttpResponseException; +use think\facade\Route; +use think\Response; + +class InstallMiddleware extends BaseMiddleware +{ + + public function before(Request $request) + { + if(!file_exists(__DIR__.'/../../../install/install.lock')){ + throw new HttpResponseException( Response::create('/install.html', 'redirect')->code(302)); + } + } + + public function after(Response $response) + { + } +} diff --git a/app/common/middleware/LogMiddleware.php b/app/common/middleware/LogMiddleware.php new file mode 100644 index 00000000..f3268e46 --- /dev/null +++ b/app/common/middleware/LogMiddleware.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + + +use app\common\repositories\system\admin\AdminLogRepository; +use app\Request; +use crmeb\services\SwooleTaskService; +use think\Response; + +class LogMiddleware extends BaseMiddleware +{ + + public function before(Request $request) + { + // TODO: Implement before() method. + } + + + public function after(Response $response) + { + if ($this->request->method() == 'GET') return; + SwooleTaskService::log($this->request->merId(), AdminLogRepository::parse($this->request)); + } +} diff --git a/app/common/middleware/MerchantAuthMiddleware.php b/app/common/middleware/MerchantAuthMiddleware.php new file mode 100644 index 00000000..9a76c8d9 --- /dev/null +++ b/app/common/middleware/MerchantAuthMiddleware.php @@ -0,0 +1,95 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + + +use app\common\repositories\system\auth\MenuRepository; +use app\common\repositories\system\auth\RoleRepository; +use app\Request; +use think\exception\ValidateException; +use think\Response; + +class MerchantAuthMiddleware extends BaseMiddleware +{ + + public function before(Request $request) + { + $admin = $request->adminInfo(); + + $merchant = $request->merchant(); + + /** @var RoleRepository $role */ + $role = app()->make(RoleRepository::class); + + /** @var MenuRepository $menu */ + $menu = app()->make(MenuRepository::class); + + if ($admin->level) { + $rules = $role->idsByRules($request->merId(), $admin->roles); + $menus = count($rules) ? ($merchant->type_id ? $menu->typesByRoutes($merchant->type_id, $rules) : $menu->idsByRoutes($rules)) : []; + $msg = '没有权限访问'; + } else { + $rules = []; + $menus = $merchant->type_id ? $menu->merchantTypeByRoutes($merchant->type_id) : []; + $msg = '请前往平台后台-商户 - 店铺管理 - 店铺类型-编辑店铺权限'; + } + + $request->macro('adminAuth', function () use (&$menus) { + return $menus; + }); + + $request->macro('adminRule', function () use (&$rules) { + return $rules; + }); + + $request->macro('checkAuth', function ($name, $vars) use (&$merchant, &$admin, &$menus, &$menu) { + if (!$name || (!$admin->level && !$merchant->type_id)) return true; + $isset = false; + foreach ($menus as $_menu) { + $keys = $menu->tidyParams($_menu['params']); + if ($_menu['route'] != $name) continue; + $isset = true; + if (!count($keys)) return true; + if ($menu->checkParams($keys, $vars)) + return true; + } + if ($isset || $menu->routeExists($name, 1)) + return false; + return true; + }); + + $rule = $request->rule(); + if (!$rule) { + return true; + } + $options = $rule->getOption(); + if (!($options['_auth'] ?? true) && !isset($options['_form'])) { + return true; + } + if (isset($options['_form'])) { + $name = $options['_form']; + $var = $options['_form_val'] ?? []; + } else { + $name = $rule->getName(); + $var = $rule->getVars(); + } + if (!$request->checkAuth($name, $var)) + throw new ValidateException($msg); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/MerchantCheckBaseInfoMiddleware.php b/app/common/middleware/MerchantCheckBaseInfoMiddleware.php new file mode 100644 index 00000000..297113e1 --- /dev/null +++ b/app/common/middleware/MerchantCheckBaseInfoMiddleware.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + + +use app\Request; +use think\exception\ValidateException; +use think\facade\Cache; +use think\Response; + +class MerchantCheckBaseInfoMiddleware extends BaseMiddleware +{ + + protected $rules = [ + 'merchantAttachmentCategoryCreate', + 'merchantUpdate', + 'merchantUploadImage', + 'merchant.Common/uploadCertificate', + 'merchantAttachmentCategoryUpdate', + 'merchantAttachmentCategoryDelete', + 'merchantAttachmentUpdate', + 'merchantAttachmentDelete' + ]; + + public function before(Request $request) + { + $name = $this->request->rule()->getName(); + if ($this->request->method() == 'GET' || in_array($name, $this->rules)) return; + $cache = Cache::store('file'); + $merchant = $request->merchant(); + + $key = 'mer_valid_' . $merchant->mer_id; + if ($cache->has($key)) return; + + + if (!$merchant->mer_avatar || !$merchant->mer_banner || !$merchant->mer_info || !$merchant->mer_address) { + throw new ValidateException('您好,请前往左侧菜单【设置】-【商户基本信息】完善商户基本信息。'); + } + Cache::store('file')->set('mer_valid_' . $merchant->mer_id, 1, 3600 * 8); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/MerchantServerMiddleware.php b/app/common/middleware/MerchantServerMiddleware.php new file mode 100644 index 00000000..468d75d5 --- /dev/null +++ b/app/common/middleware/MerchantServerMiddleware.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\store\service\StoreServiceRepository; +use think\exception\HttpResponseException; +use app\Request; +use think\Response; +use Throwable; + +class MerchantServerMiddleware extends BaseMiddleware +{ + + public function before(Request $request) + { + $this->merId = $this->request->route('merId'); + + $type = $this->getArg(0); + $field = 'customer'; + switch ($type) { + case 0: + $field = 'customer'; + break; + case 1: + $field = 'is_goods'; + break; + } + $userInfo = $this->request->userInfo(); + $service = app()->make(StoreServiceRepository::class)->getService($userInfo->uid, $this->merId); + if (!$service && $userInfo->main_uid) { + $service = app()->make(StoreServiceRepository::class)->getService($userInfo->main_uid, $this->merId); + } + + if (!$service || !$service->$field) { + throw new HttpResponseException(app('json')->fail('您没有权限操作')); + } + $request->macro('serviceInfo', function () use (&$service) { + return $service; + }); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/MerchantTokenMiddleware.php b/app/common/middleware/MerchantTokenMiddleware.php new file mode 100644 index 00000000..ab64b708 --- /dev/null +++ b/app/common/middleware/MerchantTokenMiddleware.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\Request; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use Firebase\JWT\ExpiredException; +use think\exception\ValidateException; +use think\Response; +use Throwable; + +class MerchantTokenMiddleware extends BaseMiddleware +{ + + /** + * @param Request $request + * @throws Throwable + * @author xaboy + * @day 2020-04-10 + */ + public function before(Request $request) + { + $force = $this->getArg(0, true); + try { + $token = trim($request->header('X-Token')); + if(!$token) $token = trim($request->param('token','')); + if (strpos($token, 'Bearer') === 0) + $token = trim(substr($token, 6)); + if (!$token) + throw new ValidateException('请登录'); + + /** + * @var MerchantAdminRepository $repository + */ + $repository = app()->make(MerchantAdminRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + throw new AuthException('token 已过期'); + } + if ('mer' != $payload->jti[1]) + throw new AuthException('无效的 token'); + + $admin = $repository->get($payload->jti[0]); + if (!$admin) + throw new AuthException('账号不存在'); + if (!$admin['status']) + throw new AuthException('账号已被禁用'); + + /** + * @var MerchantRepository $merchantRepository + */ + $merchantRepository = app()->make(MerchantRepository::class); + + $merchant = $merchantRepository->get($admin->mer_id); + + if (!$merchant || !$merchant['status']) + throw new AuthException('商户已被锁定'); + + } catch (Throwable $e) { + if ($force) + throw $e; + $request->macro('isLogin', function () { + return false; + }); + $request->macros(['tokenInfo', 'adminId', 'adminInfo', 'token', 'merchant', 'merchantId'], function () { + throw new AuthException('请登录'); + }); + return; + } + $repository->updateToken($token); + + $request->macro('isLogin', function () { + return true; + }); + $request->macro('tokenInfo', function () use (&$payload) { + return $payload; + }); + $request->macro('token', function () use (&$token) { + return $token; + }); + $request->macro('adminId', function () use (&$admin) { + return $admin->merchant_admin_id; + }); + $request->macro('adminInfo', function () use (&$admin) { + return $admin; + }); + $request->macro('merchantId', function () use (&$admin) { + return $admin->mer_id; + }); + $request->macro('merchant', function () use (&$merchant) { + return $merchant; + }); + $request->macro('userType', function () use (&$merchant) { + return 3; + }); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/RequestLockMiddleware.php b/app/common/middleware/RequestLockMiddleware.php new file mode 100644 index 00000000..9ae68e1f --- /dev/null +++ b/app/common/middleware/RequestLockMiddleware.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\Request; +use crmeb\interfaces\MiddlewareInterface; +use crmeb\services\LockService; +use think\Response; + +class RequestLockMiddleware implements MiddlewareInterface +{ + final public function handle(Request $request, \Closure $next, ...$args): Response + { + $params = $request->route(); + if (!count($params) || in_array(strtolower($request->method()), ['get', 'options']) || $request->rule()->getOption('_lock', true) === false) { + return $next($request); + } + ksort($params); + $key = 're:' . $request->rule()->getName() . ':' . implode('-', $params); + return app()->make(LockService::class)->exec($key, function () use ($next, $request) { + return $next($request); + }, 8); + } +} diff --git a/app/common/middleware/ServiceTokenMiddleware.php b/app/common/middleware/ServiceTokenMiddleware.php new file mode 100644 index 00000000..1259e57f --- /dev/null +++ b/app/common/middleware/ServiceTokenMiddleware.php @@ -0,0 +1,110 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\model\store\service\StoreService; +use app\common\repositories\store\service\StoreServiceRepository; +use app\Request; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use Firebase\JWT\ExpiredException; +use think\exception\ValidateException; +use think\Response; +use Throwable; + +class ServiceTokenMiddleware extends BaseMiddleware +{ + + /** + * @param Request $request + * @throws Throwable + * @author xaboy + * @day 2020-04-10 + */ + public function before(Request $request) + { + $force = $this->getArg(0, true); + try { + $token = trim($request->header('X-Token')); + if (!$token) $token = trim($request->param('token', '')); + if (strpos($token, 'Bearer') === 0) + $token = trim(substr($token, 6)); + if (!$token) + throw new ValidateException('请登录'); + + $repository = app()->make(StoreServiceRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + throw new AuthException('token 已过期'); + } + if ('service' != $payload->jti[1]) + throw new AuthException('无效的 token'); + + $admin = $repository->get($payload->jti[0]); + if (!$admin) + throw new AuthException('账号不存在'); + if (!$admin['is_open']) + throw new AuthException('账号未开启'); + if($admin->mer_id){ + if (!$admin->merchant) + throw new AuthException('商户不存在'); + if (!$admin->merchant['status']) + throw new ValidateException('商户已被锁定'); + } + } catch (Throwable $e) { + if ($force) + throw $e; + $request->macro('isLogin', function () { + return false; + }); + $request->macros(['tokenInfo', 'adminId', 'adminInfo', 'token'], function () { + throw new AuthException('请登录'); + }); + return; + } + $repository->updateToken($token); + + $request->macro('isLogin', function () { + return true; + }); + $request->macro('tokenInfo', function () use (&$payload) { + return $payload; + }); + $request->macro('token', function () use (&$token) { + return $token; + }); + $request->macro('adminId', function () use (&$admin) { + return $admin->service_id; + }); + $request->macro('merchantId', function () use (&$admin) { + return $admin->mer_id; + }); + $request->macro('adminInfo', function () use (&$admin) { + return $admin; + }); + $request->macro('userType', function () use (&$merchant) { + return 4; + }); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/UserTokenMiddleware.php b/app/common/middleware/UserTokenMiddleware.php new file mode 100644 index 00000000..e7655af1 --- /dev/null +++ b/app/common/middleware/UserTokenMiddleware.php @@ -0,0 +1,105 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\user\UserRepository; +use app\Request; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use Firebase\JWT\ExpiredException; +use think\exception\ValidateException; +use think\Response; +use Throwable; + +class UserTokenMiddleware extends BaseMiddleware +{ + + /** + * @param Request $request + * @throws Throwable + * @author xaboy + * @day 2020-04-10 + */ + public function before(Request $request) + { + $force = $this->getArg(0, true); + try { + $token = trim($request->header('X-Token')); + if (strpos($token, 'Bearer') === 0) + $token = trim(substr($token, 6)); + if (!$token) + throw new ValidateException('请登录'); + + /** + * @var UserRepository $repository + */ + $repository = app()->make(UserRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + throw new AuthException('token 已过期'); + } + if ('user' != $payload->jti[1]) + throw new AuthException('无效的 token'); + + $user = $repository->get($payload->jti[0]); + if (!$user) + throw new AuthException('用户不存在'); + if (!$user['status']) + throw new AuthException('用户已被禁用'); + if ($user['cancel_time']) + throw new AuthException('用户不存在'); + + } catch (Throwable $e) { + if ($force) + throw $e; + $request->macro('isLogin', function () { + return false; + }); + $request->macros(['tokenInfo', 'uid', 'userInfo', 'token'], function () { + throw new AuthException('请登录'); + }); + return; + } + $repository->updateToken($token); + + $request->macro('isLogin', function () { + return true; + }); + $request->macro('userType', function () { + return 1; + }); + $request->macro('tokenInfo', function () use (&$payload) { + return $payload; + }); + $request->macro('token', function () use (&$token) { + return $token; + }); + $request->macro('uid', function () use (&$user) { + return $user->uid; + }); + $request->macro('userInfo', function () use (&$user) { + return $user; + }); + } + + public function after(Response $response) + { + // TODO: Implement after() method. + } +} diff --git a/app/common/middleware/VisitProductMiddleware.php b/app/common/middleware/VisitProductMiddleware.php new file mode 100644 index 00000000..6db6bcf7 --- /dev/null +++ b/app/common/middleware/VisitProductMiddleware.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\middleware; + +use app\common\repositories\user\UserHistoryRepository; +use app\common\repositories\user\UserVisitRepository; +use app\Request; +use crmeb\services\SwooleTaskService; +use think\Response; + +class VisitProductMiddleware extends BaseMiddleware +{ + + public function before(Request $request) + { + // TODO: Implement before() method. + } + + + public function after(Response $response) + { + $id = intval($this->request->param('id')); + $type = $this->getArg(0); + if ($this->request->isLogin() && $id) { + $uid = $this->request->uid(); + $make = app()->make(UserHistoryRepository::class); + $data = [ + 'uid' => $uid, + 'res_type' => 1, + 'id' => $id, + 'product_type' => $type + ]; + $spu = $make->createOrUpdate($data); + + if ($spu) { + $make = app()->make(UserVisitRepository::class); + $count = $make->search(['uid' => $uid, 'type' => 'product'])->where('type_id', $spu['product_id'])->whereTime('create_time', '>', date('Y-m-d H:i:s', strtotime('- 300 seconds')))->count(); + if (!$count) { + SwooleTaskService::visit(intval($uid), $spu['product_id'], 'product'); + } + } + } + } +} diff --git a/app/common/model/BaseModel.php b/app/common/model/BaseModel.php new file mode 100644 index 00000000..c0ae08e9 --- /dev/null +++ b/app/common/model/BaseModel.php @@ -0,0 +1,74 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model; + + +use think\db\BaseQuery; +use think\Model; + +/** + * Class BaseModel + * @package app\common\model + * @author xaboy + * @day 2020-03-30 + */ +abstract class BaseModel extends Model +{ + protected $updateTime = false; + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + abstract public static function tablePk():? string; + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + abstract public static function tableName(): string; + + /** + * BaseModel constructor. + * @param array $data + */ + public function __construct(array $data = []) + { + $this->pk = static::tablePk(); + $this->name = static::tableName(); + parent::__construct($data); + } + + /** + * @return static + */ + public static function getInstance(): self + { + return new static(); + } + + /** + * @param array $scope + * @return BaseQuery + * @author xaboy + * @day 2020-03-30 + */ + public static function getDB(array $scope = []) + { + return self::getInstance()->db($scope); + } + +} diff --git a/app/common/model/article/Article.php b/app/common/model/article/Article.php new file mode 100644 index 00000000..55a42917 --- /dev/null +++ b/app/common/model/article/Article.php @@ -0,0 +1,65 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\article; + + +use app\common\model\BaseModel; + +class Article extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'article_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'article'; + } + + /** + * @return \think\model\relation\HasOne + * @author Qinii + */ + public function content() + { + return $this->hasOne(ArticleContent::class,'article_content_id','article_id'); + } + + /** + * @return \think\model\relation\HasOne + * @author Qinii + */ + public function articleCategory() + { + return $this->hasOne(ArticleCategory::class ,'article_category_id','cid') + ->field('article_category_id,title'); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } +} diff --git a/app/common/model/article/ArticleCategory.php b/app/common/model/article/ArticleCategory.php new file mode 100644 index 00000000..d9a3d7a1 --- /dev/null +++ b/app/common/model/article/ArticleCategory.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\article; + + +use app\common\model\BaseModel; + +class ArticleCategory extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'article_category_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'article_category'; + } +} diff --git a/app/common/model/article/ArticleContent.php b/app/common/model/article/ArticleContent.php new file mode 100644 index 00000000..0c0a4f64 --- /dev/null +++ b/app/common/model/article/ArticleContent.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\article; + + +use app\common\model\BaseModel; + +class ArticleContent extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'article_content_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'article_content'; + } +} diff --git a/app/common/model/community/Community.php b/app/common/model/community/Community.php new file mode 100644 index 00000000..26a3c46a --- /dev/null +++ b/app/common/model/community/Community.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\community; + +use app\common\model\BaseModel; +use app\common\model\store\product\Spu; +use app\common\model\system\Relevance; +use app\common\model\user\User; +use app\common\repositories\system\RelevanceRepository; + +class Community extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tablePk(): string + { + return 'community_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tableName(): string + { + return 'community'; + } + + public function getImageAttr($value) + { + return explode(',',$value); + } + + public function author() + { + return $this->hasOne(User::class,'uid','uid'); + } + + public function topic() + { + return $this->hasOne(CommunityTopic::class,'topic_id','topic_id'); + } + + public function reply() + { + return $this->hasMany(CommunityReply::class,'community_id','community_id'); + } + + public function relevance() + { + return $this->hasMany(Relevance::class, 'left_id','community_id') + ->where('type',RelevanceRepository::TYPE_COMMUNITY_PRODUCT); + } + + /* + * 右侧为内容ID的 + */ + public function relevanceRight() + { + return $this->hasMany(Relevance::class, 'right_id','community_id'); + } + + public function isStart() + { + return $this->hasOne(Relevance::class, 'right_id','community_id')->where('type', RelevanceRepository::TYPE_COMMUNITY_START)->bind(['relevance_id']); + } + + public function isFans() + { + return $this->hasOne(Relevance::class, 'right_id','uid')->where('type', RelevanceRepository::TYPE_COMMUNITY_FANS)->bind(['is_fans' => 'right_id']); + } + + public function category() + { + return $this->hasOne(CommunityCategory::class, 'category_id','category_id'); + } + + public function getTimeAttr() + { + return date('m月d日',strtotime($this->create_time)); + } + + public function getCountReplyAttr() + { + return CommunityReply::where('community_id',$this->community_id)->where('status',1)->count(); + } + + public function searchTopicIdAttr($query, $value) + { + $query->where('topic_id', $value); + } + + public function searchTitleAttr($query, $value) + { + $query->whereLike('title', "%{$value}%"); + } + + public function searchKeywordAttr($query, $value) + { + $query->whereLike('title|content', "%{$value}%"); + } + + public function searchCategoryIdAttr($query, $value) + { + $query->where('category_id', $value); + } + + public function searchIsShowAttr($query, $value) + { + $query->where('is_show', $value); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + + public function searchUidAttr($query, $value) + { + $query->where('uid', $value); + } + + public function searchIsHotAttr($query, $value) + { + $query->where('is_hot', $value); + } + + public function searchUidsAttr($query, $value) + { + $query->whereIn('uid', $value); + } + + public function searchSpuIdAttr($query, $value) + { + $id = Relevance::where('right_id',$value) + ->where('type',RelevanceRepository::TYPE_COMMUNITY_PRODUCT) + ->column('left_id'); + $query->where('community_id','in', $id); + } + + public function searchIsTypeAttr($query, $value) + { + $query->whereIn('is_type', $value); + } + + public function searchCommunityIdAttr($query, $value) + { + $query->where('community_id', $value); + } + + public function searchNotIdAttr($query, $value) + { + $query->where('community_id', '<>',$value); + } + +} diff --git a/app/common/model/community/CommunityCategory.php b/app/common/model/community/CommunityCategory.php new file mode 100644 index 00000000..b5aaf978 --- /dev/null +++ b/app/common/model/community/CommunityCategory.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\community; + +use app\common\model\BaseModel; + +class CommunityCategory extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tablePk(): string + { + return 'category_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tableName(): string + { + return 'community_category'; + } + + public function children() + { + return $this->hasMany(CommunityTopic::class,'category_id','category_id') + ->where('status',1) + ->where('is_del',0) + ->field('category_id,topic_id,topic_name,pic,sort,count_use') + ->order('sort DESC,create_time DESC'); + } + + + public function searchCateNameAttr($query, $value) + { + $query->whereLike('cate_name', "%{$value}%"); + } + + public function searchCategoryIdAttr($query, $value) + { + $query->where('category_id', $value); + } + + public function searchIsShowAttr($query, $value) + { + $query->where('is_show', $value); + } + +} diff --git a/app/common/model/community/CommunityReply.php b/app/common/model/community/CommunityReply.php new file mode 100644 index 00000000..00daedf7 --- /dev/null +++ b/app/common/model/community/CommunityReply.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\community; + +use app\common\model\BaseModel; +use app\common\model\system\Relevance; +use app\common\model\user\User; +use app\common\repositories\system\RelevanceRepository; + +class CommunityReply extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tablePk(): string + { + return 'reply_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tableName(): string + { + return 'community_reply'; + } + + public function children() + { + return $this->hasMany(self::class, 'pid', 'reply_id')->where('status', 1); + } + + public function hasReply() + { + return $this->hasOne(self::class, 'pid', 'reply_id'); + } + + public function author() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function reply() + { + return $this->hasOne(User::class, 'uid', 're_uid'); + } + + public function community() + { + return $this->hasOne(Community::class, 'community_id', 'community_id'); + } + + public function isStart() + { + return $this->hasOne(Relevance::class, 'right_id', 'reply_id')->where('type', RelevanceRepository::TYPE_COMMUNITY_REPLY_START)->bind(['relevance_id']); + } + + /** + * 评论被删删除处理 + * + * @param [string] $value + * @return void + */ + public function getContentAttr($value) + { + if ($this->is_del) $value = '[该评论已被删除]'; + return $value; + } + + + public function searchUidAttr($query, $value) + { + $query->where('uid', $value); + } + + public function searchCommunityIdAttr($query, $value) + { + $query->where('community_id', $value); + } + + public function searchIsDelAttr($query, $value) + { + $query->where('is_del', $value); + } + + public function searchPidAttr($query, $value) + { + $query->where('pid', $value); + } +} diff --git a/app/common/model/community/CommunityTopic.php b/app/common/model/community/CommunityTopic.php new file mode 100644 index 00000000..a6205418 --- /dev/null +++ b/app/common/model/community/CommunityTopic.php @@ -0,0 +1,75 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\community; + +use app\common\model\BaseModel; + +class CommunityTopic extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tablePk(): string + { + return 'topic_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tableName(): string + { + return 'community_topic'; + } + + public function category() + { + return $this->hasOne(CommunityCategory::class,'category_id','category_id'); + } + + + public function searchTopicNameAttr($query, $value) + { + $query->whereLike('topic_name', "%{$value}%"); + } + + public function searchTopicIdAttr($query, $value) + { + $query->where('topic_id', $value); + } + + public function searchCategoryIdAttr($query, $value) + { + $query->where('category_id', $value); + } + + public function searchIsHotAttr($query, $value) + { + $query->where('is_hot', $value); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + + +} diff --git a/app/common/model/delivery/DeliveryOrder.php b/app/common/model/delivery/DeliveryOrder.php new file mode 100644 index 00000000..0aaaa5fb --- /dev/null +++ b/app/common/model/delivery/DeliveryOrder.php @@ -0,0 +1,106 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\delivery; + +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreOrderStatus; +use app\common\model\system\merchant\Merchant; +use crmeb\services\DeliverySevices; + +class DeliveryOrder extends BaseModel +{ + + public static function tablePk(): string + { + return 'delivery_order_id'; + } + + public static function tableName(): string + { + return 'delivery_order'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id','mer_id'); + } + + public function station() + { + return $this->hasOne(DeliveryStation::class, 'station_id','station_id'); + } + + public function storeOrder() + { + return $this->hasOne(StoreOrder::class, 'order_id','order_id'); + } + + public function storeOrderStatus() + { + return $this->hasMany(StoreOrderStatus::class, 'order_id','order_id')->order('change_time DESC'); + } + + public function getDistanceAttr($value) + { + if ($value >= 1000) { + return round(($value / 1000),2) . ' km'; + } else { + return $value . 'm'; + } + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchKeywordAttr($query,$value) + { + $query->whereLike('order_sn|from_address',"%{$value}%"); + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchStationIdAttr($query,$value) + { + $query->where('station_id',$value); + } + + public function searchStationTypeAttr($query,$value) + { + $query->where('station_type',$value); + } + + public function searchOrderIdAttr($query,$value) + { + $query->where('order_id',$value); + } + public function searchSnAttr($query,$value) + { + $query->where('order_sn',$value); + } + public function searchDateAttr($query,$value) + { + getModelTime($query, $value); + } + public function searchOrderSnAttr($query,$value) + { + $ids = StoreOrder::whereLike('order_sn',"%{$value}%")->column('order_id'); + $query->whereIn('order_id', $ids); + } +} diff --git a/app/common/model/delivery/DeliveryStation.php b/app/common/model/delivery/DeliveryStation.php new file mode 100644 index 00000000..b2982ef3 --- /dev/null +++ b/app/common/model/delivery/DeliveryStation.php @@ -0,0 +1,87 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\delivery; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use crmeb\services\DeliverySevices; + +class DeliveryStation extends BaseModel +{ + + public static function tablePk(): string + { + return 'station_id'; + } + + public static function tableName(): string + { + return 'delivery_station'; + } + + public function getBusinessAttr($value, $data) + { + $res = DeliverySevices::create($data['type'])->getBusiness(); + foreach ($res as $v) { + if ($value == $v['key']) { + return $v; + } + } + return $value; + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id','mer_id'); + } + + public function searchStationNameAttr($query,$value) + { + $query->whereLike('station_name',"%{$value}%"); + } + + public function searchKeywordAttr($query,$value) + { + $query->whereLike('station_name|contact_name|phone',"%{$value}%"); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchStationIdAttr($query,$value) + { + $query->where('station_id',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } + + public function searchTypeAttr($query,$value) + { + $query->where('type',$value); + } + public function searchDateAttr($query,$value) + { + getModelTime($query, $value, 'create_time'); + } +} diff --git a/app/common/model/store/CityArea.php b/app/common/model/store/CityArea.php new file mode 100644 index 00000000..08d9b0b6 --- /dev/null +++ b/app/common/model/store/CityArea.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + + +use app\common\model\BaseModel; + +class CityArea extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'id'; + } + + public static function tableName(): string + { + return 'city_area'; + } + + public function parent() + { + return $this->hasOne(self::class,'id','parent_id'); + } + + public function getChildrenAttr() + { + return []; + } + + public function getHasChildrenAttr() + { + $count = self::where('parent_id',$this->id)->count(); + return $count ? true : false; + } +} diff --git a/app/common/model/store/Excel.php b/app/common/model/store/Excel.php new file mode 100644 index 00000000..b466be66 --- /dev/null +++ b/app/common/model/store/Excel.php @@ -0,0 +1,76 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\MerchantAdmin; + +class Excel extends BaseModel +{ + public $typeData = [ + 'order' => '订单列表', + 'delivery' => '待发货订单', + 'searchLog' => '搜索记录', + 'financial' => '流水记录', + 'refundOrder' => '退款单', + 'integralLog' => '积分日志', + 'importDelivery' => '发货导入', + 'exportFinancial' => '日/月账单', + 'financialLog' => '转账记录', + 'bill' => '资金记录', + 'profitsharing' => '分账管理', + 'extract' => '提现管理', + ]; + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + public static function tablePk(): string + { + return 'excel_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + public static function tableName(): string + { + return 'excel'; + } + + public function merAdmin() + { + return $this->hasOne(MerchantAdmin::class,'merchant_admin_id','admin_id'); + } + + public function getPathAttr($value) + { + return $value ? systemConfig('site_url').$value : ''; + } + + public function getTypeAttr($value) + { + if ($value) { + return $this->typeData[$value]; + } + return ''; + } + +} diff --git a/app/common/model/store/GeoArea.php b/app/common/model/store/GeoArea.php new file mode 100644 index 00000000..8c8a77a4 --- /dev/null +++ b/app/common/model/store/GeoArea.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + + +use app\common\model\BaseModel; + +class GeoArea extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'id'; + } + + public static function tableName(): string + { + return 'geo_area'; + } + +} diff --git a/app/common/model/store/Guarantee.php b/app/common/model/store/Guarantee.php new file mode 100644 index 00000000..1ab710f8 --- /dev/null +++ b/app/common/model/store/Guarantee.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store; + +use app\common\model\BaseModel; + + +class Guarantee extends BaseModel +{ + + public static function tablePk(): string + { + return 'guarantee_id'; + } + + public static function tableName(): string + { + return 'guarantee'; + } + + public function searchGuaranteeIdAttr($query,$value) + { + $query->where('guarantee_id',$value); + } + + public function searchGuaranteeNameAttr($query,$value) + { + $query->where('guarantee_name',$value); + } + + public function searchGuaranteeInfoAttr($query,$value) + { + $query->where('guarantee_Info',$value); + } + + public function searchKeywordAttr($query,$value) + { + $query->whereLike('guarantee_name',"%{$value}%"); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } +} diff --git a/app/common/model/store/GuaranteeTemplate.php b/app/common/model/store/GuaranteeTemplate.php new file mode 100644 index 00000000..2016630f --- /dev/null +++ b/app/common/model/store/GuaranteeTemplate.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store; + +use app\common\model\BaseModel; + + +class GuaranteeTemplate extends BaseModel +{ + + public static function tablePk(): string + { + return 'guarantee_template_id'; + } + + public static function tableName(): string + { + return 'guarantee_template'; + } + + + public function templateValue() + { + return $this->hasMany(GuaranteeValue::class,'guarantee_template_id','guarantee_template_id'); + } + + public function getTemplateValueAttr() + { + return GuaranteeValue::haswhere('value',function($query){ + $query->where('status',1)->where('is_del',0); + }) + ->where('guarantee_template_id',$this->guarantee_template_id) + ->column('GuaranteeValue.guarantee_id'); + } + + public function searchGuaranteeTemplateIdAttr($query,$value) + { + $query->where('guarantee_template_id',$value); + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchKeywordAttr($query,$value) + { + $query->whereLike('template_name',"%{$value}%"); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } +} diff --git a/app/common/model/store/GuaranteeValue.php b/app/common/model/store/GuaranteeValue.php new file mode 100644 index 00000000..555f9a07 --- /dev/null +++ b/app/common/model/store/GuaranteeValue.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store; + +use app\common\model\BaseModel; + + +class GuaranteeValue extends BaseModel +{ + + public static function tablePk(): string + { + return 'guarantee_value_id'; + } + + public static function tableName(): string + { + return 'guarantee_value'; + } + + + public function value() + { + return $this->hasOne(Guarantee::class,'guarantee_id','guarantee_id')->where('is_del',0)->where('status',1); + } + + public function searchGuaranteeIdAttr($query,$value) + { + $query->where('guarantee_id',$value); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } +} diff --git a/app/common/model/store/PriceRule.php b/app/common/model/store/PriceRule.php new file mode 100644 index 00000000..ea822550 --- /dev/null +++ b/app/common/model/store/PriceRule.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store; + +use app\common\model\BaseModel; +use app\common\model\system\Relevance; +use app\common\repositories\system\RelevanceRepository; + +class PriceRule extends BaseModel +{ + + public static function tablePk(): string + { + return 'rule_id'; + } + + + public static function tableName(): string + { + return 'price_rule'; + } + + public function cate() + { + return $this->hasMany(Relevance::class, 'left_id', 'rule_id')->where([ + 'type' => RelevanceRepository::PRICE_RULE_CATEGORY + ])->with(['category']); + } +} diff --git a/app/common/model/store/StoreActivity.php b/app/common/model/store/StoreActivity.php new file mode 100644 index 00000000..a6c5683d --- /dev/null +++ b/app/common/model/store/StoreActivity.php @@ -0,0 +1,109 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store; + +use app\common\model\BaseModel; +use app\common\model\store\product\Spu; +use app\common\model\system\Relevance; +use app\common\repositories\system\RelevanceRepository; + +class StoreActivity extends BaseModel +{ + + public static function tablePk(): string + { + return 'activity_id'; + } + + public static function tableName(): string + { + return 'store_activity'; + } + + public function getFullAttr($val) + { + return $val ? (float)$val : $val; + } + + public function spu() + { + return $this->hasMany(Spu::class, 'activity_id', 'activity_id'); + } + + public function socpeData() + { + return $this->hasMany(Relevance::class,'left_id','activity_id')->whereIn('type',[RelevanceRepository::SCOPE_TYPE_STORE,RelevanceRepository::SCOPE_TYPE_CATEGORY,RelevanceRepository::SCOPE_TYPE_PRODUCT]); + } + + public function searchIsShowAttr($query, $value) + { + if ($value !== '') { + $query->where('is_show', $value); + } + } + + public function searchStatusAttr($query, $value) + { + if ($value !== '') { + $query->where('status',$value); + } + } + + public function searchActivityTypeAttr($query, $value) + { + if ($value !== '') { + $query->where('activity_type', $value); + } + } + + public function searchIsStatusAttr($query, $value) + { + $query->whereIn('status',[0,1]); + } + + public function searchActivityIdAttr($query, $value) + { + if ($value !== '') { + $query->where('activity_id', $value); + } + } + + public function searchDateAttr($query, $value) + { + if ($value !== '') { + getModelTime($query, $value, 'create_time'); + } + } + + public function searchKeywordAttr($query, $value) + { + if ($value !== '') { + $query->whereLike('activity_id|activity_name', '%' . $value . '%'); + } + } + + public function searchIsDelAttr($query, $value) + { + if ($value !== '') { + $query->where('is_del', $value); + } + } + + public function searchGtEndTimeAttr($query, $value) + { + if ($value !== '') { + $query->whereTime('end_time','>', $value); + } + } + +} diff --git a/app/common/model/store/StoreAttrTemplate.php b/app/common/model/store/StoreAttrTemplate.php new file mode 100644 index 00000000..835b48df --- /dev/null +++ b/app/common/model/store/StoreAttrTemplate.php @@ -0,0 +1,69 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + + +use app\common\model\BaseModel; + +/** + * Class StoreAttrTemplate + * @package app\common\model\store + * @author xaboy + * @day 2020-05-06 + */ +class StoreAttrTemplate extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'attr_template_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_attr_template'; + } + + /** + * @param $val + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function getTemplateValueAttr($val) + { + return json_decode($val, true); + } + + /** + * @param $val + * @return false|string + * @author xaboy + * @day 2020-05-06 + */ + public function setTemplateValueAttr($val) + { + return json_encode($val); + } +} diff --git a/app/common/model/store/StoreBrand.php b/app/common/model/store/StoreBrand.php new file mode 100644 index 00000000..f4741c49 --- /dev/null +++ b/app/common/model/store/StoreBrand.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + +use app\common\model\BaseModel; + +class StoreBrand extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'brand_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_brand'; + } + + public function brandCategory() + { + return $this->belongsTo(StoreBrandCategory::class,'brand_category_id','store_brand_category_id'); + } + +} diff --git a/app/common/model/store/StoreBrandCategory.php b/app/common/model/store/StoreBrandCategory.php new file mode 100644 index 00000000..a8e63b3b --- /dev/null +++ b/app/common/model/store/StoreBrandCategory.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + +use app\common\model\BaseModel; + +class StoreBrandCategory extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'store_brand_category_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_brand_category'; + } + + public function getAncestorsAttr($value) + { + $value = self::whereIn('store_brand_category_id',$this->path_ids)->order('level ASC')->column('cate_name'); + return implode('/',$value).'/'.$this->cate_name; + } + + public function getPathIdsAttr() + { + return explode('/',$this->path); + } + +} diff --git a/app/common/model/store/StoreCategory.php b/app/common/model/store/StoreCategory.php new file mode 100644 index 00000000..1b565c50 --- /dev/null +++ b/app/common/model/store/StoreCategory.php @@ -0,0 +1,98 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + +use app\common\model\BaseModel; +use think\Model; + +class StoreCategory extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'store_category_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_category'; + } + + /** + * 获取父级名称 + * @Author:Qinii + * @Date: 2020/5/22 + * @param $value + * @return string + */ + public function getAncestorsAttr($value) + { + $value = self::whereIn('store_category_id',$this->path_ids)->order('level ASC')->column('cate_name'); + return implode('/',$value).'/'.$this->cate_name; + } + + /** + * 获取path的id + * @Author:Qinii + * @Date: 2020/5/22 + * @return array + */ + public function getPathIdsAttr() + { + return explode('/',$this->path); + } + + /** + * 获取子集id + * @Author:Qinii + * @Date: 2020/5/22 + * @param $value + * @return array + */ + public function getChildIdsAttr($value) + { + return self::where('path','like','%/'.$this->store_category_id.'/%')->column('store_category_id'); + } + + public function searchIdAttr($query,$value) + { + $query->where('store_category_id',$value); + } + + public function searchIdsAttr($query,$value) + { + $query->whereIn('store_category_id',$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('is_show',$value); + } + + public function searchMerIdsAttr($query,$value) + { + $query->whereIn('mer_id',$value); + } + +} diff --git a/app/common/model/store/StorePrinter.php b/app/common/model/store/StorePrinter.php new file mode 100644 index 00000000..a3c29a10 --- /dev/null +++ b/app/common/model/store/StorePrinter.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store; + + +use app\common\model\BaseModel; + +class StorePrinter extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'printer_id'; + } + + public static function tableName(): string + { + return 'store_printer'; + } + + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchKeywordAttr($query,$value) + { + $query->whereLike('printer_name|printer_terminal',"%{$value}%"); + } + + +} diff --git a/app/common/model/store/StoreSeckillActive.php b/app/common/model/store/StoreSeckillActive.php new file mode 100644 index 00000000..0d574985 --- /dev/null +++ b/app/common/model/store/StoreSeckillActive.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store; + +use app\common\model\BaseModel; + +class StoreSeckillActive extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + public static function tablePk(): string + { + return 'seckill_active_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + public static function tableName(): string + { + return 'store_seckill_active'; + } + + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } +} diff --git a/app/common/model/store/StoreSeckillTime.php b/app/common/model/store/StoreSeckillTime.php new file mode 100644 index 00000000..ae91c868 --- /dev/null +++ b/app/common/model/store/StoreSeckillTime.php @@ -0,0 +1,69 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store; + +use app\common\model\BaseModel; + +class StoreSeckillTime extends BaseModel +{ + + const ISTIME = [ + 0 => '00:00', + 1 => '01:00', + 2 => '02:00', + 3 => '03:00', + 4 => '04:00', + 5 => '05:00', + 6 => '06:00', + 7 => '07:00', + 8 => '08:00', + 9 => '09:00', + 10 => '10:00', + 11 => '11:00', + 12 => '12:00', + 13 => '13:00', + 14 => '14:00', + 15 => '15:00', + 16 => '16:00', + 17 => '17:00', + 18 => '18:00', + 19 => '19:00', + 20 => '20:00', + 21 => '21:00', + 22 => '22:00', + 23 => '23:00', + 24 => '24:00', + ]; + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + public static function tablePk(): string + { + return 'seckill_time_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-07-30 + */ + public static function tableName(): string + { + return 'store_seckill_time'; + } +} diff --git a/app/common/model/store/broadcast/BroadcastAssistant.php b/app/common/model/store/broadcast/BroadcastAssistant.php new file mode 100644 index 00000000..a696509e --- /dev/null +++ b/app/common/model/store/broadcast/BroadcastAssistant.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\broadcast; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class BroadcastAssistant extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'assistant_id'; + } + + public static function tableName(): string + { + return 'broadcast_assistant'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchUsernameAttr($query,$value) + { + $query->whereLike('username',"%{$value}%"); + } + + public function searchNicknameAttr($query,$value) + { + $query->whereLike('nickname',"%{$value}%"); + } + + public function searchAssistantIdsAttr($query,$value) + { + $query->whereIn('assistant_id', $value); + } + + public function searchAssistantIdAttr($query,$value) + { + $query->where('assistant_id',$value); + } +} diff --git a/app/common/model/store/broadcast/BroadcastGoods.php b/app/common/model/store/broadcast/BroadcastGoods.php new file mode 100644 index 00000000..2a0aeb6c --- /dev/null +++ b/app/common/model/store/broadcast/BroadcastGoods.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\broadcast; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; +use app\common\model\system\merchant\Merchant; + +/** + * Class BroadcastGoods + * @package app\common\model\store\broadcast + * @author xaboy + * @day 2020/7/29 + */ +class BroadcastGoods extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/7/29 + */ + public static function tablePk(): ?string + { + return 'broadcast_goods_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020/7/29 + */ + public static function tableName(): string + { + return 'broadcast_goods'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'product_id'); + } +} diff --git a/app/common/model/store/broadcast/BroadcastRoom.php b/app/common/model/store/broadcast/BroadcastRoom.php new file mode 100644 index 00000000..51656970 --- /dev/null +++ b/app/common/model/store/broadcast/BroadcastRoom.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\broadcast; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +/** + * Class BroadcastRoom + * @package app\common\model\store\broadcast + * @author xaboy + * @day 2020/7/29 + */ +class BroadcastRoom extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/7/29 + */ + public static function tablePk(): ?string + { + return 'broadcast_room_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020/7/29 + */ + public static function tableName(): string + { + return 'broadcast_room'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function broadcast() + { + return $this->hasMany(BroadcastRoomGoods::class)->where('on_sale', 1); + } +} diff --git a/app/common/model/store/broadcast/BroadcastRoomGoods.php b/app/common/model/store/broadcast/BroadcastRoomGoods.php new file mode 100644 index 00000000..64162c26 --- /dev/null +++ b/app/common/model/store/broadcast/BroadcastRoomGoods.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\broadcast; + + +use app\common\model\BaseModel; + +class BroadcastRoomGoods extends BaseModel +{ + + public static function tablePk(): ?string + { + return null; + } + + public static function tableName(): string + { + return 'broadcast_room_goods'; + } + + public function goods() + { + return $this->hasOne(BroadcastGoods::class, 'broadcast_goods_id', 'broadcast_goods_id'); + } + + public function room() + { + return $this->hasOne(BroadcastRoom::class, 'broadcast_room_id', 'broadcast_room_id'); + } +} diff --git a/app/common/model/store/coupon/StoreCoupon.php b/app/common/model/store/coupon/StoreCoupon.php new file mode 100644 index 00000000..e675ecc0 --- /dev/null +++ b/app/common/model/store/coupon/StoreCoupon.php @@ -0,0 +1,105 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\coupon; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\product\SpuRepository; + +class StoreCoupon extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'coupon_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_coupon'; + } + + public function product() + { + return $this->hasMany(StoreCouponProduct::class, 'coupon_id', 'coupon_id'); + } + + public function issue() + { + return $this->hasOne(StoreCouponIssueUser::class, 'coupon_id', 'coupon_id'); + } + public function svipIssue() + { + return $this->hasOne(StoreCouponIssueUser::class, 'coupon_id', 'coupon_id')->whereMonth('create_time'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function getUsedNumAttr() + { + return app()->make(StoreCouponUserRepository::class)->usedNum($this->coupon_id); + } + + public function getSendNumAttr() + { + return app()->make(StoreCouponUserRepository::class)->sendNum($this->coupon_id); + } + + public function getProductLstAttr() + { + $where['spu_status'] = 1; + $where['mer_status'] = 1; + //优惠券类型 0-店铺 1-商品券 10 平台通用券 11平台品类券 12平台跨店券 + switch ($this['type']) { + case 0: + $where['mer_id'] = $this->mer_id; + break; + case 1: + $where['product_ids'] = StoreCouponProduct::where('coupon_id', $this->coupon_id)->limit(5)->column('product_id'); + break; + case 10: + break; + case 11: + $ids = StoreCouponProduct::where('coupon_id', $this->coupon_id)->limit(5)->column('product_id'); + $where['cate_pid'] = $ids; + break; + case 12: + $ids = StoreCouponProduct::where('coupon_id', $this->coupon_id)->limit(5)->column('product_id'); + $where['mer_ids'] = $ids; + break; + } + + $where['order'] = 'none'; + $where['common'] = 1; + $product = app()->make(SpuRepository::class)->search($where)->field( + 'S.spu_id,S.product_id,S.store_name,S.image,activity_id,S.keyword,S.price,S.mer_id,spu_id,S.status,store_info,brand_id,cate_id,unit_name,S.star,S.rank,S.sort,sales,S.product_type,P.ot_price' + )->limit(3)->orderRand()->select()->toArray(); + return $product; + } +} diff --git a/app/common/model/store/coupon/StoreCouponIssueUser.php b/app/common/model/store/coupon/StoreCouponIssueUser.php new file mode 100644 index 00000000..a8776d35 --- /dev/null +++ b/app/common/model/store/coupon/StoreCouponIssueUser.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\coupon; + + +use app\common\model\BaseModel; +use app\common\model\user\User; + +class StoreCouponIssueUser extends BaseModel +{ + + public static function tablePk(): ?string + { + return null; + } + + public static function tableName(): string + { + return 'store_coupon_issue_user'; + } + + public function coupon() + { + return $this->hasOne(StoreCoupon::class, 'coupon_id', 'coupon_id'); + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } +} diff --git a/app/common/model/store/coupon/StoreCouponProduct.php b/app/common/model/store/coupon/StoreCouponProduct.php new file mode 100644 index 00000000..f7015060 --- /dev/null +++ b/app/common/model/store/coupon/StoreCouponProduct.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\coupon; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; + +class StoreCouponProduct extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk():? string + { + return null; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_coupon_product'; + } + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'product_id'); + } +} diff --git a/app/common/model/store/coupon/StoreCouponSend.php b/app/common/model/store/coupon/StoreCouponSend.php new file mode 100644 index 00000000..ac4c5334 --- /dev/null +++ b/app/common/model/store/coupon/StoreCouponSend.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\coupon; + + +use app\common\model\BaseModel; +use app\common\repositories\store\coupon\StoreCouponUserRepository; + +class StoreCouponSend extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'coupon_send_id'; + } + + public static function tableName(): string + { + return 'store_coupon_send'; + } + + public function setMarkAttr(array $val) + { + return json_encode($val); + } + + public function getMarkAttr($val) + { + return json_decode($val, true) ?: []; + } + + public function getUseCountAttr() + { + return app()->make(StoreCouponUserRepository::class)->sendNum($this->coupon_id, $this->coupon_send_id, 1); + } + + public function getUsedNumAttr() + { + return app()->make(StoreCouponUserRepository::class)->usedNum($this->coupon_id); + } + + public function getSendNumAttr() + { + return app()->make(StoreCouponUserRepository::class)->sendNum($this->coupon_id); + } + + public function coupon() + { + return $this->hasOne(StoreCoupon::class, 'coupon_id', 'coupon_id'); + } +} diff --git a/app/common/model/store/coupon/StoreCouponUser.php b/app/common/model/store/coupon/StoreCouponUser.php new file mode 100644 index 00000000..7ffdae1d --- /dev/null +++ b/app/common/model/store/coupon/StoreCouponUser.php @@ -0,0 +1,69 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\coupon; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; + +/** + * Class StoreCouponUser + * @package app\common\model\store\coupon + * @author xaboy + * @day 2020-05-14 + */ +class StoreCouponUser extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'coupon_user_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'store_coupon_user'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function coupon() + { + return $this->hasOne(StoreCoupon::class, 'coupon_id', 'coupon_id'); + } + + public function product() + { + return $this->hasMany(StoreCouponProduct::class, 'coupon_id', 'coupon_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } +} diff --git a/app/common/model/store/order/MerchantReconciliation.php b/app/common/model/store/order/MerchantReconciliation.php new file mode 100644 index 00000000..ef71787b --- /dev/null +++ b/app/common/model/store/order/MerchantReconciliation.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\order; + +use app\common\model\BaseModel; +use app\common\model\system\admin\Admin; +use app\common\model\system\merchant\Merchant; + +class MerchantReconciliation extends BaseModel +{ + public static function tablePk(): ?string + { + return 'reconciliation_id'; + } + + public static function tableName(): string + { + return 'merchant_reconciliation'; + } + + public function withOrder() + { + return $this->hasMany(MerchantReconciliationOrder::class,'reconciliation_id','reconciliation_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function admin() + { + return $this->hasOne(Admin::class,'admin_id','admin_id'); + } + + /** + * 计算扣除费用 + * @Author:Qinii + * @Date: 2020/10/15 + * @return string + */ + public function getChargeAttr() + { + return bcadd(bcadd(bcadd($this->order_extension,$this->order_rate,2),$this->refund_price,2),$this->refund_extensionthis,2); + } +} diff --git a/app/common/model/store/order/MerchantReconciliationOrder.php b/app/common/model/store/order/MerchantReconciliationOrder.php new file mode 100644 index 00000000..a12f91b7 --- /dev/null +++ b/app/common/model/store/order/MerchantReconciliationOrder.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\order; + +use app\common\model\BaseModel; + +class MerchantReconciliationOrder extends BaseModel +{ + public static function tablePk(): ?string + { + return ''; + } + + public static function tableName(): string + { + return 'merchant_reconciliation_order'; + } + + public function Order() + { + return $this->hasOne(StoreOrder::class,'order_id','order_id'); + } + + public function refund() + { + return $this->hasOne(StoreRefundOrder::class,'refund_order_id','order_id'); + } +} diff --git a/app/common/model/store/order/PresellOrder.php b/app/common/model/store/order/PresellOrder.php new file mode 100644 index 00000000..1ea8bf8f --- /dev/null +++ b/app/common/model/store/order/PresellOrder.php @@ -0,0 +1,98 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; +use app\common\repositories\store\order\PresellOrderRepository; + +class PresellOrder extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'presell_order_id'; + } + + public static function tableName(): string + { + return 'presell_order'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function order() + { + return $this->hasOne(StoreOrder::class, 'order_id', 'order_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + + public function searchOrderIdAttr($query, $value) + { + $query->where('order_id', $value); + } + + public function getActiveStatusAttr() + { + $status = 1; + $now = time(); + if (strtotime($this->final_start_time) > $now) $status = 0; + else if (strtotime($this->final_end_time) < $now) { + if ($this->status && $this->presell_order_id) + app()->make(PresellOrderRepository::class)->cancel($this->presell_order_id); + $status = 2; + } + return $status; + } + + public function getCombinePayParams() + { + return [ + 'order_sn' => $this->presell_order_sn, + 'sub_orders' => [ + [ + 'pay_price' => $this->pay_price, + 'order_sn' => $this->presell_order_sn, + 'sub_mchid' => $this->merchant->sub_mchid, + ] + ], + 'attach' => 'presell', + 'body' => '尾款支付', + ]; + } + + public function getPayParams($return_url = '') + { + $params = [ + 'order_sn' => $this->presell_order_sn, + 'pay_price' => $this->pay_price, + 'attach' => 'presell', + 'body' => '尾款支付' + ]; + if ($return_url) { + $params['return_url'] = $return_url; + } + return $params; + } +} diff --git a/app/common/model/store/order/StoreCart.php b/app/common/model/store/order/StoreCart.php new file mode 100644 index 00000000..6da947e2 --- /dev/null +++ b/app/common/model/store/order/StoreCart.php @@ -0,0 +1,340 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; +use app\common\model\store\product\ProductAssistSet; +use app\common\model\store\product\ProductAttr; +use app\common\model\store\product\ProductAttrValue; +use app\common\model\store\product\ProductGroup; +use app\common\model\store\product\ProductPresell; +use app\common\model\store\product\ProductPresellSku; +use app\common\model\store\product\ProductSku; +use app\common\model\store\product\Spu; +use app\common\model\store\product\StoreDiscounts; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductAssistSkuRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\ProductGroupSkuRepository; +use app\common\repositories\store\product\ProductPresellSkuRepository; +use app\common\repositories\store\product\ProductSkuRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use function Symfony\Component\String\b; + +class StoreCart extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'cart_id'; + } + + public static function tableName(): string + { + return 'store_cart'; + } + + public function searchCartIdAttr($query,$value) + { + $query->where('cart_id',$value); + } + + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'product_id'); + } + + public function productAttr() + { + return $this->hasOne(ProductAttrValue::class, 'unique', 'product_attr_unique'); + } + + public function attr() + { + return $this->hasMany(ProductAttr::class,'product_id','product_id'); + } + + public function attrValue() + { + return $this->hasMany(ProductAttrValue::class, 'product_id', 'product_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + + public function productPresell() + { + return $this->hasOne(ProductPresell::class,'product_presell_id','source_id'); + } + + public function productDiscount() + { + return $this->hasOne(StoreDiscounts::class, 'discount_id', 'source_id'); + } + + public function getProductDiscountAttrAttr() + { + return app()->make(ProductSkuRepository::class)->getSearch(['active_id' => $this->source_id, 'unique' => $this->product_attr_unique,'active_type'=> 10])->find(); + } + + public function productAssistSet() + { + return $this->hasOne(ProductAssistSet::class,'product_assist_set_id','source_id'); + } + + public function getProductPresellAttrAttr() + { + return app()->make(ProductPresellSkuRepository::class)->getSearch(['product_presell_id' => $this->source_id, 'unique' => $this->product_attr_unique])->find(); + } + + public function getProductAssistAttrAttr() + { + $make = app()->make(ProductAssistSkuRepository::class); + $where = [ + "product_assist_id" => $this->productAssistSet->product_assist_id, + "unique" => $this->product_attr_unique + ]; + return $make->getSearch($where)->find(); + } + + + /** + * TODO 活动商品 SKU + * @return array|\think\Model|null + * @author Qinii + * @day 1/13/21 + */ + public function getActiveSkuAttr() + { + switch ($this->product_type) + { + case 2: + $make = app()->make(ProductPresellSkuRepository::class); + $where['product_presell_id'] = $this->source_id; + break; + case 3: + $make = app()->make(ProductAssistSkuRepository::class); + $where['product_assist_id'] = $this->productAssistSet->product_assist_id; + break; + case 4: + $make = app()->make(ProductGroupSkuRepository::class); + $where['product_group_id'] = $this->product->productGroup->product_group_id; + break; + default: + $make = app()->make(ProductAttrValueRepository::class); + $where['product_id'] = $this->product_id; + break; + } + $where['unique'] = $this->product_attr_unique; + return $make->getSearch($where)->find(); + } + + public function getSpuAttr() + { + if ($this->product_type) { + $where = [ + 'activity_id' => $this->source_id, + 'product_type' => $this->product_type, + ]; + } else { + $where = [ + 'product_id' => $this->product_id, + 'product_type' => $this->product_type, + ]; + } + return Spu::where($where)->field('spu_id,store_name')->find(); + } + /** + * TODO 检测商品是否有效 + * @return bool + * @author Qinii + * @day 2020-10-29 + */ + public function getCheckCartProductAttr() + { + if($this->is_fail == 1) return false; + + if(is_null($this->product) || is_null($this->productAttr) || $this->product->status !== 1 || $this->product->mer_status !== 1 || $this->product->is_del !== 0) + {$this->is_fail = 1;$this->save();return false;} + + switch ($this->product_type) + { + case 0: //普通商品 + if ($this->product->product_type !== 0 || $this->product->is_show !== 1 || $this->productAttr->stock < $this->cart_num || $this->product->is_used !== 1) { + return false; + } + break; + case 1: //秒杀商品 + if ($this->product->product_type !== 1 || $this->product->is_show !== 1) return false; + //结束时间 + if ($this->product->end_time < time()) return false; + //限量 + $order_make = app()->make(StoreOrderRepository::class); + $count = $order_make->seckillOrderCounut($this->product_id); + if ($this->productAttr->stock <= $count) return false; + + //原商品sku库存 + $value_make = app()->make(ProductAttrValueRepository::class); + $sku = $value_make->getWhere(['sku' => $this->productAttr->sku, 'product_id' => $this->product->old_product_id]); + if (!$sku || $sku['stock'] <= 0) return false; + + break; + + case 2: //预售商品 + if($this->source !== 2 || $this->product->product_type !== 2) return false; + if($this->productPresell->status !== 1 || + $this->productPresell->is_show !== 1 || + $this->productPresell->is_del !== 0 || + $this->productPresell->presell_status !== 1) + {$this->is_fail = 1;$this->save();return false;} + + $sku = $this->ActiveSku; + if(!$sku || !$sku->sku()) {$this->is_fail = 1; $this->save(); return false; } + + //库存不足 + if($sku->stock < $this->cart_num || $sku->sku->stock < $this->cart_num) return false; + break; + + case 3: //助力商品 + if($this->source !== 3 || $this->product->product_type !== 3 || ($this->productAssistSet->assist_count !== $this->productAssistSet->yet_assist_count)) return false; + if( + $this->productAssistSet->stop_time < time() || + $this->productAssistSet->sataus === -1 || + !$this->productAssistSet->assist->is_show || + $this->productAssistSet->assist->is_del !== 0 || + $this->productAssistSet->assist->status !== 1) + {$this->is_fail = 1;$this->save();return false;} + $sku = $this->ActiveSku; + if(!$sku || !$sku->sku()) { $this->is_fail = 1; $this->save(); return false; } + //库存不足 + if($sku->stock < $this->cart_num || $sku->sku->stock < $this->cart_num) return false; + break; + case 4: + if($this->source !== 4 || $this->product->product_type !== 4 ) return false; + $sku = $this->ActiveSku; + if(!$sku || !$sku->sku()) { $this->is_fail = 1; $this->save(); return false; } + //库存不足 + if($sku->stock < $this->cart_num || $sku->sku->stock < $this->cart_num) return false; + break; + case 100: //扫码枪商品 + if ($this->product->product_type !== 0 || $this->product->is_show !== 1 || $this->productAttr->stock < $this->cart_num || $this->product->is_used !== 1) { + return false; + } + break; + } + return true; + } + + /** + * TODO + * @return bool + * @author Qinii + * @day 2020-10-29 + */ + public function getUserPayCountAttr() + { + $make = app()->make(StoreOrderRepository::class); + switch ($this->product_type) + { + case 1: //秒杀 + if(!$make->getDayPayCount($this->uid,$this->product_id) || !$make->getPayCount($this->uid,$this->product_id)) + return false; + break; + case 2: //预售 + $count = $this->productPresell->pay_count; + if($count == 0) return true; + $tattend = [ + 'activity_id' => $this->source_id, + 'product_type' => 2, + ]; + $pay_count = $make->getTattendCount($tattend,$this->uid)->sum('total_num'); + if($pay_count < $count) return false; + if (($count - $pay_count) < $this->cart_num) return false; + + break; + + case 3: //助力 + $tattend = [ + 'activity_id' => $this->source_id, + 'product_type' => 3, + ]; + $pay_count = $make->getTattendCount($tattend,$this->uid)->count(); + if($pay_count) return false; + + $count = $this->productAssistSet->assist->pay_count; + if($count !== 0){ + $_tattend = [ + 'exsits_id' => $this->productAssistSet->assist->product_assist_id, + 'product_type' => 3, + ]; + $_count = $make->getTattendCount($_tattend,$this->uid)->count(); + if($_count >= $count) return false; + } + break; + case 4: + $tattend = [ + 'exsits_id' => $this->product_id, + 'product_type' => 4, + ]; + $pay_count = $make->getTattendCount($tattend,$this->uid)->count(); + if($pay_count) return false; + $count = $this->product->productGroup->pay_count; + if($count !== 0){ + $_tattend = [ + 'exsits_id' => $this->product_id, + 'product_type' => 34, + ]; + $_count = $make->getTattendCount($_tattend,$this->uid)->count(); + if($_count >= $count) return false; + } + break; + } + + return true; + } + + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + public function searchIsNewAttr($query,$value) + { + $query->where('is_new',$value); + } + public function searchIsPayAttr($query,$value) + { + $query->where('is_pay',$value); + } + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } + public function searchIsFailAttr($query,$value) + { + $query->where('is_fail',$value); + } + +} diff --git a/app/common/model/store/order/StoreCart.php.bak b/app/common/model/store/order/StoreCart.php.bak new file mode 100644 index 00000000..638e35df --- /dev/null +++ b/app/common/model/store/order/StoreCart.php.bak @@ -0,0 +1,335 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; +use app\common\model\store\product\ProductAssistSet; +use app\common\model\store\product\ProductAttr; +use app\common\model\store\product\ProductAttrValue; +use app\common\model\store\product\ProductGroup; +use app\common\model\store\product\ProductPresell; +use app\common\model\store\product\ProductPresellSku; +use app\common\model\store\product\ProductSku; +use app\common\model\store\product\Spu; +use app\common\model\store\product\StoreDiscounts; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductAssistSkuRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\ProductGroupSkuRepository; +use app\common\repositories\store\product\ProductPresellSkuRepository; +use app\common\repositories\store\product\ProductSkuRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use function Symfony\Component\String\b; + +class StoreCart extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'cart_id'; + } + + public static function tableName(): string + { + return 'store_cart'; + } + + public function searchCartIdAttr($query,$value) + { + $query->where('cart_id',$value); + } + + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'product_id'); + } + + public function productAttr() + { + return $this->hasOne(ProductAttrValue::class, 'unique', 'product_attr_unique'); + } + + public function attr() + { + return $this->hasMany(ProductAttr::class,'product_id','product_id'); + } + + public function attrValue() + { + return $this->hasMany(ProductAttrValue::class, 'product_id', 'product_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + + public function productPresell() + { + return $this->hasOne(ProductPresell::class,'product_presell_id','source_id'); + } + + public function productDiscount() + { + return $this->hasOne(StoreDiscounts::class, 'discount_id', 'source_id'); + } + + public function getProductDiscountAttrAttr() + { + return app()->make(ProductSkuRepository::class)->getSearch(['active_id' => $this->source_id, 'unique' => $this->product_attr_unique,'active_type'=> 10])->find(); + } + + public function productAssistSet() + { + return $this->hasOne(ProductAssistSet::class,'product_assist_set_id','source_id'); + } + + public function getProductPresellAttrAttr() + { + return app()->make(ProductPresellSkuRepository::class)->getSearch(['product_presell_id' => $this->source_id, 'unique' => $this->product_attr_unique])->find(); + } + + public function getProductAssistAttrAttr() + { + $make = app()->make(ProductAssistSkuRepository::class); + $where = [ + "product_assist_id" => $this->productAssistSet->product_assist_id, + "unique" => $this->product_attr_unique + ]; + return $make->getSearch($where)->find(); + } + + + /** + * TODO 活动商品 SKU + * @return array|\think\Model|null + * @author Qinii + * @day 1/13/21 + */ + public function getActiveSkuAttr() + { + switch ($this->product_type) + { + case 2: + $make = app()->make(ProductPresellSkuRepository::class); + $where['product_presell_id'] = $this->source_id; + break; + case 3: + $make = app()->make(ProductAssistSkuRepository::class); + $where['product_assist_id'] = $this->productAssistSet->product_assist_id; + break; + case 4: + $make = app()->make(ProductGroupSkuRepository::class); + $where['product_group_id'] = $this->product->productGroup->product_group_id; + break; + default: + $make = app()->make(ProductAttrValueRepository::class); + $where['product_id'] = $this->product_id; + break; + } + $where['unique'] = $this->product_attr_unique; + return $make->getSearch($where)->find(); + } + + public function getSpuAttr() + { + if ($this->product_type) { + $where = [ + 'activity_id' => $this->source_id, + 'product_type' => $this->product_type, + ]; + } else { + $where = [ + 'product_id' => $this->product_id, + 'product_type' => $this->product_type, + ]; + } + return Spu::where($where)->field('spu_id,store_name')->find(); + } + /** + * TODO 检测商品是否有效 + * @return bool + * @author Qinii + * @day 2020-10-29 + */ + public function getCheckCartProductAttr() + { + if($this->is_fail == 1) return false; + + if(is_null($this->product) || is_null($this->productAttr) || $this->product->status !== 1 || $this->product->mer_status !== 1 || $this->product->is_del !== 0) + {$this->is_fail = 1;$this->save();return false;} + + switch ($this->product_type) + { + case 0: //普通商品 + if ($this->product->product_type !== 0 || $this->product->is_show !== 1 || $this->productAttr->stock < $this->cart_num || $this->product->is_used !== 1) { + return false; + } + break; + case 1: //秒杀商品 + if ($this->product->product_type !== 1 || $this->product->is_show !== 1) return false; + //结束时间 + if ($this->product->end_time < time()) return false; + //限量 + $order_make = app()->make(StoreOrderRepository::class); + $count = $order_make->seckillOrderCounut($this->product_id); + if ($this->productAttr->stock <= $count) return false; + + //原商品sku库存 + $value_make = app()->make(ProductAttrValueRepository::class); + $sku = $value_make->getWhere(['sku' => $this->productAttr->sku, 'product_id' => $this->product->old_product_id]); + if (!$sku || $sku['stock'] <= 0) return false; + + break; + + case 2: //预售商品 + if($this->source !== 2 || $this->product->product_type !== 2) return false; + if($this->productPresell->status !== 1 || + $this->productPresell->is_show !== 1 || + $this->productPresell->is_del !== 0 || + $this->productPresell->presell_status !== 1) + {$this->is_fail = 1;$this->save();return false;} + + $sku = $this->ActiveSku; + if(!$sku || !$sku->sku()) {$this->is_fail = 1; $this->save(); return false; } + + //库存不足 + if($sku->stock < $this->cart_num || $sku->sku->stock < $this->cart_num) return false; + break; + + case 3: //助力商品 + if($this->source !== 3 || $this->product->product_type !== 3 || ($this->productAssistSet->assist_count !== $this->productAssistSet->yet_assist_count)) return false; + if( + $this->productAssistSet->stop_time < time() || + $this->productAssistSet->sataus === -1 || + !$this->productAssistSet->assist->is_show || + $this->productAssistSet->assist->is_del !== 0 || + $this->productAssistSet->assist->status !== 1) + {$this->is_fail = 1;$this->save();return false;} + $sku = $this->ActiveSku; + if(!$sku || !$sku->sku()) { $this->is_fail = 1; $this->save(); return false; } + //库存不足 + if($sku->stock < $this->cart_num || $sku->sku->stock < $this->cart_num) return false; + break; + case 4: + if($this->source !== 4 || $this->product->product_type !== 4 ) return false; + $sku = $this->ActiveSku; + if(!$sku || !$sku->sku()) { $this->is_fail = 1; $this->save(); return false; } + //库存不足 + if($sku->stock < $this->cart_num || $sku->sku->stock < $this->cart_num) return false; + break; + } + return true; + } + + /** + * TODO + * @return bool + * @author Qinii + * @day 2020-10-29 + */ + public function getUserPayCountAttr() + { + $make = app()->make(StoreOrderRepository::class); + switch ($this->product_type) + { + case 1: //秒杀 + if(!$make->getDayPayCount($this->uid,$this->product_id) || !$make->getPayCount($this->uid,$this->product_id)) + return false; + break; + case 2: //预售 + $count = $this->productPresell->pay_count; + if($count == 0) return true; + $tattend = [ + 'activity_id' => $this->source_id, + 'product_type' => 2, + ]; + $pay_count = $make->getTattendCount($tattend,$this->uid)->sum('total_num'); + if($pay_count < $count) return false; + if (($count - $pay_count) < $this->cart_num) return false; + + break; + + case 3: //助力 + $tattend = [ + 'activity_id' => $this->source_id, + 'product_type' => 3, + ]; + $pay_count = $make->getTattendCount($tattend,$this->uid)->count(); + if($pay_count) return false; + + $count = $this->productAssistSet->assist->pay_count; + if($count !== 0){ + $_tattend = [ + 'exsits_id' => $this->productAssistSet->assist->product_assist_id, + 'product_type' => 3, + ]; + $_count = $make->getTattendCount($_tattend,$this->uid)->count(); + if($_count >= $count) return false; + } + break; + case 4: + $tattend = [ + 'exsits_id' => $this->product_id, + 'product_type' => 4, + ]; + $pay_count = $make->getTattendCount($tattend,$this->uid)->count(); + if($pay_count) return false; + $count = $this->product->productGroup->pay_count; + if($count !== 0){ + $_tattend = [ + 'exsits_id' => $this->product_id, + 'product_type' => 34, + ]; + $_count = $make->getTattendCount($_tattend,$this->uid)->count(); + if($_count >= $count) return false; + } + break; + } + + return true; + } + + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + public function searchIsNewAttr($query,$value) + { + $query->where('is_new',$value); + } + public function searchIsPayAttr($query,$value) + { + $query->where('is_pay',$value); + } + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } + public function searchIsFailAttr($query,$value) + { + $query->where('is_fail',$value); + } + +} diff --git a/app/common/model/store/order/StoreGroupOrder.php b/app/common/model/store/order/StoreGroupOrder.php new file mode 100644 index 00000000..41725309 --- /dev/null +++ b/app/common/model/store/order/StoreGroupOrder.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\user\User; +use app\common\repositories\store\coupon\StoreCouponRepository; + +class StoreGroupOrder extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'group_order_id'; + } + + public static function tableName(): string + { + return 'store_group_order'; + } + + public function orderList() + { + return $this->hasMany(StoreOrder::class, 'group_order_id', 'group_order_id'); + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function getGiveCouponAttr() + { + if (count($this->give_coupon_ids)) + return app()->make(StoreCouponRepository::class)->getGiveCoupon($this->give_coupon_ids); + return []; + } + + public function getCancelTimeAttr() + { + $timer = ((int)systemConfig('auto_close_order_timer')) ?: 15; + return date('m-d H:i', strtotime("+ $timer minutes", strtotime($this->create_time))); + } + + public function getCancelUnixAttr() + { + $timer = ((int)systemConfig('auto_close_order_timer')) ?: 15; + return strtotime("+ $timer minutes", strtotime($this->create_time)); + } + + public function getGiveCouponIdsAttr($value) + { + return $value ? explode(',', $value) : []; + } + + public function setGiveCouponIdsAttr($value) + { + return $value ? implode(',', $value) : ''; + } + + public function getCombinePayParams() + { + $params = [ + 'order_sn' => $this->group_order_sn, + 'sub_orders' => [], + 'attach' => 'order', + 'body' => '订单支付', + ]; + foreach ($this->orderList as $order) { + if ($order->pay_price > 0) { + $subOrder = [ + 'pay_price' => $order->pay_price, + 'order_sn' => $order->order_sn, + 'sub_mchid' => $order->merchant->sub_mchid, + ]; + $params['sub_orders'][] = $subOrder; + } + } + return $params; + } + + public function getPayParams($return_url = '') + { + $params = [ + 'order_sn' => $this->group_order_sn, + 'pay_price' => $this->pay_price, + 'attach' => 'order', + 'body' => '订单支付' + ]; + if ($return_url) { + $params['return_url'] = $return_url; + } + return $params; + } +} diff --git a/app/common/model/store/order/StoreImport.php b/app/common/model/store/order/StoreImport.php new file mode 100644 index 00000000..ba420ced --- /dev/null +++ b/app/common/model/store/order/StoreImport.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + +use app\common\model\BaseModel; + +class StoreImport extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'import_id'; + } + + public static function tableName(): string + { + return 'store_import'; + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + + public function searchImportTypeAttr($query,$value) + { + $query->where('import_type',$value); + } + + public function searchTypeAttr($query,$value) + { + $query->where('type',$value); + } + +} diff --git a/app/common/model/store/order/StoreImportDelivery.php b/app/common/model/store/order/StoreImportDelivery.php new file mode 100644 index 00000000..bc65f283 --- /dev/null +++ b/app/common/model/store/order/StoreImportDelivery.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + +use app\common\model\BaseModel; + +class StoreImportDelivery extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'import_delivery_id'; + } + + public static function tableName(): string + { + return 'store_import_delivery'; + } + + public function getStatusAttr($value) + { + return $value ? '已发货' : '未发货'; + } + + public function searchImportIdAttr($query,$value) + { + $query->where('import_id',$value); + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + +} diff --git a/app/common/model/store/order/StoreOrder.php b/app/common/model/store/order/StoreOrder.php new file mode 100644 index 00000000..77ab9451 --- /dev/null +++ b/app/common/model/store/order/StoreOrder.php @@ -0,0 +1,180 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\community\Community; +use app\common\model\store\product\ProductGroupUser; +use app\common\model\store\service\StoreService; +use app\common\model\store\shipping\Express; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; +use app\common\repositories\store\MerchantTakeRepository; + +class StoreOrder extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'order_id'; + } + + public static function tableName(): string + { + return 'store_order'; + } + + public function orderProduct() + { + return $this->hasMany(StoreOrderProduct::class, 'order_id', 'order_id'); + } + + public function refundProduct() + { + return $this->orderProduct()->where('refund_num', '>', 0); + } + + public function refundOrder() + { + return $this->hasMany(StoreRefundOrder::class,'order_id','order_id'); + } + + public function orderStatus() + { + return $this->hasMany(StoreOrderStatus::class,'order_id','order_id')->order('change_time DESC'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + public function receipt() + { + return $this->hasOne(StoreOrderReceipt::class, 'order_id', 'order_id'); + } + + public function spread() + { + return $this->hasOne(User::class, 'uid', 'spread_uid'); + } + + public function TopSpread() + { + return $this->hasOne(User::class, 'uid', 'top_uid'); + } + + public function groupOrder() + { + return $this->hasOne(StoreGroupOrder::class, 'group_order_id', 'group_order_id'); + } + + public function verifyService() + { + return $this->hasOne(StoreService::class, 'service_id', 'verify_service_id'); + } + + public function getTakeAttr() + { + return app()->make(MerchantTakeRepository::class)->get($this->mer_id); + } + + public function searchDataAttr($query, $value) + { + return getModelTime($query, $value); + } + + public function presellOrder() + { + return $this->hasOne(PresellOrder::class, 'order_id', 'order_id'); + } + + public function finalOrder() + { + return $this->hasOne(PresellOrder::class,'order_id','order_id'); + } + + public function groupUser() + { + return $this->hasOne(ProductGroupUser::class,'order_id','order_id'); + } + + public function profitsharing() + { + return $this->hasMany(StoreOrderProfitsharing::class, 'order_id', 'order_id'); + } + + public function firstProfitsharing() + { + return $this->hasOne(StoreOrderProfitsharing::class, 'order_id', 'order_id')->where('type', 'order'); + } + + public function presellProfitsharing() + { + return $this->hasOne(StoreOrderProfitsharing::class, 'order_id', 'order_id')->where('type', 'presell'); + } + + // 核销订单的自订单列表 + public function takeOrderList() + { + return $this->hasMany(self::class,'main_id','order_id')->order('verify_time DESC'); + } + + public function searchMerIdAttr($query, $value) + { + return $query->where('mer_id', $value); + } + + public function getRefundStatusAttr() + { + $day = (int)systemConfig('sys_refund_timer') ?: 15; + return ($this->verify_time ? strtotime($this->verify_time) > strtotime('-' . $day . ' day') : true); + } + + public function getOrderExtendAttr($val) + { + return $val ? json_decode($val, true) : null; + } + + public function getRefundExtensionOneAttr() + { + if ( $this->refundOrder ){ + return $this->refundOrder()->where('status',3)->sum('extension_one'); + } + return 0; + } + + public function getRefundExtensionTwoAttr() + { + if ( $this->refundOrder ){ + return $this->refundOrder()->where('status',3)->sum('extension_two'); + } + return 0; + } + + public function community() + { + return $this->hasOne(Community::class, 'order_id', 'order_id')->bind(['community_id']); + } + + public function getRefundPriceAttr() + { + return StoreRefundOrder::where('order_id',$this->order_id)->where('status',3)->sum('refund_price'); + } +} diff --git a/app/common/model/store/order/StoreOrderProduct.php b/app/common/model/store/order/StoreOrderProduct.php new file mode 100644 index 00000000..104607b1 --- /dev/null +++ b/app/common/model/store/order/StoreOrderProduct.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; +use app\common\model\store\product\Spu; +use app\common\model\user\User; + +class StoreOrderProduct extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'order_product_id'; + } + + public static function tableName(): string + { + return 'store_order_product'; + } + + public function getCartInfoAttr($value) + { + return json_decode($value, true); + } + + public function orderInfo() + { + return $this->hasOne(StoreOrder::class, 'order_id', 'order_id'); + } + + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + + public function spu() + { + return $this->hasOne(Spu::class,'product_id','product_id'); + } + + public function searchUidAttr($query ,$value) + { + $query->where('uid',$value); + } + public function searchActivitIidAttr($query,$value) + { + $query->where('activity_id',$value); + } + public function searchProductTypeAttr($query,$value) + { + $query->where('product_type',$value); + } + public function searchOrderIdAttr($query,$value) + { + $query->where('order_id',$value); + } + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } +} diff --git a/app/common/model/store/order/StoreOrderProfitsharing.php b/app/common/model/store/order/StoreOrderProfitsharing.php new file mode 100644 index 00000000..9d580326 --- /dev/null +++ b/app/common/model/store/order/StoreOrderProfitsharing.php @@ -0,0 +1,82 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class StoreOrderProfitsharing extends BaseModel +{ + + const TYPE_NAME = ['order' => '订单支付', 'presell' => '尾款支付']; + + const STATUS_NAME = [0 => '待分账', 1 => '已分账', -1 => '已退款', -2 => '退款失败']; + + public static function tablePk(): string + { + return 'profitsharing_id'; + } + + + public static function tableName(): string + { + return 'store_order_profitsharing'; + } + + public function getTypeNameAttr() + { + return self::TYPE_NAME[$this->getAttr('type')]; + } + + public function getStatusNameAttr() + { + return self::STATUS_NAME[$this->status]; + } + + public function order() + { + return $this->hasOne(StoreOrder::class, 'order_id', 'order_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function getProfitsharingParmas() + { + return [ + 'transaction_id' => $this->transaction_id, + 'sub_mchid' => $this->merchant->sub_mchid, + 'out_order_no' => $this->profitsharing_sn, + 'receivers' => [ + [ + 'amount' => bcsub($this->profitsharing_price, $this->profitsharing_mer_price, 2), + 'body' => '订单分账', + 'receiver_account' => systemConfig('wechat_service_merid'), + ] + ] + ]; + } + + public function getProfitsharingFinishParmas() + { + return [ + 'sub_mchid' => $this->merchant->sub_mchid, + 'transaction_id' => $this->order->transaction_id, + 'out_order_no' => $this->profitsharing_sn, + 'description' => '订单分账', + ]; + } +} diff --git a/app/common/model/store/order/StoreOrderReceipt.php b/app/common/model/store/order/StoreOrderReceipt.php new file mode 100644 index 00000000..77a0d38b --- /dev/null +++ b/app/common/model/store/order/StoreOrderReceipt.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\order; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; + +class StoreOrderReceipt extends BaseModel +{ + public static function tablePk(): ?string + { + return 'order_receipt_id'; + } + + public static function tableName(): string + { + return 'store_order_receipt'; + } + + public function getReceiptInfoAttr($value) + { + return json_decode($value); + } + + public function getDeliveryInfoAttr($value) + { + return json_decode($value); + } + + public function storeOrder() + { + return $this->hasOne(StoreOrder::class,'order_id','order_id'); + } + + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function searchOrderReceiptIdsAttr($query,$value) + { + $query->whereIn('order_receipt_id',$value); + } + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + public function searchOrderReceiptIdAttr($query,$value) + { + $query->where('order_receipt_id',$value); + } +} diff --git a/app/common/model/store/order/StoreOrderStatus.php b/app/common/model/store/order/StoreOrderStatus.php new file mode 100644 index 00000000..66dd4f9c --- /dev/null +++ b/app/common/model/store/order/StoreOrderStatus.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; + +/** + * Class StoreOrderStatus + * @package app\common\model\store\order + * @author xaboy + * @day 2020/6/12 + */ +class StoreOrderStatus extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/6/12 + */ + public static function tablePk(): ?string + { + return null; + } + + /** + * @return string + * @author xaboy + * @day 2020/6/12 + */ + public static function tableName(): string + { + return 'store_order_status'; + } +} diff --git a/app/common/model/store/order/StoreRefundOrder.php b/app/common/model/store/order/StoreRefundOrder.php new file mode 100644 index 00000000..d208fb15 --- /dev/null +++ b/app/common/model/store/order/StoreRefundOrder.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; + +class StoreRefundOrder extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'refund_order_id'; + } + + public static function tableName(): string + { + return 'store_refund_order'; + } + + public function getPicsAttr($val) + { + return $val ? explode(',', $val) : []; + } + + public function setPicsAttr($val) + { + return $val ? implode(',', $val) : ''; + } + + public function refundProduct() + { + return $this->hasMany(StoreRefundProduct::class, 'refund_order_id', 'refund_order_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function order() + { + return $this->hasOne(StoreOrder::class, 'order_id', 'order_id'); + } + + public function searchDataAttr($query, $value) + { + return getModelTime($query, $value); + } + + public function getAutoRefundTimeAttr() + { + $merAgree = systemConfig('mer_refund_order_agree') ?: 7; + return strtotime('+' . $merAgree . ' day', strtotime($this->status_time)); + } + + public function getCombineRefundParams() + { + return [ + 'sub_mchid' => $this->merchant->sub_mchid, + 'order_sn' => $this->order->order_sn, + 'refund_order_sn' => $this->refund_order_sn, + 'refund_price' => $this->refund_price, + 'pay_price' => $this->order->pay_price, + 'refund_message' => $this->refund_message, + 'open_id' => $this->user->wechat->routine_openid ?? null, + 'transaction_id' => $this->order->transaction_id, + ]; + } +} diff --git a/app/common/model/store/order/StoreRefundProduct.php b/app/common/model/store/order/StoreRefundProduct.php new file mode 100644 index 00000000..7556158f --- /dev/null +++ b/app/common/model/store/order/StoreRefundProduct.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; + +class StoreRefundProduct extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'refund_product_id'; + } + + public static function tableName(): string + { + return 'store_refund_product'; + } + + public function product() + { + return $this->hasOne(StoreOrderProduct::class,'order_product_id','order_product_id'); + } + + public function refundOrder() + { + return $this->hasOne(StoreRefundOrder::class,'refund_order_id','refund_order_id'); + } +} diff --git a/app/common/model/store/order/StoreRefundStatus.php b/app/common/model/store/order/StoreRefundStatus.php new file mode 100644 index 00000000..b18f5f63 --- /dev/null +++ b/app/common/model/store/order/StoreRefundStatus.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\order; + + +use app\common\model\BaseModel; + +class StoreRefundStatus extends BaseModel +{ + + public static function tablePk(): ?string + { + return null; + } + + public static function tableName(): string + { + return 'store_refund_status'; + } +} diff --git a/app/common/model/store/parameter/Parameter.php b/app/common/model/store/parameter/Parameter.php new file mode 100644 index 00000000..33c68062 --- /dev/null +++ b/app/common/model/store/parameter/Parameter.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\parameter; + +use app\common\model\BaseModel; + +class Parameter extends BaseModel +{ + + + public static function tablePk(): string + { + return 'parameter_id'; + } + + public static function tableName(): string + { + return 'parameter'; + } + + public function searchTemplateIdAttr($query, $value) + { + $query->where('template_id',$value); + } + +} diff --git a/app/common/model/store/parameter/ParameterTemplate.php b/app/common/model/store/parameter/ParameterTemplate.php new file mode 100644 index 00000000..02a7fdb0 --- /dev/null +++ b/app/common/model/store/parameter/ParameterTemplate.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\parameter; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\system\Relevance; +use app\common\repositories\system\RelevanceRepository; + +class ParameterTemplate extends BaseModel +{ + + + public static function tablePk(): string + { + return 'template_id'; + } + + public static function tableName(): string + { + return 'parameter_template'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function parameter() + { + return $this->hasMany(Parameter::class,'template_id','template_id'); + } + + public function cateId() + { + return $this->hasMany(Relevance::class,'left_id','template_id')->where('type', RelevanceRepository::PRODUCT_PARAMES_CATE); + } + + public function searchCateIdAttr($query, $value) + { + $id = Relevance::where('right_id',$value)->where('type', RelevanceRepository::PRODUCT_PARAMES_CATE)->column('left_id'); + $query->where('template_id','in',$id); + } + + public function searchTemplateNameAttr($query, $value) + { + $query->whereLike('template_name',"%{$value}%"); + } + + public function searchTemplateIdsAttr($query, $value) + { + $query->whereIn('template_id',$value); + } + + public function searchMerIdAttr($query, $value) + { + $query->where('mer_id',$value); + } + + public function searchMerNameAttr($query, $value) + { + $value = Merchant::whereLike('mer_name',"%{$value}%")->coupon('mer_id'); + $query->whereIn('mer_id',$value); + } + + public function searchIsMerAttr($query, $value) + { + if ($value == 1) { + $query->where('mer_id','>',0); + } else { + $query->where('mer_id',0); + } + } + +} diff --git a/app/common/model/store/parameter/ParameterValue.php b/app/common/model/store/parameter/ParameterValue.php new file mode 100644 index 00000000..7ee90338 --- /dev/null +++ b/app/common/model/store/parameter/ParameterValue.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\parameter; + +use app\common\model\BaseModel; + +class ParameterValue extends BaseModel +{ + + + public static function tablePk(): string + { + return 'parameter_attr_id'; + } + + public static function tableName(): string + { + return 'parameter_value'; + } + + public function parameter() + { + return $this->hasOne(Parameter::class,'parameter_id','parameter_id'); + } +} diff --git a/app/common/model/store/product/Product.php b/app/common/model/store/product/Product.php new file mode 100644 index 00000000..d3dbd9e3 --- /dev/null +++ b/app/common/model/store/product/Product.php @@ -0,0 +1,556 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\dao\store\StoreSeckillActiveDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponProduct; +use app\common\model\store\Guarantee; +use app\common\model\store\GuaranteeTemplate; +use app\common\model\store\GuaranteeValue; +use app\common\model\store\parameter\ParameterValue; +use app\common\model\store\shipping\ShippingTemplate; +use app\common\model\store\StoreBrand; +use app\common\model\store\StoreCategory; +use app\common\model\store\StoreSeckillActive; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\StoreCategoryRepository; +use crmeb\services\VicWordService; +use Darabonba\GatewaySpi\Models\InterceptorContext\request; +use think\db\BaseQuery; +use think\facade\Db; +use think\model\concern\SoftDelete; + +class Product extends BaseModel +{ + use SoftDelete; + + protected $deleteTime = 'is_del'; + protected $defaultSoftDelete = 0; + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return 'product_id'; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product'; + } + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 属性 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function getSliderImageAttr($value) + { + return $value ? explode(',',$value) : []; + } + public function getGiveCouponIdsAttr($value) + { + return $value ? explode(',',$value) : []; + } + public function getMaxExtensionAttr($value) + { + if($this->extension_type){ + $org_extension = ($this->attrValue()->order('extension_two DESC')->value('extension_one')); + } else { + $org_extension = bcmul(($this->attrValue()->order('price DESC')->value('price')) , systemConfig('extension_one_rate'),2); + } + $spreadUser = (request()->hasMacro('isLogin') && request()->isLogin() && request()->userType() == 1 ) ? request()->userInfo() : null; + if ($spreadUser && $spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); + } + return $org_extension; + } + public function getMinExtensionAttr($value) + { + if($this->extension_type){ + $org_extension = ($this->attrValue()->order('extension_two ASC')->value('extension_two')); + } else { + $org_extension = bcmul(($this->attrValue()->order('price ASC')->value('price')) , systemConfig('extension_one_rate'),2); + } + $spreadUser = (request()->hasMacro('isLogin') && request()->isLogin() && request()->userType() == 1 ) ? request()->userInfo() : null; + if ($spreadUser && $spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); + } + return $org_extension; + } + + public function check() + { + if(!$this || !$this->is_show || !$this->is_used || !$this->status || $this->is_del || !$this->mer_status) return false; + return true; + } + + /** + * TODO 秒杀商品结束时间 + * @return false|int + * @author Qinii + * @day 2020-08-15 + */ + public function getEndTimeAttr() + { + if($this->product_type !== 1) return true; + $day = date('Y-m-d',time()); + $_day = strtotime($day); + $end_day = strtotime($this->seckillActive['end_day']); + if($end_day >= $_day) + return strtotime($day.$this->seckillActive['end_time'].':00:00'); + if($end_day < strtotime($day)) + return strtotime(date('Y-m-d',$end_day).$this->seckillActive['end_time'].':00:00'); + } + + /** + * TODO 秒杀商品状态 + * @return array|int + * @author Qinii + * @day 2020-08-19 + */ + public function getSeckillStatusAttr() + { + if($this->product_type !== 1) return true; + $day = strtotime(date('Y-m-d',time())); + $_h = date('H',time()); + $start_day = strtotime($this->seckillActive['start_day']); + $end_day = strtotime($this->seckillActive['end_day']); + if(!$this->seckillActive) return ''; + if($this->seckillActive['status'] !== -1){ + //还未开始 + if($start_day > time() || $this->is_show !== 1)return 0; + //已结束 + if($end_day < $day) return -1; + //开始 - 结束 + if($start_day <= $day && $day <= $end_day){ + //未开始 + if($this->seckillActive['start_time'] > $_h) return 0; + //已结束 + if($this->seckillActive['end_time'] <= $_h) return -1; + //进行中 + if($this->seckillActive['start_time'] <= $_h && $this->seckillActive['end_time'] > $_h) return 1; + } + } + //已结束 + return -1; + + } + + public function getImageAttr($value) + { + if (is_int(strpos($value, 'http'))){ + return $value; + }else{ + return rtrim(systemConfig('site_url'),'/') .$value; + } + } + + public function getTopReplyAttr() + { + $res = ProductReply::where('product_id',$this->product_id)->where('is_del',0)->with(['orderProduct'])->field('reply_id,uid,nickname,merchant_reply_content,avatar,order_product_id,product_id,product_score,service_score,postage_score,comment,pics,rate,create_time') + ->order('sort DESC,create_time DESC')->limit(1)->find(); + if(!$res) return null; + if ($res['orderProduct']) + $res['sku'] = $res['orderProduct']['cart_info']['productAttr']['sku']; + unset($res['orderProduct']); + if (strlen($res['nickname']) > 1) { + $str = mb_substr($res['nickname'],0,1) . '*'; + if (strlen($res['nickname']) > 2) { + $str .= mb_substr($res['nickname'], -1,1); + } + $res['nickname'] = $str; + } + + return $res; + } + + public function getUsStatusAttr() + { + return ($this->status == 1) ? ($this->is_used == 1 ? ( $this->is_show ? 1 : 0 ) : -1) : -1; + } + + public function getGuaranteeTemplateAttr() + { + $gua = GuaranteeTemplate::where('guarantee_template_id',$this->guarantee_template_id)->where('status',1)->where('is_del',0)->find(); + if(!$gua) return []; + $guarantee_id = GuaranteeValue::where('guarantee_template_id',$this->guarantee_template_id)->column('guarantee_id'); + return Guarantee::where('guarantee_id','in',$guarantee_id)->where('status',1)->where('is_del',0)->select(); + } + + public function getMaxIntegralAttr() + { + if(systemConfig('integral_status') && merchantConfig($this->mer_id,'mer_integral_status')){ + $price = ($this->attrValue()->order('price DESC')->value('price')); + $rate = ($this->integral_rate < 0) ? merchantConfig($this->mer_id,'mer_integral_rate') : $this->integral_rate; + $rate = $rate < 0 ? $rate / 100 : 0; + return bcmul($price ,$rate,2); + } + return '0'; + } + + public function getHotRankingAttr() + { + if ($this->product_type == 0) { + $where = [ + 'is_show' => 1, + 'status' => 1, + 'is_used' => 1, + 'product_type' => 0, + 'mer_status' => 1, + 'is_gift_bag' => 0, + 'cate_id' => $this->cate_id + ]; + self::where($where)->order('sales DESC'); + } + } + + /** + * TODO 商品参数 + * @author Qinii + * @day 2022/11/24 + */ + public function getParamsAttr() + { + if(in_array($this->product_type,[0,2])) { + $product_id = $this->product_id; + } else { + $product_id = $this->old_product_id; + } + return ParameterValue::where('product_id',$product_id)->order('parameter_value_id ASC')->select(); + } + + public function getParamTempIdAttr($value) + { + return $value ? explode(',',$value) : $value; + } + + /** + * TODO 是否是会员 + * @return bool + * @author Qinii + * @day 2023/1/4 + */ + public function getIsVipAttr() + { + if (request()->hasMacro('isLogin') && request()->isLogin()) { + if (request()->userType() == 1) { + $userInfo = request()->userInfo(); + return $userInfo->is_svip > 0 ? true : false; + } else { + return true; + } + } + return false; + } + /** + * TODO 是否展示会员价 + * @return bool + * @author Qinii + * @day 2023/1/4 + */ + public function getShowSvipPriceAttr() + { + if ($this->mer_svip_status != 0 && (systemConfig('svip_show_price') != 1 || $this->is_vip) && $this->svip_price_type > 0 ) { + return true; + } + return false; + } + + + /** + * TODO 是否显示会员价等信息 + * @return array + * @author Qinii + * @day 2022/11/24 + */ + public function getShowSvipInfoAttr() + { + $res = [ + 'show_svip' => true, //是否展示会员入口 + 'is_svip' => false, //当前用户是否是会员 + 'show_svip_price' => false, //是否展示会员价 + 'save_money' => 0, //当前商品会员优化多少钱 + ]; + if ($this->product_type == 0) { + if (!systemConfig('svip_switch_status')) { + $res['show_svip'] = false; + } else { + $res['is_svip'] = $this->is_vip; + if ($this->show_svip_price) { + $res['show_svip_price'] = true; + $res['save_money'] = bcsub($this->price, $this->svip_price, 2); + } + } + } + return $res; + } + + /** + * TODO 获取会员价 + * @return int|string + * @author Qinii + * @day 2023/1/4 + */ + public function getSvipPriceAttr() + { + if ($this->product_type == 0 && $this->mer_svip_status != 0 && $this->show_svip_price) { + //默认比例 + if ($this->svip_price_type == 1) { + $rate = merchantConfig($this->mer_id,'svip_store_rate'); + $svip_store_rate = $rate > 0 ? bcdiv($rate,100,2) : 0; + $price = $this->attrValue()->order('price ASC')->value('price'); + return bcmul($price,$svip_store_rate,2); + } + //自定义 + if ($this->svip_price_type == 2) { + return $this->getData('svip_price'); + } + } + return 0; + } + + public function getIsSvipPriceAttr() + { + if ($this->product_type == 0 && $this->mer_svip_status != 0) { + //默认比例 + if ($this->svip_price_type == 1) { + $rate = merchantConfig($this->mer_id,'svip_store_rate'); + $svip_store_rate = $rate > 0 ? bcdiv($rate,100,2) : 0; + $price = $this->attrValue()->order('price ASC')->value('price'); + return bcmul($price,$svip_store_rate,2); + } + //自定义 + if ($this->svip_price_type == 2) { + return $this->getData('svip_price'); + } + } + return 0; + } + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 关联模型 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function merCateId() + { + return $this->hasMany(ProductCate::class,'product_id','product_id')->field('product_id,mer_cate_id'); + } + public function attr() + { + return $this->hasMany(ProductAttr::class,'product_id','product_id'); + } + public function attrValue() + { + return $this->hasMany(ProductAttrValue::class,'product_id','product_id'); + } + public function oldAttrValue() + { + return $this->hasMany(ProductAttrValue::class,'product_id','old_product_id'); + } + public function content() + { + return $this->hasOne(ProductContent::class,'product_id','product_id'); + } + protected function temp() + { + return $this->hasOne(ShippingTemplate::class,'shipping_template_id','temp_id'); + } + public function storeCategory() + { + return $this->hasOne(StoreCategory::class,'store_category_id','cate_id')->field('store_category_id,cate_name'); + } + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id')->field('is_trader,type_id,mer_id,mer_name,mer_avatar,product_score,service_score,postage_score,service_phone,care_count,is_margin'); + } + public function reply() + { + return $this->hasMany(ProductReply::class,'product_id','product_id')->order('create_time DESC'); + } + public function brand() + { + return $this->hasOne(StoreBrand::class,'brand_id','brand_id')->field('brand_id,brand_name'); + } + public function seckillActive() + { + return $this->hasOne(StoreSeckillActive::class,'product_id','product_id'); + } + public function issetCoupon() + { + return $this->hasOne(StoreCouponProduct::class, 'product_id', 'product_id')->alias('A') + ->rightJoin('StoreCoupon B', 'A.coupon_id = B.coupon_id')->where(function (BaseQuery $query) { + $query->where('B.is_limited', 0)->whereOr(function (BaseQuery $query) { + $query->where('B.is_limited', 1)->where('B.remain_count', '>', 0); + }); + })->where(function (BaseQuery $query) { + $query->where('B.is_timeout', 0)->whereOr(function (BaseQuery $query) { + $time = date('Y-m-d H:i:s'); + $query->where('B.is_timeout', 1)->where('B.start_time', '<', $time)->where('B.end_time', '>', $time); + }); + })->field('A.product_id,B.*')->where('status', 1)->where('type', 1)->where('send_type', 0)->where('is_del', 0) + ->order('sort DESC,coupon_id DESC')->hidden(['is_del', 'status']); + } + public function assist() + { + return $this->hasOne(ProductAssist::class,'product_id','product_id'); + } + public function productGroup() + { + return $this->hasOne(ProductGroup::class,'product_id','product_id'); + } + public function guarantee() + { + return $this->hasOne(GuaranteeTemplate::class,'guarantee_template_id','guarantee_template_id')->where('status',1)->where('is_del',0); + } + + + + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 搜索器 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function searchMerCateIdAttr($query, $value) + { + $cate_ids = (StoreCategory::where('path','like','%/'.$value.'/%'))->column('store_category_id'); + $cate_ids[] = intval($value); + $product_id = ProductCate::whereIn('mer_cate_id',$cate_ids)->column('product_id'); + $query->whereIn('Product.product_id',$product_id); + } + public function searchKeywordAttr($query, $value) + { + if (!$value) return; + if (is_numeric($value)) { + $query->whereLike("Product.store_name|Product.keyword|bar_code|Product.product_id", "%{$value}%"); + } else { + $word = app()->make(VicWordService::class)->getWord($value); + $query->where(function ($query) use ($word, $value) { + foreach ($word as $item) { + $query->whereOr('Product.store_name|Product.keyword', 'LIKE', "%$item%"); + } + $query->order(Db::raw('REPLACE(Product.store_name,\'' . $value . '\',\'\')')); + }); + } + } + public function searchStatusAttr($query, $value) + { + if($value === -1){ + $query->where('Product.status', 'in',[-1,-2]); + }else { + $query->where('Product.status',$value); + } + } + public function searchCateIdAttr($query, $value) + { + $query->where('cate_id',$value); + } + public function searchCateIdsAttr($query, $value) + { + $query->whereIn('cate_id',$value); + } + public function searchIsShowAttr($query, $value) + { + $query->where('is_show',$value); + } + public function searchPidAttr($query, $value) + { + $childrenId = app()->make(StoreCategoryRepository::class)->findChildrenId((int)$value); + $ids = array_merge($childrenId, [(int)$value]); + $query->whereIn('cate_id', $ids); + } + public function searchStockAttr($query, $value) + { + $value ? $query->where('stock','<=', $value) : $query->where('stock', $value); + } + public function searchIsNewAttr($query, $value) + { + $query->where('is_new',$value); + } + public function searchPriceAttr($query, $value) + { + if(empty($value[0]) && !empty($value[1])) + $query->where('price','<',$value[1]); + if(!empty($value[0]) && empty($value[1])) + $query->where('price','>',$value[0]); + if(!empty($value[0]) && !empty($value[1])) + $query->whereBetween('price',[$value[0],$value[1]]); + } + public function searchBrandIdAttr($query, $value) + { + $query->whereIn('brand_id',$value); + } + public function searchIsGiftBagAttr($query, $value) + { + $query->where('is_gift_bag',$value); + } + public function searchIsGoodAttr($query, $value) + { + $query->where('is_good',$value); + } + public function searchIsUsedAttr($query, $value) + { + $query->where('is_used',$value); + } + public function searchProductTypeAttr($query, $value) + { + $query->where('Product.product_type',$value); + } + public function searchSeckillStatusAttr($query, $value) + { + $product_id = (new StoreSeckillActiveDao())->getStatus($value)->column('product_id'); + $query->whereIn('Product.product_id',$product_id); + } + public function searchStoreNameAttr($query, $value) + { + $query->where('Product.store_name','like','%'.$value.'%'); + } + public function searchMerStatusAttr($query, $value) + { + $query->where('mer_status',$value); + } + public function searchProductIdAttr($query, $value) + { + $query->where('Product.product_id',$value); + } + public function searchPriceOnAttr($query, $value) + { + $query->where('price','>=',$value); + } + public function searchPriceOffAttr($query, $value) + { + $query->where('price','<=',$value); + } + public function searchisFictiAttr($query, $value) + { + $query->where('type',$value); + } + public function searchGuaranteeTemplateIdAttr($query, $value) + { + $query->whereIn('guarantee_template_id',$value); + } + public function searchTempIdAttr($query, $value) + { + $query->whereIn('Product.temp_id',$value); + } +} diff --git a/app/common/model/store/product/ProductAssist.php b/app/common/model/store/product/ProductAssist.php new file mode 100644 index 00000000..04ba4203 --- /dev/null +++ b/app/common/model/store/product/ProductAssist.php @@ -0,0 +1,161 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductAssistUserRepository; +use app\common\repositories\store\product\SpuRepository; + +class ProductAssist extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return 'product_assist_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_assist'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + + public function assistSku() + { + return$this->hasMany(ProductAssistSku::class,'product_assist_id','product_assist_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + /** + * TODO 状态 + * @return int + * @author Qinii + * @day 2020-10-14 + */ + public function getAssistStatusAttr() + { + $start_time = strtotime($this->start_time); + $end_time = strtotime($this->end_time); + $time = time(); + //已结束 + if($this->action_status == -1) return 2; + //未开始 + if($start_time > $time) return 0; + //进行中 + if($start_time <= $time && $end_time > $time) { + if($this->product_status != 1 || $this->status != 1 || $this->is_show != 1) return 0; + return 1; + } + //已结束 + if($end_time <= $time) { + $this->action_status = -1; + $this->save(); + app()->make(SpuRepository::class)->changeStatus($this->product_assist_id,3); + return 2; + } + } + + public function getStarAttr() + { + return Spu::where('product_type',3)->where('activity_id',$this->product_assist_id)->value('star'); + } + + public function getUsStatusAttr() + { + return ($this->product_status == 1) ? ($this->status == 1 ? ( $this->is_show ? 1 : 0 ) : -1) : -1; + } + + public function getUserCountAttr() + { + return ProductAssistUser::where('product_assist_id',$this->product_assist_id)->count() + ProductAssistSet::where('product_assist_id',$this->product_assist_id)->count(); + } + + /** + * TODO 助力成功人数 + * @return mixed + * @author Qinii + * @day 2020-10-30 + */ + public function getSuccessAttr() + { + $make = app()->make(ProductAssistSetRepository::class); + $where = [ + 'product_assist_id' => $this->product_assist_id, + 'status' => [10, 20] + ]; + return $make->getSearch($where)->count(); + } + + /** + * TODO 支付成功人数 + * @return mixed + * @author Qinii + * @day 2020-10-30 + */ + public function getPayAttr() + { + $make = app()->make(ProductAssistSetRepository::class); + $where = [ + 'product_assist_id' => $this->product_assist_id, + 'status' => 20 + ]; + return $make->getSearch($where)->count(); + } + + /** + * TODO 助力人数 + * @return mixed + * @author Qinii + * @day 2020-10-30 + */ + public function getAllAttr() + { + $make = app()->make(ProductAssistUserRepository::class); + $where = [ + 'product_assist_id' => $this->product_assist_id, + ]; + return $make->getSearch($where)->count(); + } + + public function getStockCountAttr() + { + return ProductAssistSku::where('product_assist_id',$this->product_assist_id)->sum('stock_count'); + } + + public function getStockAttr() + { + return ProductAssistSku::where('product_assist_id',$this->product_assist_id)->sum('stock'); + } +} diff --git a/app/common/model/store/product/ProductAssistSet.php b/app/common/model/store/product/ProductAssistSet.php new file mode 100644 index 00000000..dce9936e --- /dev/null +++ b/app/common/model/store/product/ProductAssistSet.php @@ -0,0 +1,158 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; +use app\common\repositories\store\product\ProductAssistUserRepository; +use app\common\repositories\system\merchant\MerchantRepository; + +class ProductAssistSet extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return 'product_assist_set_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_assist_set'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + + public function assistSku() + { + return$this->hasMany(ProductAssistSku::class,'product_assist_id','product_assist_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function assist() + { + return $this->hasOne(ProductAssist::class,'product_assist_id','product_assist_id'); + } + + public function getStopTimeAttr() + { + return isset($this->assist->end_time) ? strtotime($this->assist->end_time) : ''; + } + + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } + + public function getCheckAttr() + { + if(in_array($this->status,[0,1])){ + if($this->assist_count == $this->yet_assist_count){ + $this->status = 10; + $this->save(); + }else{ + if(isset($this->stop_time) && $this->stop_time < time()){ + $this->status = -1; + $this->save(); + } + } + } + return true; + } + + /** + * TODO 所有助力者数量 + * @return mixed + * @author Qinii + * @day 2020-10-30 + */ + public function getUserCountAttr() + { + $make = app()->make(ProductAssistUserRepository::class); + return $make->getSearch(['product_assist_set_id' => $this->product_assist_set_id])->count(); + } + + public function getViweNumAttr() + { + return self::getDB()->sum('view_num'); + } + + public function getShareNumAttr() + { + return self::getDB()->sum('share_num'); + } + + public function searchProductAssistIdAttr($query,$value) + { + $query->where('product_assist_id',$value); + } + public function searchProductAssistSetIdAttr($query,$value) + { + $query->where('product_assist_set_id',$value); + } + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + public function searchStatusAttr($query, $value) + { + is_array($value) ? $query->whereIn('status', $value) : $query->where('status', $value); + } + public function searchUserNameAttr($query,$value) + { + $uid = User::whereLike('nickname',"%{$value}%")->column('uid'); + $query->where('uid','in',$uid); + } + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + public function searchIsTraderAttr($query,$value) + { + $make = app()->make(MerchantRepository::class); + $mer_id = $make->search(['is_trader' => $value])->column('mer_id'); + $query->where('mer_id','in',$mer_id); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + + public function searchKeywordAttr($query,$value) + { + $id = ProductAssist::whereLike('store_name',"%{$value}%")->column('product_assist_id'); + $query->where(function($query) use ($value, $id){ + $query->where('product_assist_id','in',$id)->whereOr('product_assist_set_id',$value); + }); + } +} diff --git a/app/common/model/store/product/ProductAssistSku.php b/app/common/model/store/product/ProductAssistSku.php new file mode 100644 index 00000000..6f0446d2 --- /dev/null +++ b/app/common/model/store/product/ProductAssistSku.php @@ -0,0 +1,60 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductAssistSku extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return ''; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_assist_sku'; + } + + public function sku() + { + return $this->hasOne(ProductAttrValue::class,'unique','unique'); + } + + + public function searchUniqueAttr($query,$value) + { + $query->where('unique',$value); + } + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + public function searchProductAssistIdAttr($query,$value) + { + $query->where('product_assist_id',$value); + } +} diff --git a/app/common/model/store/product/ProductAssistUser.php b/app/common/model/store/product/ProductAssistUser.php new file mode 100644 index 00000000..2dc7f316 --- /dev/null +++ b/app/common/model/store/product/ProductAssistUser.php @@ -0,0 +1,78 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class ProductAssistUser extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return 'product_assist_user_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_assist_user'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + + public function assistSku() + { + return$this->hasMany(ProductAssistSku::class,'product_assist_id','product_assist_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + +// public function getAvatarImgAttr($value) +// { +// if(!$value){ +// $value = '/static/f.png'; +// } +// return $value; +// } + + public function searchProductAssistSetIdAttr($query,$value) + { + $query->where('product_assist_set_id',$value); + } + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + public function searchProductAssistIdAttr($query,$value) + { + $query->where('product_assist_id',$value); + } +} diff --git a/app/common/model/store/product/ProductAttr.php b/app/common/model/store/product/ProductAttr.php new file mode 100644 index 00000000..e847dd27 --- /dev/null +++ b/app/common/model/store/product/ProductAttr.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductAttr extends BaseModel +{ + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return ''; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product_attr'; + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param $value + * @return array + */ + public function getAttrValuesAttr($value) + { + return explode('-!-',$value); + } + + /** + * @Author:Qinii + * @Date: 2020/5/9 + * @param $value + * @return string + */ + public function setAttrValuesAttr($value) + { + return implode('-!-',$value); + } + +} diff --git a/app/common/model/store/product/ProductAttrValue.php b/app/common/model/store/product/ProductAttrValue.php new file mode 100644 index 00000000..77b8860a --- /dev/null +++ b/app/common/model/store/product/ProductAttrValue.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductAttrValue extends BaseModel +{ + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return ''; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product_attr_value'; + } + + public function getDetailAttr($value) + { + return json_decode($value); + } + + public function product() + { + return $this->hasOne(Product::class, 'product_id','product_id'); + } + + public function getSvipPriceAttr() + { + if ($this->product->product_type == 0 && $this->product->show_svip_price && $this->product->svip_price_type == 1) { + $rate = merchantConfig($this->product->mer_id,'svip_store_rate'); + $svip_store_rate = $rate > 0 ? bcdiv($rate,100,2) : 0; + return bcmul($this->price, $svip_store_rate,2); + } + return $this->getData('svip_price'); + } + + public function getIsSvipPriceAttr() + { + if ($this->product->product_type == 0 && $this->product->svip_price_type == 1) { + $rate = merchantConfig($this->product->mer_id,'svip_store_rate'); + $svip_store_rate = $rate > 0 ? bcdiv($rate,100,2) : 0; + return bcmul($this->price, $svip_store_rate,2); + } + return '未设置'; + } + + public function getBcExtensionOneAttr() + { + if(!intval(systemConfig('extension_status'))) return 0; + if($this->product->extension_type == 1) return $this->extension_one; + return floatval(round(bcmul(systemConfig('extension_one_rate'), $this->price, 3),2)); + } + + public function getBcExtensionTwoAttr() + { + if(!intval(systemConfig('extension_status'))) return 0; + if($this->product->extension_type == 1) return $this->extension_two; + return floatval(round(bcmul(systemConfig('extension_two_rate'), $this->price, 3),2)); + } + + public function productSku() + { + return $this->hasOne(ProductSku::class, 'unique', 'unique'); + } + + public function searchUniqueAttr($query,$value) + { + $query->where('unique',$value); + } + + public function searchSkuAttr($query,$value) + { + $query->where('sku',$value); + } + + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + + +} diff --git a/app/common/model/store/product/ProductCate.php b/app/common/model/store/product/ProductCate.php new file mode 100644 index 00000000..99c29e4e --- /dev/null +++ b/app/common/model/store/product/ProductCate.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\store\StoreCategory; + +class ProductCate extends BaseModel +{ + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return ''; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product_cate'; + } + + public function category() + { + return $this->hasOne(StoreCategory::class,'store_category_id','mer_cate_id')->field('store_category_id,cate_name'); + } + + public function searchProductIdAttr($query, $value) + { + $query->where('product_id',$value); + } +} diff --git a/app/common/model/store/product/ProductContent.php b/app/common/model/store/product/ProductContent.php new file mode 100644 index 00000000..cfe14ae2 --- /dev/null +++ b/app/common/model/store/product/ProductContent.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductContent extends BaseModel +{ + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return ''; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product_content'; + } + + public function getContentAttr($value) + { + return $this->type ? json_decode($value) : $value; + } + +} diff --git a/app/common/model/store/product/ProductCopy.php b/app/common/model/store/product/ProductCopy.php new file mode 100644 index 00000000..7f7d674f --- /dev/null +++ b/app/common/model/store/product/ProductCopy.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\store\StoreCategory; +use app\common\model\system\merchant\Merchant; + +class ProductCopy extends BaseModel +{ + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return 'store_product_copy_id'; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product_copy'; + } + + public function getInfoAttr($value) + { + return json_decode($value) ?: $value; + } + + public function setInfoAttr($value) + { + return json_encode($value,JSON_UNESCAPED_UNICODE); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } +} diff --git a/app/common/model/store/product/ProductGroup.php b/app/common/model/store/product/ProductGroup.php new file mode 100644 index 00000000..cbeffd18 --- /dev/null +++ b/app/common/model/store/product/ProductGroup.php @@ -0,0 +1,156 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrderProduct; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\SpuRepository; + +class ProductGroup extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tablePk(): string + { + return 'product_group_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tableName(): string + { + return 'store_product_group'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function groupBuying() + { + return $this->hasMany(ProductGroupBuying::class,'product_group_id','product_group_id'); + } + + public function activeSku() + { + return $this->hasMany(ProductGroupSku::class,'product_group_id','product_group_id'); + } + + + public function getActionStatusAttr($value) + { + if($value== -1) return -1; + $start_time = strtotime($this->start_time); + $end_time = strtotime($this->end_time); + if($start_time > time()) return 0; + + + if($start_time <= time() && $end_time > time()){ + $this->action_status = 1; + $this->save(); + return 1; + } + if($end_time <= time()){ + $this->action_status = -1; + $this->save(); + queue(ChangeSpuStatusJob::class, ['id' => $this->product_group_id, 'product_type' => 4]); + //app()->make(SpuRepository::class)->changeStatus($this->product_group_id,4); + return -1; + } + } + + public function getStockAttr() + { + return ProductGroupSku::where('product_group_id',$this->product_group_id)->sum('stock'); + } + + public function getStockCountAttr() + { + return ProductGroupSku::where('product_group_id',$this->product_group_id)->sum('stock_count'); + } + + public function getUsStatusAttr() + { + return ($this->product_status == 1) ? ($this->status == 1 ? ( $this->is_show ? 1 : 0 ) : -1) : -1; + } + + //销量 + public function getSalesAttr() + { + $make = app()->make(StoreOrderRepository::class); + $where = [ + 'product_id' => $this->product_id, + 'product_type' => 4, + ]; + return $make->getTattendCount($where,null)->sum('product_num'); + } + + //参与人次:所有(含待付款) + public function getCountTakeAttr() + { + return StoreOrderProduct::where('product_id',$this->product_id)->where('product_type',4)->count(); + } + + //成团人数数量: 成功的团,真实人数 + public function getCountUserAttr() + { + return ProductGroupUser::where('product_group_id',$this->product_group_id) + ->where('uid','<>',0)->where('status',10)->count(); + } + + public function getStarAttr() + { + return Spu::where('product_type',4)->where('activity_id',$this->product_group_id)->value('star'); + } + + + public function searchProductStatusAttr($query,$value) + { + if($value == -1){ + $query->where('product_status','in',[-1,-2]); + }else { + $query->where('product_status', $value); + } + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchProductGroupIdAttr($query,$value) + { + $query->where('product_group_id',$value); + } + +} diff --git a/app/common/model/store/product/ProductGroupBuying.php b/app/common/model/store/product/ProductGroupBuying.php new file mode 100644 index 00000000..09956dd6 --- /dev/null +++ b/app/common/model/store/product/ProductGroupBuying.php @@ -0,0 +1,97 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class ProductGroupBuying extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tablePk(): string + { + return 'group_buying_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tableName(): string + { + return 'store_product_group_buying'; + } + + + public function getStopTimeAttr() + { + return date('Y-m-d H:i:s',$this->end_time); + } + + public function groupUser() + { + return $this->hasMany(ProductGroupUser::class,'group_buying_id','group_buying_id'); + } + + public function initiator() + { + return $this->hasOne(ProductGroupUser::class,'group_buying_id','group_buying_id')->where('is_initiator',1); + } + public function productGroup() + { + return $this->hasOne(ProductGroup::class,'product_group_id','product_group_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + + + + + + public function searchEndTimeAttr($query,$value) + { + $query->where('end_time','<=',$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } + + public function searchProductGroupIdAttr($query,$value) + { + $query->where('product_group_id',$value); + } + + public function searchGroupBuyingIdAttr($query,$value) + { + $query->where('group_buying_id',$value); + } + + +} diff --git a/app/common/model/store/product/ProductGroupSku.php b/app/common/model/store/product/ProductGroupSku.php new file mode 100644 index 00000000..1c13b11a --- /dev/null +++ b/app/common/model/store/product/ProductGroupSku.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\repositories\store\order\StoreOrderRepository; + +class ProductGroupSku extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tablePk(): string + { + return ''; + } + + public function sku() + { + return $this->hasOne(ProductAttrValue::class,'unique','unique'); + } + + public function getSalesAttr() + { + $make = app()->make(StoreOrderRepository::class); + $where = [ + 'product_sku' => $this->unique, + 'product_type' => 4, + 'exsits_id' => $this->product_group_id, + ]; + $count = $make->getTattendCount($where,null)->sum('product_num'); + + return $count; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tableName(): string + { + return 'store_product_group_sku'; + } + + public function searchProductGroupIdAttr($query,$value) + { + $query->where('product_group_id',$value); + } + + public function searchuniqueAttr($query,$value) + { + $query->where('unique',$value); + } +} diff --git a/app/common/model/store/product/ProductGroupUser.php b/app/common/model/store/product/ProductGroupUser.php new file mode 100644 index 00000000..fb5f93ce --- /dev/null +++ b/app/common/model/store/product/ProductGroupUser.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrder; + +class ProductGroupUser extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tablePk(): string + { + return ''; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 1/7/21 + */ + public static function tableName(): string + { + return 'store_product_group_user'; + } + + public function orderInfo() + { + return $this->hasOne(StoreOrder::class,'order_id','order_id'); + } + + public function groupBuying() + { + return $this->hasOne(ProductGroupBuying::class,'group_buying_id','group_buying_id'); + } + + public function productGroup() + { + return $this->hasOne(ProductGroup::class,'product_group_id','product_group_id'); + } + +// public function getAvatarAttr($value) +// { +// return $value ? $value : '/static/f.png'; +// } + + public function searchProductGroupIdAttr($query,$value) + { + $query->where('product_group_id',$value); + } + + public function searchGroupBuyingIdAttr($query,$value) + { + $query->where('group_buying_id',$value); + } + + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } +} diff --git a/app/common/model/store/product/ProductLabel.php b/app/common/model/store/product/ProductLabel.php new file mode 100644 index 00000000..0063aff4 --- /dev/null +++ b/app/common/model/store/product/ProductLabel.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductLabel extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 8/17/21 + */ + public static function tablePk(): string + { + return 'product_label_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 8/17/21 + */ + public static function tableName(): string + { + return 'store_product_label'; + } + + public function searchMerIdAttr($query, $value) + { + $query->where('mer_id', $value); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + + public function searchNameAttr($query, $value) + { + $query->whereLike('name', "%{$value}%"); + } + + public function searchIsDelAttr($query, $value) + { + $query->where('is_del', $value); + } +} diff --git a/app/common/model/store/product/ProductPresell.php b/app/common/model/store/product/ProductPresell.php new file mode 100644 index 00000000..9f2a9c47 --- /dev/null +++ b/app/common/model/store/product/ProductPresell.php @@ -0,0 +1,157 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\product\SpuRepository; + +class ProductPresell extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return 'product_presell_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_presell'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + + public function presellSku() + { + return$this->hasMany(ProductPresellSku::class,'product_presell_id','product_presell_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + /** + * TODO 状态 + * @return int + * @author Qinii + * @day 2020-10-14 + */ + public function getPresellStatusAttr() + { + $start_time = strtotime($this->start_time); + $end_time = strtotime($this->end_time); + $time = time(); + //已结束 + if($this->action_status == -1) return 2; + //未开始 + if($start_time > $time) return 0; + //进行中 + if($start_time <= $time && $end_time > $time) { + if($this->product_status !== 1 || $this->status !==1 || $this->is_show !== 1) return 0; + return 1; + } + //已结束 + if($end_time <= $time) { + if($this->presell_type == 1 || ($this->presell_type == 2 && (strtotime($this->final_end_time) < $time))){ + $this->action_status = -1; + $this->save(); + } + app()->make(SpuRepository::class)->changeStatus($this->product_presell_id,2); + return 2; + } + } + + public function getStarAttr() + { + return Spu::where('product_type',2)->where('activity_id',$this->product_presell_id)->value('star'); + } + + public function getUsStatusAttr() + { + return ($this->product_status == 1) ? ($this->status == 1 ? ( $this->is_show ? 1 : 0 ) : -1) : -1; + } + + /** + * TODO 第一阶段 参与人数 + * @return mixed + * @author Qinii + * @day 2020-10-30 + */ + public function getTattendOneAttr() + { + $data['all'] = ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('one_take'); + $data['pay']= ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('one_pay'); + return $data; + } + + /** + * TODO 第二阶段 参与人数 + * @return mixed + * @author Qinii + * @day 2020-10-30 + */ + public function getTattendTwoAttr() + { + $data['all'] = 0; + $data['pay'] = 0; + if($this->presell_type == 2){ + $data['all'] = ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('one_pay'); + $data['pay']= ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('two_pay'); + } + return $data; + } + + /** + * TODO 获取一张店铺优惠券 + * @return array|\think\Model|null + * @author Qinii + * @day 2020-10-30 + */ + public function getCouponAttr() + { + $make = app()->make(StoreCouponRepository::class); + return $coupon = $make->validCouponQuery(0,0)->where('mer_id',$this->mer_id)->find(); + } + + public function getSelesAttr() + { + return ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('seles'); + } + + public function getStockAttr() + { + return ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('stock'); + } + + public function getStockCountAttr() + { + return ProductPresellSku::where('product_presell_id',$this->product_presell_id)->sum('stock_count'); + } +} diff --git a/app/common/model/store/product/ProductPresellSku.php b/app/common/model/store/product/ProductPresellSku.php new file mode 100644 index 00000000..aa77f631 --- /dev/null +++ b/app/common/model/store/product/ProductPresellSku.php @@ -0,0 +1,78 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductPresellSku extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return ''; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_presell_sku'; + } + + public function sku() + { + return $this->hasOne(ProductAttrValue::class,'unique','unique'); + } + + public function presell() + { + return $this->hasOne(ProductPresell::class,'product_presell_id','product_presell_id'); + } + + public function searchUniqueAttr($query,$value) + { + $query->where('unique',$value); + } + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + public function searchProductPresellIdAttr($query,$value) + { + $query->where('product_presell_id',$value); + } + + public function getBcExtensionOneAttr() + { + if (!intval(systemConfig('extension_status'))) return 0; + if ($this->sku->extension_one > 0) return $this->sku->extension_one; + return floatval(round(bcmul(systemConfig('extension_one_rate'), $this->presell_price, 3), 2)); + } + + public function getBcExtensionTwoAttr() + { + if (!intval(systemConfig('extension_status'))) return 0; + if ($this->sku->extension_two > 0) return $this->sku->extension_two; + return floatval(round(bcmul(systemConfig('extension_two_rate'), $this->presell_price, 3), 2)); + } +} diff --git a/app/common/model/store/product/ProductReply.php b/app/common/model/store/product/ProductReply.php new file mode 100644 index 00000000..5854a1d8 --- /dev/null +++ b/app/common/model/store/product/ProductReply.php @@ -0,0 +1,89 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrderProduct; +use app\common\repositories\store\product\ProductAttrValueRepository; + +/** + * Class ProductReply + * @package app\common\model\store\product + * @author xaboy + * @day 2020/5/30 + */ +class ProductReply extends BaseModel +{ + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tablePk(): string + { + return 'reply_id'; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return string + */ + public static function tableName(): string + { + return 'store_product_reply'; + } + + public function getPicsAttr($value) + { + return $value ? explode(',', $value) : []; + } + + public function setPicsAttr($value) + { + return $value ? implode(',', $value) : ''; + } + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'product_id'); + } + + public function orderProduct() + { + return $this->hasOne(StoreOrderProduct::class,'order_product_id','order_product_id'); + } + + /** + * TODO 用户昵称处理 + * @param $value + * @return string + * @author Qinii + * @day 2022/11/28\ + */ + public function getNicnameAttr($value) + { + if (strlen($value) > 1) { + $str = mb_substr($value,0,1) . '*'; + if (strlen($value) > 2) { + $str .= mb_substr($value, -1,1); + } + return $str; + } + return $value; + } + +} diff --git a/app/common/model/store/product/ProductSku.php b/app/common/model/store/product/ProductSku.php new file mode 100644 index 00000000..5a426fbe --- /dev/null +++ b/app/common/model/store/product/ProductSku.php @@ -0,0 +1,62 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; + +class ProductSku extends BaseModel +{ + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tablePk(): string + { + return 'product_sku_id'; + } + + + /** + * TODO + * @return string + * @author Qinii + * @day 2020-10-12 + */ + public static function tableName(): string + { + return 'store_product_sku'; + } + + public function attrValue() + { + return $this->hasOne(ProductAttrValue::class,'unique','unique'); + } + + + public function searchUniqueAttr($query,$value) + { + $query->where('unique',$value); + } + + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + + public function searchActiveIdAttr($query,$value) + { + $query->where('active_id',$value); + } +} diff --git a/app/common/model/store/product/ProductTake.php b/app/common/model/store/product/ProductTake.php new file mode 100644 index 00000000..24efd108 --- /dev/null +++ b/app/common/model/store/product/ProductTake.php @@ -0,0 +1,76 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\user\User; + +class ProductTake extends BaseModel +{ + + + public static function tablePk(): string + { + return 'product_take_id'; + } + + + public static function tableName(): string + { + return 'store_product_take'; + } + + + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'product_id'); + } + + public function sku() + { + return $this->hasOne(ProductAttrValue::class,'unique','unique'); + } + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } + + + public function searchUniqueAttr($query,$value) + { + $query->where('unique',$value); + } + + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchProductIdAttr($query,$value) + { + $value = is_array($value) ? $value : [$value]; + $query->whereIn('product_id',$value); + } + + public function searchTypeAttr($query,$value) + { + $query->where('type',$value); + } +} diff --git a/app/common/model/store/product/Spu.php b/app/common/model/store/product/Spu.php new file mode 100644 index 00000000..d95dee51 --- /dev/null +++ b/app/common/model/store/product/Spu.php @@ -0,0 +1,239 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\product; + + +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponProduct; +use app\common\model\store\StoreCategory; +use app\common\model\store\StoreSeckillActive; +use app\common\model\system\merchant\Merchant; +use think\db\BaseQuery; + +class Spu extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 12/18/20 + */ + public static function tablePk(): string + { + return 'spu_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 12/18/20 + */ + public static function tableName(): string + { + return 'store_spu'; + } + + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 属性 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function getMinExtensionAttr($value) + { + if(!isset($this->product)) return 0; + if($this->product->extension_type){ + return ($this->product->attrValue()->order('extension_two ASC')->value('extension_two')); + } else { + return bcmul(($this->product->attrValue()->order('price ASC')->value('price')) , systemConfig('extension_one_rate'),2); + } + } + + public function getMaxExtensionAttr($value) + { + if(!isset($this->product)) return 0; + if($this->product->extension_type){ + return ($this->product->attrValue()->order('extension_two DESC')->value('extension_one')); + } else { + return bcmul(($this->product->attrValue()->order('price DESC')->value('price')) , systemConfig('extension_one_rate'),2); + } + } + + public function getStopTimeAttr() + { + if($this->product_type == 1){ + if (is_null($this->seckillActive)) { + return date('Y-m-d H:i:s',strtotime("-1 day")); + } + $day = date('Y-m-d',time()); + $_day = strtotime($day); + $end_day = strtotime($this->seckillActive['end_day']); + if($end_day >= $_day) + return strtotime($day.$this->seckillActive['end_time'].':00:00'); + if($end_day < strtotime($day)) + return strtotime(date('Y-m-d',$end_day).$this->seckillActive['end_time'].':00:00'); + } + } + + public function setMerLabelsAttr($value) + { + if (!empty($value)) { + if (!is_array($value)) + return ','. $value .','; + return ','. implode(',', $value) .','; + } + return $value; + } + + public function getMerLabelsAttr($value) + { + if (!$value) return []; + return explode(',',rtrim(ltrim($value,','),',')); + } + + + public function setSysLabelsAttr($value) + { + if (!empty($value)) { + if (!is_array($value)) + return ','. $value .','; + return ','. implode(',', $value) .','; + } + return $value; + } + + public function getSysLabelsAttr($value) + { + if (!$value) return []; + return explode(',',rtrim(ltrim($value,','),',')); + } + + public function getImageAttr($value) + { + if (is_int(strpos($value, 'http'))) { + return $value; + } else { + return rtrim(systemConfig('site_url'), '/') . $value; + } + } + + /** + * TODO 是否展示会员价 + * @return array + * @author Qinii + * @day 2023/1/4 + */ + public function getShowSvipInfoAttr($value, $data) + { + return $this->product->show_svip_info; + } + + /** + * TODO 获取会员价 + * @return int|string + * @author Qinii + * @day 2023/1/4 + */ + public function getSvipPriceAttr() + { + return $this->product->svip_price; + } + + public function getIsSvipPriceAttr() + { + return $this->product->is_svip_price; + } + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 关联表 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + public function issetCoupon() + { + return $this->hasOne(StoreCouponProduct::class, 'product_id', 'product_id')->alias('A') + ->rightJoin('StoreCoupon B', 'A.coupon_id = B.coupon_id') + ->where(function (BaseQuery $query) { + $query->where('B.is_limited', 0)->whereOr(function (BaseQuery $query) { + $query->where('B.is_limited', 1)->where('B.remain_count', '>', 0); + }); + })->where(function (BaseQuery $query) { + $query->where('B.is_timeout', 0)->whereOr(function (BaseQuery $query) { + $time = date('Y-m-d H:i:s'); + $query->where('B.is_timeout', 1)->where('B.start_time', '<', $time)->where('B.end_time', '>', $time); + }); + })->field('A.product_id,B.*')->where('status', 1)->where('type', 1)->where('send_type', 0)->where('is_del', 0) + ->order('sort DESC,coupon_id DESC')->hidden(['is_del', 'status']); + } + + public function cateName(){ + return $this->hasOne(StoreCategory::class,'store_category_id','cate_id')->bind(['cate_name']); + + } + public function merCateId() + { + return $this->hasMany(ProductCate::class,'product_id','product_id')->field('product_id,mer_cate_id'); + } + public function seckillActive() + { + return $this->hasOne(StoreSeckillActive::class,'seckill_active_id','activity_id'); + } + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 搜索器 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + public function searchProductTypeAttr($query,$value) + { + $query->where('product_type',$value); + } + public function searchActivityIdAttr($query,$value) + { + $query->where('activity_id',$value); + } + public function searchKeyworkAttr($query,$value) + { + $query->whereLike('store_name|keyword',$value); + } + public function searchPriceOnAttr($query, $value) + { + $query->where('price','>=',$value); + } + public function searchPriceOffAttr($query, $value) + { + $query->where('price','<=',$value); + } + public function searchSpuIdsAttr($query, $value) + { + $query->whereIn('spu_id',$value); + } +} diff --git a/app/common/model/store/product/Spu.php.bak b/app/common/model/store/product/Spu.php.bak new file mode 100644 index 00000000..66f48350 --- /dev/null +++ b/app/common/model/store/product/Spu.php.bak @@ -0,0 +1,233 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\product; + + +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponProduct; +use app\common\model\store\StoreSeckillActive; +use app\common\model\system\merchant\Merchant; +use think\db\BaseQuery; + +class Spu extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 12/18/20 + */ + public static function tablePk(): string + { + return 'spu_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 12/18/20 + */ + public static function tableName(): string + { + return 'store_spu'; + } + + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 属性 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function getMinExtensionAttr($value) + { + if(!isset($this->product)) return 0; + if($this->product->extension_type){ + return ($this->product->attrValue()->order('extension_two ASC')->value('extension_two')); + } else { + return bcmul(($this->product->attrValue()->order('price ASC')->value('price')) , systemConfig('extension_one_rate'),2); + } + } + + public function getMaxExtensionAttr($value) + { + if(!isset($this->product)) return 0; + if($this->product->extension_type){ + return ($this->product->attrValue()->order('extension_two DESC')->value('extension_one')); + } else { + return bcmul(($this->product->attrValue()->order('price DESC')->value('price')) , systemConfig('extension_one_rate'),2); + } + } + + public function getStopTimeAttr() + { + if($this->product_type == 1){ + if (is_null($this->seckillActive)) { + return date('Y-m-d H:i:s',strtotime("-1 day")); + } + $day = date('Y-m-d',time()); + $_day = strtotime($day); + $end_day = strtotime($this->seckillActive['end_day']); + if($end_day >= $_day) + return strtotime($day.$this->seckillActive['end_time'].':00:00'); + if($end_day < strtotime($day)) + return strtotime(date('Y-m-d',$end_day).$this->seckillActive['end_time'].':00:00'); + } + } + + public function setMerLabelsAttr($value) + { + if (!empty($value)) { + if (!is_array($value)) + return ','. $value .','; + return ','. implode(',', $value) .','; + } + return $value; + } + + public function getMerLabelsAttr($value) + { + if (!$value) return []; + return explode(',',rtrim(ltrim($value,','),',')); + } + + + public function setSysLabelsAttr($value) + { + if (!empty($value)) { + if (!is_array($value)) + return ','. $value .','; + return ','. implode(',', $value) .','; + } + return $value; + } + + public function getSysLabelsAttr($value) + { + if (!$value) return []; + return explode(',',rtrim(ltrim($value,','),',')); + } + + public function getImageAttr($value) + { + if (is_int(strpos($value, 'http'))) { + return $value; + } else { + return rtrim(systemConfig('site_url'), '/') . $value; + } + } + + /** + * TODO 是否展示会员价 + * @return array + * @author Qinii + * @day 2023/1/4 + */ + public function getShowSvipInfoAttr($value, $data) + { + return $this->product->show_svip_info; + } + + /** + * TODO 获取会员价 + * @return int|string + * @author Qinii + * @day 2023/1/4 + */ + public function getSvipPriceAttr() + { + return $this->product->svip_price; + } + + public function getIsSvipPriceAttr() + { + return $this->product->is_svip_price; + } + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 关联表 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function product() + { + return $this->hasOne(Product::class,'product_id','product_id'); + } + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + public function issetCoupon() + { + return $this->hasOne(StoreCouponProduct::class, 'product_id', 'product_id')->alias('A') + ->rightJoin('StoreCoupon B', 'A.coupon_id = B.coupon_id') + ->where(function (BaseQuery $query) { + $query->where('B.is_limited', 0)->whereOr(function (BaseQuery $query) { + $query->where('B.is_limited', 1)->where('B.remain_count', '>', 0); + }); + })->where(function (BaseQuery $query) { + $query->where('B.is_timeout', 0)->whereOr(function (BaseQuery $query) { + $time = date('Y-m-d H:i:s'); + $query->where('B.is_timeout', 1)->where('B.start_time', '<', $time)->where('B.end_time', '>', $time); + }); + })->field('A.product_id,B.*')->where('status', 1)->where('type', 1)->where('send_type', 0)->where('is_del', 0) + ->order('sort DESC,coupon_id DESC')->hidden(['is_del', 'status']); + } + public function merCateId() + { + return $this->hasMany(ProductCate::class,'product_id','product_id')->field('product_id,mer_cate_id'); + } + public function seckillActive() + { + return $this->hasOne(StoreSeckillActive::class,'seckill_active_id','activity_id'); + } + + /* + * ----------------------------------------------------------------------------------------------------------------- + * 搜索器 + * ----------------------------------------------------------------------------------------------------------------- + */ + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + public function searchProductIdAttr($query,$value) + { + $query->where('product_id',$value); + } + public function searchProductTypeAttr($query,$value) + { + $query->where('product_type',$value); + } + public function searchActivityIdAttr($query,$value) + { + $query->where('activity_id',$value); + } + public function searchKeyworkAttr($query,$value) + { + $query->whereLike('store_name|keyword',$value); + } + public function searchPriceOnAttr($query, $value) + { + $query->where('price','>=',$value); + } + public function searchPriceOffAttr($query, $value) + { + $query->where('price','<=',$value); + } + public function searchSpuIdsAttr($query, $value) + { + $query->whereIn('spu_id',$value); + } +} diff --git a/app/common/model/store/product/StoreDiscountProduct.php b/app/common/model/store/product/StoreDiscountProduct.php new file mode 100644 index 00000000..d6e330df --- /dev/null +++ b/app/common/model/store/product/StoreDiscountProduct.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\repositories\store\product\ProductSkuRepository; + +class StoreDiscountProduct extends BaseModel +{ + + public static function tablePk(): string + { + return 'discount_product_id'; + } + + public static function tableName(): string + { + return 'store_discounts_product'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id', 'product_id'); + } + + public function productSku() + { + return $this->hasMany(ProductSku::class,'active_product_id', 'discount_product_id')->where('active_type',ProductSkuRepository::ACTIVE_TYPE_DISCOUNTS); + } + + public function searchProductIdAttr($query, $value) + { + $query->where('product_id', $value); + } +} diff --git a/app/common/model/store/product/StoreDiscounts.php b/app/common/model/store/product/StoreDiscounts.php new file mode 100644 index 00000000..e9b2e36e --- /dev/null +++ b/app/common/model/store/product/StoreDiscounts.php @@ -0,0 +1,106 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\store\product; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class StoreDiscounts extends BaseModel +{ + + public static function tablePk(): string + { + return 'discount_id'; + } + + public static function tableName(): string + { + return 'store_discounts'; + } + + public function discountsProduct() + { + return $this->hasMany(StoreDiscountProduct::class, 'discount_id', 'discount_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + + public function getTimeAttr() + { + if ($this->is_time) { + return [date('Y-m-d H:i:s',$this->start_time),date('Y-m-d H:i:s', $this->stop_time)]; + } + return []; + } + + + + public function searchTitleAttr($query, $value) + { + $query->whereLike('title', "%{$value}%"); + } + + public function searchMerIdAttr($query, $value) + { + $query->where('mer_id', $value); + } + + public function searchStoreNameAttr($query, $value) + { + $id = StoreDiscountProduct::whereLike('store_name', "%{$value}%")->column('discount_id'); + $query->whereIn('discount_id', $id); + } + + public function searchDiscountIdAttr($query, $value) + { + if (is_array($value)) { + $query->whereIn('discount_id', $value); + } else { + $query->where('discount_id', $value); + } + + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + + public function searchIsShowAttr($query, $value) + { + $query->where('is_show', $value); + } + + public function searchIsDelAttr($query, $value) + { + $query->where('is_del', $value); + } + + public function searchTypeAttr($query, $value) + { + $query->where('type', $value); + } + + + public function searchEndTimeAttr($query, $value) + { + $query->where(function ($query) { + $query->where('is_time', 0)->whereOr(function ($query) { + $query->where('is_time', 1)->where('start_time', '<', time())->where('stop_time', '>', time()); + }); + }); + + } +} diff --git a/app/common/model/store/service/StoreService.php b/app/common/model/store/service/StoreService.php new file mode 100644 index 00000000..c80842e7 --- /dev/null +++ b/app/common/model/store/service/StoreService.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\service; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; + +class StoreService extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'service_id'; + } + + public static function tableName(): string + { + return 'store_service'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } +} diff --git a/app/common/model/store/service/StoreServiceLog.php b/app/common/model/store/service/StoreServiceLog.php new file mode 100644 index 00000000..85184a36 --- /dev/null +++ b/app/common/model/store/service/StoreServiceLog.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\service; + + +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreRefundOrder; +use app\common\model\store\product\Product; +use app\common\model\store\product\ProductGroup; +use app\common\model\store\product\ProductPresell; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; + +class StoreServiceLog extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'service_log_id'; + } + + public static function tableName(): string + { + return 'store_service_log'; + } + + public function orderInfo() + { + return $this->hasOne(StoreOrder::class, 'order_id', 'msn')->with('orderProduct'); + } + + public function product() + { + return $this->hasOne(Product::class, 'product_id', 'msn'); + } + + public function presell() + { + return $this->hasOne(ProductPresell::class, 'product_presell_id', 'msn')->append(['product']); + } + + public function productGroup() + { + return $this->hasOne(ProductGroup::class, 'product_group_id', 'msn')->append(['product']); + } + + public function refundOrder() + { + return $this->hasOne(StoreRefundOrder::class, 'refund_order_id', 'msn')->with('refundProduct.product'); + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid')->field('uid,avatar,nickname'); + } + + public function service() + { + return $this->hasOne(StoreService::class, 'service_id', 'service_id')->field('uid,service_id,avatar,nickname'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function getSendTimeAttr() + { + return strtotime($this->create_time); + } + + public function getSendDateAttr() + { + return date('H:i',strtotime($this->create_time)); + } +} diff --git a/app/common/model/store/service/StoreServiceReply.php b/app/common/model/store/service/StoreServiceReply.php new file mode 100644 index 00000000..4886beb6 --- /dev/null +++ b/app/common/model/store/service/StoreServiceReply.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\service; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class StoreServiceReply extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'service_reply_id'; + } + + public static function tableName(): string + { + return 'store_service_reply'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } +} diff --git a/app/common/model/store/service/StoreServiceUser.php b/app/common/model/store/service/StoreServiceUser.php new file mode 100644 index 00000000..8f13a983 --- /dev/null +++ b/app/common/model/store/service/StoreServiceUser.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\service; + + +use app\common\model\BaseModel; +use app\common\model\system\Extend; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; +use app\common\repositories\system\ExtendRepository; + +class StoreServiceUser extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'service_user_id'; + } + + public static function tableName(): string + { + return 'store_service_user'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id', 'mer_id'); + } + + public function service() + { + return $this->hasOne(StoreService::class, 'service_id', 'service_id'); + } + + public function last() + { + return $this->hasOne(StoreServiceLog::class, 'service_log_id', 'last_log_id'); + } + + public function mark() + { + return $this->hasOne(Extend::class, 'link_id', 'uid')->where('extend_type', ExtendRepository::TYPE_SERVICE_USER_MARK); + } + +} diff --git a/app/common/model/store/shipping/City.php b/app/common/model/store/shipping/City.php new file mode 100644 index 00000000..58624a81 --- /dev/null +++ b/app/common/model/store/shipping/City.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; + +class City extends BaseModel +{ + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tablePk(): string + { + return 'id'; + } + + + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tableName(): string + { + return 'system_city'; + } +} diff --git a/app/common/model/store/shipping/Express.php b/app/common/model/store/shipping/Express.php new file mode 100644 index 00000000..fb30d1c9 --- /dev/null +++ b/app/common/model/store/shipping/Express.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; + +class Express extends BaseModel +{ + /** + * @Author:Qinii + * @return string + */ + public static function tablePk():string + { + return 'id'; + } + + /** + * @Author:Qinii + * @return string + */ + public static function tableName():string + { + return 'express'; + } + + public function searchNameAttr($query, $value) + { + $query->where('name',$value); + } + + public function searchCodeAttr($query, $value) + { + $query->where('code',$value); + } +} diff --git a/app/common/model/store/shipping/ExpressPartner.php b/app/common/model/store/shipping/ExpressPartner.php new file mode 100644 index 00000000..16ad391e --- /dev/null +++ b/app/common/model/store/shipping/ExpressPartner.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; + +class ExpressPartner extends BaseModel +{ + /** + * @Author:Qinii + * @return string + */ + public static function tablePk():string + { + return 'id'; + } + + /** + * @Author:Qinii + * @return string + */ + public static function tableName():string + { + return 'express_partner'; + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchExpressIdAttr($query,$value) + { + $query->where('express_id',$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + +} diff --git a/app/common/model/store/shipping/ShippingTemplate.php b/app/common/model/store/shipping/ShippingTemplate.php new file mode 100644 index 00000000..d7e745ce --- /dev/null +++ b/app/common/model/store/shipping/ShippingTemplate.php @@ -0,0 +1,102 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; + +class ShippingTemplate extends BaseModel +{ + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tablePk(): string + { + return 'shipping_template_id'; + } + + + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tableName(): string + { + return 'shipping_template'; + } + + /** + * 包邮 + * @Author:Qinii + * @Date: 2020/5/6 + * @Time: 18:00 + * @return \think\model\relation\HasMany + */ + public function free() + { + return $this->hasMany(ShippingTemplateFree::class, 'temp_id', 'shipping_template_id'); + } + + /** + * 配送 + * @Author:Qinii + * @Date: 2020/5/6 + * @Time: 18:01 + * @return \think\model\relation\HasMany + */ + public function region() + { + return $this->hasMany(ShippingTemplateRegion::class, 'temp_id', 'shipping_template_id'); + } + + /** + * @return \think\model\relation\HasOne + * @author xaboy + * @day 2020/6/4 + */ + public function freeAddress() + { + return $this->hasOne(ShippingTemplateFree::class, 'temp_id', 'shipping_template_id'); + } + + /** + * @return \think\model\relation\HasOne + * @author xaboy + * @day 2020/6/4 + */ + public function regionAddress() + { + return $this->hasOne(ShippingTemplateRegion::class, 'temp_id', 'shipping_template_id'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/6 + * @Time: 18:01 + * @return \think\model\relation\HasOne + */ + public function undelives() + { + return $this->hasOne(ShippingTemplateUndelivery::class, 'temp_id', 'shipping_template_id'); + } + + public function searchShippingTemplateIdAttr($query,$value) + { + $query->where('shipping_template_id',$value); + } +} diff --git a/app/common/model/store/shipping/ShippingTemplateFree.php b/app/common/model/store/shipping/ShippingTemplateFree.php new file mode 100644 index 00000000..a42dc050 --- /dev/null +++ b/app/common/model/store/shipping/ShippingTemplateFree.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; +use app\common\repositories\store\CityAreaRepository; + +class ShippingTemplateFree extends BaseModel +{ + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tablePk(): string + { + return 'shipping_template_free_id'; + } + + + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tableName(): string + { + return 'shipping_template_free'; + } + + + public function getCityIDsAttr($value, $data) + { + if (!$data['city_id']) return []; + $city_id = explode('/', trim($data['city_id'],'/')); + $data = app()->make(CityAreaRepository::class)->search([])->where('id','in',$city_id)->select(); + $result = []; + foreach ($data as $v) { + $result[] = array_map('intval', explode('/', trim($v['path'] . $v['id'], '/'))); + } + return $result; + } + + public function getCityNameAttr($value, $data) + { + if (!$data['city_id']) return []; + $city_id = explode('/', trim($data['city_id'],'/')); + $result = app()->make(CityAreaRepository::class)->search([])->where('id','in',$city_id)->column('id,name'); + return $result; + } + + public function setCityIdAttr($value) + { + return implode('/',$value); + } +} diff --git a/app/common/model/store/shipping/ShippingTemplateRegion.php b/app/common/model/store/shipping/ShippingTemplateRegion.php new file mode 100644 index 00000000..324a88f8 --- /dev/null +++ b/app/common/model/store/shipping/ShippingTemplateRegion.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; +use app\common\repositories\store\CityAreaRepository; + +class ShippingTemplateRegion extends BaseModel +{ + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tablePk(): string + { + return 'shipping_template_region_id'; + } + + + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tableName(): string + { + return 'shipping_template_region'; + } + + public function getCityIDsAttr($value, $data) + { + if (!$data['city_id']) return []; + $city_id = explode('/', $data['city_id']); + $data = app()->make(CityAreaRepository::class)->search([])->where('id', 'in', $city_id)->select(); + $result = []; + foreach ($data as $v) { + $result[] = array_map('intval', explode('/', trim($v['path'] . $v['id'], '/'))); + } + return $result; + } + + public function getCityNameAttr($value, $data) + { + if (!$data['city_id']) return []; + $city_id = explode('/', trim($data['city_id'],'/')); + $result = app()->make(CityAreaRepository::class)->search([])->where('id','in',$city_id)->column('id,name'); + return $result; + } + + public function setCityIdAttr($value) + { + return '/'.( implode('/',$value)).'/'; + } +} diff --git a/app/common/model/store/shipping/ShippingTemplateUndelivery.php b/app/common/model/store/shipping/ShippingTemplateUndelivery.php new file mode 100644 index 00000000..063ec2b1 --- /dev/null +++ b/app/common/model/store/shipping/ShippingTemplateUndelivery.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\store\shipping; + +use app\common\model\BaseModel; +use app\common\repositories\store\CityAreaRepository; + +class ShippingTemplateUndelivery extends BaseModel +{ + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tablePk(): string + { + return 'shipping_template_undelivery_id'; + } + + + /** + * Author:Qinii + * Date: 2020/5/6 + * Time: 14:20 + * @return string + */ + public static function tableName(): string + { + return 'shipping_template_undelivery'; + } + + public function getCityIDsAttr($value, $data) + { + if (!$data['city_id']) return []; + $city_id = explode('/', $data['city_id']); + $data = app()->make(CityAreaRepository::class)->search([])->where('id', 'in', $city_id)->select(); + $result = []; + foreach ($data as $v) { + $result[] = array_map('intval', explode('/', trim($v['path'] . $v['id'], '/'))); + } + return $result; + } + + public function getCityNameAttr($value, $data) + { + if (!$data['city_id']) return []; + $city_id = explode('/', trim($data['city_id'],'/')); + $result = app()->make(CityAreaRepository::class)->search([])->where('id','in',$city_id)->column('id,name'); + return $result; + } + + public function setCityIdAttr($value) + { + if ($value) return '/'.implode('/',$value).'/'; + return ''; + } +} diff --git a/app/common/model/system/Cache.php b/app/common/model/system/Cache.php new file mode 100644 index 00000000..fdffb0a5 --- /dev/null +++ b/app/common/model/system/Cache.php @@ -0,0 +1,70 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system; + + +use app\common\model\BaseModel; + +/** + * Class Cache + * @package app\common\model\system + * @author xaboy + * @day 2020-04-24 + */ +class Cache extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'key'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'cache'; + } + + /** + * @param $val + * @return false|string + * @author xaboy + * @day 2020-04-24 + */ + public function setResultAttr($val) + { + return json_encode($val); + } + + /** + * @param string $val + * @return mixed + * @author xaboy + * @day 2020-04-24 + */ + public function getResultAttr($val) + { + return json_decode($val, true); + } + +} diff --git a/app/common/model/system/Extend.php b/app/common/model/system/Extend.php new file mode 100644 index 00000000..9b2b98d4 --- /dev/null +++ b/app/common/model/system/Extend.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system; + + +use app\common\model\BaseModel; + +/** + * Class Extend + * @package app\common\model\system + * @author xaboy + * @day 2020-04-24 + */ +class Extend extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'extend_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'extend'; + } + +} diff --git a/app/common/model/system/Relevance.php b/app/common/model/system/Relevance.php new file mode 100644 index 00000000..a4af751a --- /dev/null +++ b/app/common/model/system/Relevance.php @@ -0,0 +1,109 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system; + +use app\common\model\store\product\Spu; +use app\common\model\BaseModel; +use app\common\model\community\Community; +use app\common\model\store\StoreCategory; +use app\common\model\system\auth\Menu; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; +use app\common\repositories\system\RelevanceRepository; + +class Relevance extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tablePk(): string + { + return 'relevance_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 10/26/21 + */ + public static function tableName(): string + { + return 'relevance'; + } + + public function fans() + { + return $this->hasOne(User::class,'uid','left_id'); + } + + public function focus() + { + return $this->hasOne(User::class,'uid','right_id'); + } + + public function community() + { + return $this->hasOne(Community::class,'community_id','right_id') + ->bind(['community_id','title','image','start','uid','create_time','count_start','author','is_type']); + } + + public function getIsStartAttr() + { + return self::where('left_id', $this->right_id) + ->where('right_id',$this->left_id) + ->where('type',RelevanceRepository::TYPE_COMMUNITY_FANS) + ->count() > 0; + } + + public function spu() + { + return $this->hasOne(Spu::class, 'spu_id','right_id'); + } + public function merchant() + { + return $this->hasOne(Merchant::class, 'mer_id','right_id'); + } + + public function category() + { + return $this->hasOne(StoreCategory::class, 'store_category_id','right_id'); + } + + + public function auth() + { + return $this->hasOne(Menu::class, 'menu_id','right_id'); + } + + public function searchLeftIdAttr($query, $value) + { + $query->where('left_id', $value); + } + + public function searchRightIdAttr($query, $value) + { + $query->where('right_id', $value); + } + + public function searchTypeAttr($query, $value) + { + $query->where('type', $value); + } + +} diff --git a/app/common/model/system/admin/Admin.php b/app/common/model/system/admin/Admin.php new file mode 100644 index 00000000..0c2fd6ed --- /dev/null +++ b/app/common/model/system/admin/Admin.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\admin; + +use app\common\model\BaseModel; +use app\common\model\system\auth\Role; + +class Admin extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'admin_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_admin'; + } + + /** + * @param $value + * @return array + * @author xaboy + * @day 2020-03-30 + */ + public function getRolesAttr($value) + { + return array_map('intval', explode(',', $value)); + } + + /** + * @param $value + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public function setRolesAttr($value) + { + return implode(',', $value); + } + + /** + * @param bool $isArray + * @return array|string + * @author xaboy + * @day 2020-04-09 + */ + public function roleNames($isArray = false) + { + $roleNames = Role::getDB()->whereIn('role_id', $this->roles)->column('role_name'); + return $isArray ? $roleNames : implode(',', $roleNames); + } + + public function searchRealNameAttr($query,$value) + { + $query->whereLike('real_name',"%{$value}%"); + } +} diff --git a/app/common/model/system/admin/Log.php b/app/common/model/system/admin/Log.php new file mode 100644 index 00000000..c7de3771 --- /dev/null +++ b/app/common/model/system/admin/Log.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\admin; + + +use app\common\model\BaseModel; + +class Log extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'log_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_log'; + } +} diff --git a/app/common/model/system/attachment/Attachment.php b/app/common/model/system/attachment/Attachment.php new file mode 100644 index 00000000..4735c965 --- /dev/null +++ b/app/common/model/system/attachment/Attachment.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\attachment; + +use app\common\model\BaseModel; + +class Attachment extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'attachment_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_attachment'; + } + + public function parent() + { + return $this->hasOne(self::class, 'config_classify_id', 'pid'); + } + + public function children() + { + return $this->hasMany(self::class, 'pid', 'config_classify_id'); + } +} diff --git a/app/common/model/system/attachment/AttachmentCategory.php b/app/common/model/system/attachment/AttachmentCategory.php new file mode 100644 index 00000000..76144f03 --- /dev/null +++ b/app/common/model/system/attachment/AttachmentCategory.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\attachment; + + +use app\common\model\BaseModel; + +class AttachmentCategory extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'attachment_category_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_attachment_category'; + } +} diff --git a/app/common/model/system/auth/Menu.php b/app/common/model/system/auth/Menu.php new file mode 100644 index 00000000..f86d780b --- /dev/null +++ b/app/common/model/system/auth/Menu.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\auth; + + +use app\common\model\BaseModel; + +class Menu extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'menu_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_menu'; + } + + public function searchMenuIdAttr($query,$value) + { + $query->where('menu_id', $value); + } + + public function searchRouteAttr($query,$value) + { + $query->where('route', $value); + } + + +} diff --git a/app/common/model/system/auth/Role.php b/app/common/model/system/auth/Role.php new file mode 100644 index 00000000..02535617 --- /dev/null +++ b/app/common/model/system/auth/Role.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\auth; + +use app\common\model\BaseModel; + +class Role extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'role_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_role'; + } + + public function ruleNames($isArray = false) + { + $menusName = Menu::getDB()->whereIn('menu_id', $this->rules)->column('menu_name'); + return $isArray ? $menusName : implode(',', $menusName); + } + + + /** + * @param $value + * @return array + * @author xaboy + * @day 2020-03-30 + */ + public function getRulesAttr($value) + { + return array_map('intval', explode(',', $value)); + } + + /** + * @param $value + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public function setRulesAttr($value) + { + return implode(',', $value); + } +} diff --git a/app/common/model/system/config/SystemConfig.php b/app/common/model/system/config/SystemConfig.php new file mode 100644 index 00000000..a81301fe --- /dev/null +++ b/app/common/model/system/config/SystemConfig.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\config; + + +use app\common\model\BaseModel; +use think\model\relation\HasOne; + +/** + * Class SystemConfig + * @package app\common\model\system\config + * @author xaboy + * @day 2020-03-30 + */ +class SystemConfig extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'config_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_config'; + } + + /** + * @return HasOne + * @author xaboy + * @day 2020-03-30 + */ + public function classify() + { + return $this->hasOne(SystemConfig::class, 'config_classify_id', 'config_classify_id'); + } + +} diff --git a/app/common/model/system/config/SystemConfigClassify.php b/app/common/model/system/config/SystemConfigClassify.php new file mode 100644 index 00000000..9563e981 --- /dev/null +++ b/app/common/model/system/config/SystemConfigClassify.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\config; + + +use app\common\model\BaseModel; +use think\model\relation\HasMany; +use think\model\relation\HasOne; + +/** + * Class SystemConfigClassify + * @package app\common\model\system\config + * @author xaboy + * @day 2020-03-30 + */ +class SystemConfigClassify extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'config_classify_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_config_classify'; + } + + + /** + * @return HasOne + * @author xaboy + * @day 2020-03-30 + */ + public function parent() + { + return $this->hasOne(self::class, 'config_classify_id', 'pid'); + } + + /** + * @return HasMany + * @author xaboy + * @day 2020-03-30 + */ + public function children() + { + return $this->hasMany(self::class, 'pid', 'config_classify_id'); + } + + /** + * @return HasMany + * @author xaboy + * @day 2020-03-30 + */ + public function config() + { + return $this->hasMany(SystemConfig::class, 'classify_id', 'config_classify_id'); + } +} diff --git a/app/common/model/system/config/SystemConfigValue.php b/app/common/model/system/config/SystemConfigValue.php new file mode 100644 index 00000000..1b92c399 --- /dev/null +++ b/app/common/model/system/config/SystemConfigValue.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\config; + + +use app\common\model\BaseModel; + +/** + * Class SystemConfigValue + * @package app\common\model\system\config + * @author xaboy + * @day 2020-03-30 + */ +class SystemConfigValue extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'config_value_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_config_value'; + } + + /** + * @param $value + * @return mixed + * @author xaboy + * @day 2020-03-30 + */ + public function getValueAttr($value) + { + return json_decode($value, true); + } + + /** + * @param $value + * @return false|string + * @author xaboy + * @day 2020-03-30 + */ + public function setValueAttr($value) + { + return json_encode($value); + } +} diff --git a/app/common/model/system/diy/Diy.php b/app/common/model/system/diy/Diy.php new file mode 100644 index 00000000..8c802e2f --- /dev/null +++ b/app/common/model/system/diy/Diy.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\diy; + +use app\common\model\BaseModel; + +class Diy extends BaseModel +{ + + public static function tablePk(): string + { + return 'id'; + } + + public static function tableName(): string + { + return 'diy'; + } + + public function searchTypeAttr($query,$value) + { + if (is_array($value)) { + $query->whereIn('type',$value); + } else { + $query->where('type',$value); + } + } + + public function searchMerIdAttr($query, $value) + { + if ($value) { + $query->where(function ($query) use ($value){ + $query->where('mer_id', $value)->whereOr('is_default',2); + }); + } else { + $query->where('mer_id', $value)->where('is_default','<',2); + } + } + + public function searchIsDefaultAttr($query, $value) + { + $query->where('is_default', $value); + } +} diff --git a/app/common/model/system/diy/PageCategory.php b/app/common/model/system/diy/PageCategory.php new file mode 100644 index 00000000..fb8a41b0 --- /dev/null +++ b/app/common/model/system/diy/PageCategory.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\diy; + +use app\common\model\BaseModel; + +class PageCategory extends BaseModel +{ + + public static function tablePk(): string + { + return 'id'; + } + + public static function tableName(): string + { + return 'page_category'; + } + + + public function pageLink() + { + return $this->hasMany(PageLink::class,'cate_id','id'); + } + + public function searchIsMerAttr($query, $value) + { + $query->where('is_mer', $value); + } + + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } +} diff --git a/app/common/model/system/diy/PageLink.php b/app/common/model/system/diy/PageLink.php new file mode 100644 index 00000000..5c965454 --- /dev/null +++ b/app/common/model/system/diy/PageLink.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\diy; + +use app\common\model\BaseModel; + +class PageLink extends BaseModel +{ + + public static function tablePk(): string + { + return 'id'; + } + + public static function tableName(): string + { + return 'page_link'; + } + + public function category() + { + return $this->hasOne(PageCategory::class,'id', 'cate_id'); + } + + public function searchIsMerAttr($query, $value) + { + $query->where('is_mer', $value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + +} diff --git a/app/common/model/system/financial/Financial.php b/app/common/model/system/financial/Financial.php new file mode 100644 index 00000000..2f365d5e --- /dev/null +++ b/app/common/model/system/financial/Financial.php @@ -0,0 +1,94 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\financial; + + +use app\common\model\BaseModel; +use app\common\model\system\admin\Admin; +use app\common\model\system\merchant\Merchant; +use app\common\model\system\merchant\MerchantAdmin; +use think\facade\Db; + +class Financial extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'financial_id'; + } + + public static function tableName(): string + { + return 'financial'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function getFinancialAccountAttr($value) + { + return json_decode($value); + } + + public function getImageAttr($value) + { + return explode(',',$value); + } + + public function getAdminIdAttr($value) + { + return Admin::where('admin_id',$value)->value('real_name'); + } + + public function getMerAdminIdAttr($value) + { + return MerchantAdmin::where('merchant_admin_id',$value)->value('real_name'); + } + + public function searchFinancialIdAttr($query,$value) + { + $query->where('financial_id',$value); + } + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + public function searchFinancailStatusAttr($query,$value) + { + $query->where('financial_status',$value); + } + public function searchFinancailTypeAttr($query,$value) + { + $query->where('financial_type',$value); + } + public function searchKeywordsAttr($query,$value) + { + $query->whereLike('keywords',"%{$value}%"); + } + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } + +} diff --git a/app/common/model/system/groupData/SystemGroup.php b/app/common/model/system/groupData/SystemGroup.php new file mode 100644 index 00000000..a044013b --- /dev/null +++ b/app/common/model/system/groupData/SystemGroup.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\groupData; + + +use app\common\model\BaseModel; + +/** + * Class SystemGroup + * @package app\common\model\system\groupData + * @author xaboy + * @day 2020-03-30 + */ +class SystemGroup extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'group_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_group'; + } + + /** + * @param $value + * @return mixed + * @author xaboy + * @day 2020-03-30 + */ + public function getFieldsAttr($value) + { + return json_decode($value, true); + } + + /** + * @param $value + * @return false|string + * @author xaboy + * @day 2020-03-30 + */ + public function setFieldsAttr($value) + { + return json_encode($value); + } +} diff --git a/app/common/model/system/groupData/SystemGroupData.php b/app/common/model/system/groupData/SystemGroupData.php new file mode 100644 index 00000000..d62e0f24 --- /dev/null +++ b/app/common/model/system/groupData/SystemGroupData.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\groupData; + + +use app\common\model\BaseModel; + +/** + * Class SystemGroupData + * @package app\common\model\system\groupData + * @author xaboy + * @day 2020-03-30 + */ +class SystemGroupData extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'group_data_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'system_group_data'; + } + + public static function getValueAttr($val) + { + return json_decode($val, true); + } + + public static function setValueAttr($val) + { + return json_encode($val); + } +} diff --git a/app/common/model/system/merchant/FinancialRecord.php b/app/common/model/system/merchant/FinancialRecord.php new file mode 100644 index 00000000..1533aa05 --- /dev/null +++ b/app/common/model/system/merchant/FinancialRecord.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\merchant; + + +use app\common\model\BaseModel; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreRefundOrder; +use app\common\model\user\User; +use app\common\repositories\system\merchant\MerchantRepository; + +class FinancialRecord extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'financial_record_id'; + } + + public static function tableName(): string + { + return 'financial_record'; + } + + public function user() + { + return $this->hasOne(User::class,'uid','user_id'); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + public function orderInfo() + { + return $this->hasOne(StoreOrder::class,'order_sn','order_sn'); + } + public function refundOrder() + { + return $this->hasOne(StoreRefundOrder::class,'refund_order_sn','order_sn'); + } +} diff --git a/app/common/model/system/merchant/Merchant.php b/app/common/model/system/merchant/Merchant.php new file mode 100644 index 00000000..2aada263 --- /dev/null +++ b/app/common/model/system/merchant/Merchant.php @@ -0,0 +1,234 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\merchant; + + +use app\common\dao\store\product\ProductDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponProduct; +use app\common\model\store\coupon\StoreCouponUser; +use app\common\model\store\product\Product; +use app\common\model\store\product\Spu; +use app\common\model\system\config\SystemConfigValue; +use app\common\model\system\financial\Financial; +use app\common\model\system\serve\ServeOrder; +use app\common\repositories\store\StoreActivityRepository; + +class Merchant extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'mer_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'merchant'; + } + + public function getDeliveryWayAttr($value) + { + if (!$value) return []; + return explode(',',$value); + } + + public function product() + { + return $this->hasMany(Product::class, 'mer_id', 'mer_id'); + } + + public function config() + { + return $this->hasMany(SystemConfigValue::class, 'mer_id', 'mer_id'); + } + + public function showProduct() + { + return $this->hasMany(Product::class, 'mer_id', 'mer_id') + ->where((new ProductDao())->productShow()) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good') + ->order('is_good DESC,sort DESC'); + } + + /** + * TODO 商户列表下的推荐 + * @return \think\Collection + * @author Qinii + * @day 4/20/22 + */ + public function getAllRecommendAttr() + { + $list = Product::where('mer_id', $this['mer_id']) + ->where((new ProductDao())->productShow()) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,cate_id') + ->order('sort DESC, create_time DESC') + ->limit(10) + ->select()->append(['show_svip_info']); + if ($list) { + $data = []; + $make = app()->make(StoreActivityRepository::class); + foreach ($list as $item) { + $spu_id = Spu::where('product_id',$item->product_id)->where('product_type' ,0)->value('spu_id'); + $act = $make->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_BORDER,$spu_id,$item['cate_id'],$item['mer_id']); + $item['border_pic'] = $act['pic'] ?? ''; + $data[] = $item; + } + return $data; + } + return []; + } + + public function getCityRecommendAttr() + { + $list = Product::where('mer_id', $this['mer_id']) + ->where((new ProductDao())->productShow()) + ->whereLike('delivery_way',"%1%") + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,cate_id') + ->order('sort DESC, create_time DESC') + ->limit(10) + ->select(); + if ($list) { + $data = []; + $make = app()->make(StoreActivityRepository::class); + foreach ($list as $item) { + $spu_id = Spu::where('product_id',$item->product_id)->where('product_type' ,0)->value('spu_id'); + $act = $make->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_BORDER,$spu_id,$item['cate_id'],$item['mer_id']); + $item['border_pic'] = $act['pic'] ?? ''; + $data[] = $item; + } + return $data; + } + return []; + } + + + public function recommend() + { + return $this->hasMany(Product::class, 'mer_id', 'mer_id') + ->where((new ProductDao())->productShow()) + ->where('is_good', 1) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,sales,create_time') + ->order('is_good DESC,sort DESC,create_time DESC') + ->limit(3); + } + + + public function coupon() + { + $time = date('Y-m-d H:i:s'); + return $this->hasMany(StoreCouponUser::class, 'mer_id', 'mer_id')->where('start_time', '<', $time)->where('end_time', '>', $time) + ->where('is_fail', 0)->where('status', 0)->order('coupon_price DESC, coupon_user_id ASC') + ->with(['product' => function ($query) { + $query->field('coupon_id,product_id'); + }, 'coupon' => function ($query) { + $query->field('coupon_id,type'); + }]); + } + + public function getServicesTypeAttr() + { + return merchantConfig($this->mer_id,'services_type'); + } + + public function marginOrder() + { + return $this->hasOne(ServeOrder::class, 'mer_id','mer_id')->where('type', 10)->order('create_time DESC'); + } + + public function refundMarginOrder() + { + return $this->hasOne(Financial::class, 'mer_id', 'mer_id') + ->where('type',1) + ->where('status', -1) + ->order('create_time DESC') + ->limit(1); + } + + public function merchantCategory() + { + return $this->hasOne(MerchantCategory::class, 'merchant_category_id', 'category_id'); + } + + public function merchantType() + { + return $this->hasOne(MerchantType::class, 'mer_type_id', 'type_id'); + } + + public function typeName() + { + return $this->merchantType()->bind(['type_name']); + } + + public function getMerCommissionRateAttr() + { + return $this->commission_rate > 0 ? $this->commission_rate : bcmul($this->merchantCategory->commission_rate, 100, 4); + } + + public function getOpenReceiptAttr() + { + return merchantConfig($this->mer_id, 'mer_open_receipt'); + } + + public function admin() + { + return $this->hasOne(MerchantAdmin::class, 'mer_id', 'mer_id')->where('level', 0); + } + + + public function searchKeywordAttr($query, $value) + { + $query->whereLike('mer_name|mer_keyword', "%{$value}%"); + } + + public function getFinancialAlipayAttr($value) + { + return $value ? json_decode($value) : $value; + } + + public function getFinancialWechatAttr($value) + { + return $value ? json_decode($value) : $value; + } + + public function getFinancialBankAttr($value) + { + return $value ? json_decode($value) : $value; + } + + public function getMerCertificateAttr() + { + return merchantConfig($this->mer_id, 'mer_certificate'); + } + + public function getIssetCertificateAttr() + { + return count(merchantConfig($this->mer_id, 'mer_certificate') ?: []) > 0; + } + + public function searchMerIdsAttr($query, $value) + { + $query->whereIn('mer_id',$value); + } +} diff --git a/app/common/model/system/merchant/Merchant.php.bak b/app/common/model/system/merchant/Merchant.php.bak new file mode 100644 index 00000000..5169a5af --- /dev/null +++ b/app/common/model/system/merchant/Merchant.php.bak @@ -0,0 +1,234 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\merchant; + + +use app\common\dao\store\product\ProductDao; +use app\common\model\BaseModel; +use app\common\model\store\coupon\StoreCouponProduct; +use app\common\model\store\coupon\StoreCouponUser; +use app\common\model\store\product\Product; +use app\common\model\store\product\Spu; +use app\common\model\system\config\SystemConfigValue; +use app\common\model\system\financial\Financial; +use app\common\model\system\serve\ServeOrder; +use app\common\repositories\store\StoreActivityRepository; + +class Merchant extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'mer_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'merchant'; + } + + public function getDeliveryWayAttr($value) + { + if (!$value) return []; + return explode(',',$value); + } + + public function product() + { + return $this->hasMany(Product::class, 'mer_id', 'mer_id'); + } + + public function config() + { + return $this->hasMany(SystemConfigValue::class, 'mer_id', 'mer_id'); + } + + public function showProduct() + { + return $this->hasMany(Product::class, 'mer_id', 'mer_id') + ->where((new ProductDao())->productShow()) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good') + ->order('is_good DESC,sort DESC'); + } + + /** + * TODO 商户列表下的推荐 + * @return \think\Collection + * @author Qinii + * @day 4/20/22 + */ + public function getAllRecommendAttr() + { + $list = Product::where('mer_id', $this['mer_id']) + ->where((new ProductDao())->productShow()) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,cate_id') + ->order('sort DESC, create_time DESC') + ->limit(3) + ->select()->append(['show_svip_info']); + if ($list) { + $data = []; + $make = app()->make(StoreActivityRepository::class); + foreach ($list as $item) { + $spu_id = Spu::where('product_id',$item->product_id)->where('product_type' ,0)->value('spu_id'); + $act = $make->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_BORDER,$spu_id,$item['cate_id'],$item['mer_id']); + $item['border_pic'] = $act['pic'] ?? ''; + $data[] = $item; + } + return $data; + } + return []; + } + + public function getCityRecommendAttr() + { + $list = Product::where('mer_id', $this['mer_id']) + ->where((new ProductDao())->productShow()) + ->whereLike('delivery_way',"%1%") + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,cate_id') + ->order('sort DESC, create_time DESC') + ->limit(3) + ->select(); + if ($list) { + $data = []; + $make = app()->make(StoreActivityRepository::class); + foreach ($list as $item) { + $spu_id = Spu::where('product_id',$item->product_id)->where('product_type' ,0)->value('spu_id'); + $act = $make->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_BORDER,$spu_id,$item['cate_id'],$item['mer_id']); + $item['border_pic'] = $act['pic'] ?? ''; + $data[] = $item; + } + return $data; + } + return []; + } + + + public function recommend() + { + return $this->hasMany(Product::class, 'mer_id', 'mer_id') + ->where((new ProductDao())->productShow()) + ->where('is_good', 1) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,sales,create_time') + ->order('is_good DESC,sort DESC,create_time DESC') + ->limit(3); + } + + + public function coupon() + { + $time = date('Y-m-d H:i:s'); + return $this->hasMany(StoreCouponUser::class, 'mer_id', 'mer_id')->where('start_time', '<', $time)->where('end_time', '>', $time) + ->where('is_fail', 0)->where('status', 0)->order('coupon_price DESC, coupon_user_id ASC') + ->with(['product' => function ($query) { + $query->field('coupon_id,product_id'); + }, 'coupon' => function ($query) { + $query->field('coupon_id,type'); + }]); + } + + public function getServicesTypeAttr() + { + return merchantConfig($this->mer_id,'services_type'); + } + + public function marginOrder() + { + return $this->hasOne(ServeOrder::class, 'mer_id','mer_id')->where('type', 10)->order('create_time DESC'); + } + + public function refundMarginOrder() + { + return $this->hasOne(Financial::class, 'mer_id', 'mer_id') + ->where('type',1) + ->where('status', -1) + ->order('create_time DESC') + ->limit(1); + } + + public function merchantCategory() + { + return $this->hasOne(MerchantCategory::class, 'merchant_category_id', 'category_id'); + } + + public function merchantType() + { + return $this->hasOne(MerchantType::class, 'mer_type_id', 'type_id'); + } + + public function typeName() + { + return $this->merchantType()->bind(['type_name']); + } + + public function getMerCommissionRateAttr() + { + return $this->commission_rate > 0 ? $this->commission_rate : bcmul($this->merchantCategory->commission_rate, 100, 4); + } + + public function getOpenReceiptAttr() + { + return merchantConfig($this->mer_id, 'mer_open_receipt'); + } + + public function admin() + { + return $this->hasOne(MerchantAdmin::class, 'mer_id', 'mer_id')->where('level', 0); + } + + + public function searchKeywordAttr($query, $value) + { + $query->whereLike('mer_name|mer_keyword', "%{$value}%"); + } + + public function getFinancialAlipayAttr($value) + { + return $value ? json_decode($value) : $value; + } + + public function getFinancialWechatAttr($value) + { + return $value ? json_decode($value) : $value; + } + + public function getFinancialBankAttr($value) + { + return $value ? json_decode($value) : $value; + } + + public function getMerCertificateAttr() + { + return merchantConfig($this->mer_id, 'mer_certificate'); + } + + public function getIssetCertificateAttr() + { + return count(merchantConfig($this->mer_id, 'mer_certificate') ?: []) > 0; + } + + public function searchMerIdsAttr($query, $value) + { + $query->whereIn('mer_id',$value); + } +} diff --git a/app/common/model/system/merchant/MerchantAdmin.php b/app/common/model/system/merchant/MerchantAdmin.php new file mode 100644 index 00000000..68f098ba --- /dev/null +++ b/app/common/model/system/merchant/MerchantAdmin.php @@ -0,0 +1,76 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\merchant; + + +use app\common\model\BaseModel; +use app\common\model\system\auth\Role; + +class MerchantAdmin extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'merchant_admin_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'merchant_admin'; + } + + /** + * @param $value + * @return array + * @author xaboy + * @day 2020-03-30 + */ + public function getRolesAttr($value) + { + return array_map('intval', explode(',', $value)); + } + + /** + * @param $value + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public function setRolesAttr($value) + { + return implode(',', $value); + } + + /** + * @param bool $isArray + * @return array|string + * @author xaboy + * @day 2020-04-18 + */ + public function roleNames($isArray = false) + { + $roleNames = Role::getDB()->whereIn('role_id', $this->roles)->column('role_name'); + return $isArray ? $roleNames : implode(',', $roleNames); + } +} diff --git a/app/common/model/system/merchant/MerchantApplyments.php b/app/common/model/system/merchant/MerchantApplyments.php new file mode 100644 index 00000000..8ce07d50 --- /dev/null +++ b/app/common/model/system/merchant/MerchantApplyments.php @@ -0,0 +1,76 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\system\merchant; + +use app\common\model\BaseModel; + +class MerchantApplyments extends BaseModel +{ + + /** + * TODO + * @return string + * @author Qinii + * @day 6/22/21 + */ + public static function tablePk(): string + { + return 'mer_applyments_id'; + } + + /** + * TODO + * @return string + * @author Qinii + * @day 6/22/21 + */ + public static function tableName(): string + { + return 'merchant_applyments'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function searchOutRequestNoAttr($query,$value) + { + $query->where('out_request_no',$value); + } + + public function searchKeywordAttr($query,$value) + { + $query->whereLike('mer_name',"%{$value}%"); + } + + public function searchMerIdAttr($query,$value) + { + $query->where('mer_id',$value); + } + + public function searchStatusAttr($query,$value) + { + $query->where('status',$value); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query,$value); + } + + public function searchMerApplymentsIdAttr($query,$value) + { + $query->where('mer_applyments_id',$value); + } +} diff --git a/app/common/model/system/merchant/MerchantCategory.php b/app/common/model/system/merchant/MerchantCategory.php new file mode 100644 index 00000000..a337f06a --- /dev/null +++ b/app/common/model/system/merchant/MerchantCategory.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\merchant; + + +use app\common\model\BaseModel; + +/** + * Class MerchantCategory + * @package app\common\model\system\merchant + * @author xaboy + * @day 2020-05-06 + */ +class MerchantCategory extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'merchant_category_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'merchant_category'; + } +} diff --git a/app/common/model/system/merchant/MerchantIntention.php b/app/common/model/system/merchant/MerchantIntention.php new file mode 100644 index 00000000..8323d607 --- /dev/null +++ b/app/common/model/system/merchant/MerchantIntention.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\system\merchant; + +use app\common\model\BaseModel; + +class MerchantIntention extends BaseModel +{ + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'mer_intention_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'merchant_intention'; + } + + public function setImagesAttr($value) + { + return implode(',', $value); + } + + public function getImagesAttr($value) + { + return $value ? explode(',', $value) : []; + } + + public function merchantCategory() + { + return $this->hasOne(MerchantCategory::class, 'merchant_category_id', 'merchant_category_id')->bind(['category_name']); + } + + public function merchantType() + { + return $this->hasOne(MerchantType::class, 'mer_type_id', 'mer_type_id')->bind(['type_name']); + } +} diff --git a/app/common/model/system/merchant/MerchantType.php b/app/common/model/system/merchant/MerchantType.php new file mode 100644 index 00000000..f95abc87 --- /dev/null +++ b/app/common/model/system/merchant/MerchantType.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\merchant; + + +use app\common\model\BaseModel; +use app\common\model\system\auth\Menu; +use app\common\model\system\Relevance; +use app\common\repositories\system\RelevanceRepository; + +class MerchantType extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'mer_type_id'; + } + + public static function tableName(): string + { + return 'merchant_type'; + } + + public function auth() + { + return $this->hasMany(Relevance::class, 'left_id', 'mer_type_id')->where('type', RelevanceRepository::TYPE_MERCHANT_AUTH); + } +} diff --git a/app/common/model/system/notice/SystemNotice.php b/app/common/model/system/notice/SystemNotice.php new file mode 100644 index 00000000..904cceab --- /dev/null +++ b/app/common/model/system/notice/SystemNotice.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\notice; + + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; + +class SystemNotice extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'notice_id'; + } + + public static function tableName(): string + { + return 'system_notice'; + } +} diff --git a/app/common/model/system/notice/SystemNoticeConfig.php b/app/common/model/system/notice/SystemNoticeConfig.php new file mode 100644 index 00000000..9f26cb7b --- /dev/null +++ b/app/common/model/system/notice/SystemNoticeConfig.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\notice; + + +use app\common\model\BaseModel; +use app\common\model\wechat\TemplateMessage; + +/** + * Class SystemNoticeLog + * @package app\common\model\system\notice + * @author xaboy + * @day 2020/11/6 + */ +class SystemNoticeConfig extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/11/6 + */ + public static function tablePk(): ?string + { + return 'notice_config_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020/11/6 + */ + public static function tableName(): string + { + return 'system_notice_config'; + } + + public function wechatTemplate() + { + return $this->hasOne(TemplateMessage::class,'tempkey','wechat_tempkey'); + } + + public function routineTemplate() + { + return $this->hasOne(TemplateMessage::class,'tempkey','routine_tempkey'); + } + + public function searchKeywordAttr($query, $value) + { + $query->whereLike("notice_title|notice_key|notice_info","%{$value}%"); + } + + public function searchTypeAttr($query, $value) + { + $query->where("type",$value); + } + + public function searchConstKeyAttr($query, $value) + { + $query->where("const_key",$value); + } +} diff --git a/app/common/model/system/notice/SystemNoticeLog.php b/app/common/model/system/notice/SystemNoticeLog.php new file mode 100644 index 00000000..ac18ff5f --- /dev/null +++ b/app/common/model/system/notice/SystemNoticeLog.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\notice; + + +use app\common\model\BaseModel; + +/** + * Class SystemNoticeLog + * @package app\common\model\system\notice + * @author xaboy + * @day 2020/11/6 + */ +class SystemNoticeLog extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/11/6 + */ + public static function tablePk(): ?string + { + return 'notice_log_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020/11/6 + */ + public static function tableName(): string + { + return 'system_notice_log'; + } + + /** + * @return \think\model\relation\HasOne + * @author xaboy + * @day 2020/11/6 + */ + public function notice() + { + return $this->hasOne(SystemNotice::class, 'notice_id', 'notice_id'); + } +} diff --git a/app/common/model/system/serve/ServeMeal.php b/app/common/model/system/serve/ServeMeal.php new file mode 100644 index 00000000..70cbcf3f --- /dev/null +++ b/app/common/model/system/serve/ServeMeal.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\system\serve; + +use app\common\model\BaseModel; + +class ServeMeal extends BaseModel +{ + + + public static function tablePk(): string + { + return 'meal_id'; + } + + + public static function tableName(): string + { + return 'serve_meal'; + } + + public function searchTypeAttr($query, $value) + { + $query->where('type', $value); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + + public function searchNameAttr($query, $value) + { + $query->whereLike('name', "%{$value}%"); + } + + public function searchIsDelAttr($query, $value) + { + $query->where('is_del', $value); + } + +} diff --git a/app/common/model/system/serve/ServeOrder.php b/app/common/model/system/serve/ServeOrder.php new file mode 100644 index 00000000..1cae0985 --- /dev/null +++ b/app/common/model/system/serve/ServeOrder.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- +namespace app\common\model\system\serve; + +use app\common\model\BaseModel; +use app\common\model\system\merchant\Merchant; +use app\common\model\user\User; + +class ServeOrder extends BaseModel +{ + + public static function tablePk(): string + { + return 'order_id'; + } + + public static function tableName(): string + { + return 'serve_order'; + } + + public function getOrderInfoAttr($value) + { + return json_decode($value); + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','mer_id'); + } + + public function userInfo() + { + return $this->hasOne(User::class,'mer_id','ud'); + } + + public function searchTypeAttr($query, $value) + { + $query->where('type', $value); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + + public function searchOrderSnAttr($query, $value) + { + $query->where('order_sn', $value); + } + + public function searchIsDelAttr($query, $value) + { + $query->where('is_del', $value); + } + + public function searchMealIdAttr($query, $value) + { + $query->where('meal_id', $value); + } + + public function searchMerIdAttr($query, $value) + { + $query->where('mer_id', $value); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query, $value); + } + + public function searchPayTypeAttr($query,$value) + { + $query->where('value'); + } +} diff --git a/app/common/model/system/sms/SmsRecord.php b/app/common/model/system/sms/SmsRecord.php new file mode 100644 index 00000000..6e421c98 --- /dev/null +++ b/app/common/model/system/sms/SmsRecord.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\system\sms; + + +use app\common\model\BaseModel; + +class SmsRecord extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'sms_record_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'sms_record'; + } +} diff --git a/app/common/model/user/FeedBackCategory.php b/app/common/model/user/FeedBackCategory.php new file mode 100644 index 00000000..c00939bc --- /dev/null +++ b/app/common/model/user/FeedBackCategory.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\user; + +use app\common\model\BaseModel; + +class FeedBackCategory extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'feedback_category_id'; + } + + public static function tableName(): string + { + return 'feedback_category'; + } + +} diff --git a/app/common/model/user/Feedback.php b/app/common/model/user/Feedback.php new file mode 100644 index 00000000..0c2fe2c1 --- /dev/null +++ b/app/common/model/user/Feedback.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\user; + +use app\common\model\BaseModel; + +class Feedback extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'feedback_id'; + } + + public static function tableName(): string + { + return 'feedback'; + } + + public function getImagesAttr($val) + { + return $val ? json_decode($val, true) : []; + } + + public function setImagesAttr($val) + { + return json_encode($val ?: []); + } + + public function getUpdateTimeAttr($value) + { + if ($value) return date('m月d日',strtotime($value)); + return $value; + } + + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } + + public function type() + { + return $this->hasOne(FeedBackCategory::class,'feedback_category_id','type'); + } +} diff --git a/app/common/model/user/LabelRule.php b/app/common/model/user/LabelRule.php new file mode 100644 index 00000000..f9717f57 --- /dev/null +++ b/app/common/model/user/LabelRule.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class LabelRule extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'label_rule_id'; + } + + public static function tableName(): string + { + return 'label_rule'; + } + + public function label() + { + return $this->hasOne(UserLabel::class, 'label_id', 'label_id'); + } +} diff --git a/app/common/model/user/MemberInterests.php b/app/common/model/user/MemberInterests.php new file mode 100644 index 00000000..d9d5ba1e --- /dev/null +++ b/app/common/model/user/MemberInterests.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class MemberInterests extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'interests_id'; + } + + public static function tableName(): string + { + return 'member_interests'; + } + + public function searchTypeAttr($query, $value) + { + $query->where('type',$value); + } + + public function searchInterestsIdAttr($query, $value) + { + $query->where('interests_id',$value); + } + + public function searchNameAttr($query, $value) + { + $query->whereLike('name',"%{$value}%"); + } + + public function searchBrokerageLevelAttr($query, $value) + { + $query->where('brokerage_level',$value); + } + + public function searchLevelAttr($query, $value) + { + $query->where('brokerage_level', '<=', $value); + } + + public function searchStatusAttr($query, $value) + { + $query->where('status', $value); + } + +} diff --git a/app/common/model/user/User.php b/app/common/model/user/User.php new file mode 100644 index 00000000..4d252013 --- /dev/null +++ b/app/common/model/user/User.php @@ -0,0 +1,326 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; +use app\common\model\store\service\StoreService; +use app\common\model\wechat\WechatUser; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserExtractRepository; +use app\common\repositories\user\UserHistoryRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserRepository; + +/** + * Class User + * @package app\common\model\user + * @author xaboy + * @day 2020-04-28 + */ +class User extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'uid'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'user'; + } + + /** + * @param $value + * @return string + * @author xaboy + * @day 2020-05-09 + */ + public function getBirthdayAttr($value) + { + return $value == '0000-00-00' ? '' : $value; + } + + public function getIsSvipAttr($value) + { + + if (systemConfig('svip_switch_status') == 1) { + return $value; + } else { + return $value > 0 ? 0 : $value; + } + } + + /** + * @param $value + * @return array + * @author xaboy + * @day 2020-05-09 + */ + public function getLabelIdAttr($value) + { + return $value ? explode(',', $value) : []; + } + + /** + * @param $value + * @return string + * @author xaboy + * @day 2020-05-09 + */ + public function setLabelIdAttr($value) + { + return is_array($value) ? implode(',', $value) : $value; + } + + public function getValidSpreadUidAttr() + { + if (!$this->spread_uid) return 0; + else { + $data = self::getDB()->where('uid', $this->spread_uid)->field('is_promoter,spread_uid')->find(); + if ($data && $data['is_promoter']) + return $this->spread_uid; + else + return 0; + } + } + + public function getValidSpreadAttr() + { + if (!$this->spread_uid) return null; + else { + $data = self::getDB()->where('uid', $this->spread_uid)->field('is_promoter,spread_uid,brokerage_level,uid')->find(); + if ($data && $data['is_promoter']) + return $data; + else + return null; + } + } + + public function getValidTopUidAttr() + { + if (!$this->top_uid) return 0; + else { + $data = self::getDB()->where('uid', $this->top_uid)->field('is_promoter,spread_uid')->find(); + if ($data && $data['is_promoter']) + return $this->top_uid; + else + return 0; + } + } + + public function getValidTopAttr() + { + if (!$this->top_uid) return null; + else { + $data = self::getDB()->where('uid', $this->top_uid)->field('is_promoter,spread_uid,brokerage_level,uid')->find(); + if ($data && $data['is_promoter']) + return $data; + else + return null; + } + } + + public function getTopUidAttr() + { + return self::getDB()->where('uid', $this->spread_uid)->value('spread_uid') ?: 0; + } + + /** + * @return \think\model\relation\HasOne + * @author xaboy + * @day 2020-05-09 + */ + public function group() + { + return $this->hasOne(UserGroup::class, 'group_id', 'group_id'); + } + + public function spread() + { + return $this->hasOne(User::class, 'uid', 'spread_uid'); + } + + public function brokerage() + { + return $this->hasOne(UserBrokerage::class, 'brokerage_level', 'brokerage_level')->where('type',0); + } + + public function member() + { + return $this->hasOne(UserBrokerage::class, 'brokerage_level', 'member_level')->where('type',1); + } + + /** + * @param $spreadUid + * @author xaboy + * @day 2020-04-28 + */ + public function setSpread($spreadUid) + { + if (self::getDB()->where('uid', $spreadUid)->value('is_promoter')) + $this->save([ + 'spread_uid' => $spreadUid, + 'spread_time' => date('Y-m-d H:i:s') + ]); + } + + public function service() + { + return $this->hasOne(StoreService::class, 'uid', 'uid') + ->where('mer_id', '<>', 0) + ->where('is_del', 0) + ->where('is_open', 1) + ->field('service_id,uid,nickname,avatar,customer,mer_id,is_verify,is_goods,is_open') + ->order('is_verify DESC,customer DESC'); + } + + public function topService() + { + return $this->hasOne(StoreService::class, 'uid', 'uid') + ->where('mer_id', 0)->field('service_id,uid,nickname,avatar,customer,mer_id,is_verify,is_goods')->where('is_del', 0) + ->order('is_verify DESC,customer DESC'); + } + + public function getLockBrokerageAttr() + { + return app()->make(UserBillRepository::class)->lockBrokerage($this->uid) ?: 0; + } + + public function getLockIntegralAttr() + { + return app()->make(UserBillRepository::class)->lockIntegral($this->uid) ?: 0; + } + + public function getYesterdayBrokerageAttr() + { + return app()->make(UserBillRepository::class)->yesterdayBrokerage($this->uid) ?: 0; + } + + public function getTotalExtractAttr() + { + return app()->make(UserExtractRepository::class)->userTotalExtract($this->uid) ?: 0; + } + + public function getTotalBrokerageAttr() + { + return app()->make(UserBillRepository::class)->totalBrokerage($this->uid) ?: 0; + } + + public function getTotalBrokeragePriceAttr() + { + return bcadd($this->lock_brokerage, $this->brokerage_price, 2); + } + + public function getTotalIntegralAttr() + { + return bcadd($this->lock_integral, $this->integral, 0); + } + + public function getTotalRechargeAttr() + { + return app()->make(UserBillRepository::class)->userNowMoneyIncTotal($this->uid); + } + + public function getTotalConsumeAttr() + { + return app()->make(StoreGroupOrderRepository::class)->totalNowMoney($this->uid); + } + + public function getTotalCollectProductAttr() + { + return app()->make(UserRelationRepository::class)->getWhereCount(['uid' => $this->uid, 'type' => 1]); + } + + public function getTotalCollectStoreAttr() + { + return app()->make(UserRelationRepository::class)->getWhereCount(['uid' => $this->uid, 'type' => 10]); + } + + public function getTotalVisitProductAttr() + { + return app()->make(UserHistoryRepository::class)->userTotalHistory($this->uid); + } + + public function getTotalCouponAttr() + { + return app()->make(StoreCouponUserRepository::class)->userTotal($this->uid, 0); + } + + public function getTotalUnreadAttr() + { + return app()->make(StoreServiceLogRepository::class)->totalUnReadNum($this->uid); + } + + public function getOneLevelCountAttr() + { + return app()->make(UserRepository::class)->getOneLevelCount($this->uid); + } + + public function getTwoLevelCountAttr() + { + return app()->make(UserRepository::class)->getTwoLevelCount($this->uid); + } + + public function getSpreadTotalAttr() + { + return $this->one_level_count + $this->two_level_count; + } + + public function wechat() + { + return $this->hasOne(WechatUser::class, 'wechat_user_id', 'wechat_user_id'); + } + + public function getIntegralAttr($val) + { + return is_null($val) ? 0 : $val; + } + + +// public function getUserTypeAttr() +// { +// if($this->wechat['openid']){ +// return 'wechat'; +// }elseif($this->wechat['routine_openid']){ +// return 'routine'; +// }else{ +// return 'H5'; +// } +// } + + public function getSubscribeAttr() + { + if ($this->wechat['openid'] && $this->wechat['subscribe']) { + return true; + } else { + return false; + } + } + +} diff --git a/app/common/model/user/UserAddress.php b/app/common/model/user/UserAddress.php new file mode 100644 index 00000000..dea970d0 --- /dev/null +++ b/app/common/model/user/UserAddress.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; +use app\common\repositories\store\CityAreaRepository; + +class UserAddress extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'address_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'user_address'; + } + + public function getAreaAttr() + { + return app()->make(CityAreaRepository::class)->search([])->whereIn('id', [$this->province_id, $this->city_id, $this->district_id, $this->street_id])->order('id ASC')->select(); + } +} diff --git a/app/common/model/user/UserBill.php b/app/common/model/user/UserBill.php new file mode 100644 index 00000000..cc5a7ca5 --- /dev/null +++ b/app/common/model/user/UserBill.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserBill extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'bill_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'user_bill'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + +} diff --git a/app/common/model/user/UserBrokerage.php b/app/common/model/user/UserBrokerage.php new file mode 100644 index 00000000..9e14c513 --- /dev/null +++ b/app/common/model/user/UserBrokerage.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserBrokerage extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'user_brokerage_id'; + } + + public static function tableName(): string + { + return 'user_brokerage'; + } + + public function getBrokerageRuleAttr($val) + { + return json_decode($val, true); + } + + public function setBrokerageRuleAttr($val) + { + return json_encode($val, JSON_UNESCAPED_UNICODE); + } + + public function getExtensionOneRateAttr() + { + return bcdiv((int)$this->extension_one, 100, 4); + } + + public function getExtensionTwoRateAttr() + { + return bcdiv((int)$this->extension_two, 100, 4); + } + +} diff --git a/app/common/model/user/UserExtract.php b/app/common/model/user/UserExtract.php new file mode 100644 index 00000000..dccd5782 --- /dev/null +++ b/app/common/model/user/UserExtract.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\user; + +use app\common\model\BaseModel; + +class UserExtract extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'extract_id'; + } + + public static function tableName(): string + { + return 'user_extract'; + } + + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } + + public function searchUidAttr($query, $value) + { + $query->where('uid',$value); + } + + public function searchExtractTypeAttr($query, $value) + { + $query->where('extract_type',$value); + } + + +} diff --git a/app/common/model/user/UserGroup.php b/app/common/model/user/UserGroup.php new file mode 100644 index 00000000..625ab573 --- /dev/null +++ b/app/common/model/user/UserGroup.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserGroup extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'group_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'user_group'; + } +} diff --git a/app/common/model/user/UserHistory.php b/app/common/model/user/UserHistory.php new file mode 100644 index 00000000..ea2eced9 --- /dev/null +++ b/app/common/model/user/UserHistory.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Spu; + +class UserHistory extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'user_history_id'; + } + + public static function tableName(): string + { + return 'user_history'; + } + + + public function getUpdateTimeAttr($value) + { + return date('Y-m-d H:i:s',$value); + } + + public function getStopTimeAttr() + { + if (!$this->spu) return ''; + if ($this->spu->product_type == 1 && $this->spu->seckillActive) { + $day = date('Y-m-d', time()); + $_day = strtotime($day); + $end_day = strtotime($this->spu->seckillActive['end_day']); + if ($end_day >= $_day) + return strtotime($day . $this->spu->seckillActive['end_time'] . ':00:00'); + if ($end_day < strtotime($day)) + return strtotime(date('Y-m-d', $end_day) . $this->spu->seckillActive['end_time'] . ':00:00'); + } + return ''; + } + + public function spu() + { + return $this->hasOne(Spu::class,'spu_id','res_id'); + } + + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + + public function searchHistoryIdAttr($query,$value) + { + $query->where('history_id',$value); + } + public function searchHistoryIdsAttr($query,$value) + { + $query->where('history_id','in',$value); + } +} diff --git a/app/common/model/user/UserLabel.php b/app/common/model/user/UserLabel.php new file mode 100644 index 00000000..6851c17f --- /dev/null +++ b/app/common/model/user/UserLabel.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserLabel extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'label_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'user_label'; + } +} diff --git a/app/common/model/user/UserMerchant.php b/app/common/model/user/UserMerchant.php new file mode 100644 index 00000000..7925ef48 --- /dev/null +++ b/app/common/model/user/UserMerchant.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +/** + * Class UserMerchant + * @package app\common\model\user + * @author xaboy + * @day 2020/10/20 + */ +class UserMerchant extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/10/20 + */ + public static function tablePk(): ?string + { + return 'user_merchant_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020/10/20 + */ + public static function tableName(): string + { + return 'user_merchant'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + /** + * @param $value + * @return array + * @author xaboy + * @day 2020-05-09 + */ + public function getLabelIdAttr($value) + { + return $value ? explode(',', $value) : []; + } + + /** + * @param $value + * @return string + * @author xaboy + * @day 2020-05-09 + */ + public function setLabelIdAttr($value) + { + return implode(',', $value); + } + + public function getAuthLabelAttr() + { + return app()->make(UserLabel::class)->whereIn('label_id', $this->label_id)->where('mer_id', $this->mer_id)->where('type', 1)->column('label_id'); + } +} diff --git a/app/common/model/user/UserOrder.php b/app/common/model/user/UserOrder.php new file mode 100644 index 00000000..7fec16b3 --- /dev/null +++ b/app/common/model/user/UserOrder.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserOrder extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'order_id'; + } + + public static function tableName(): string + { + return 'user_order'; + } + + public function user() + { + return $this->hasOne(User::class,'uid','uid'); + } +} diff --git a/app/common/model/user/UserReceipt.php b/app/common/model/user/UserReceipt.php new file mode 100644 index 00000000..5e58b7dd --- /dev/null +++ b/app/common/model/user/UserReceipt.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\user; + +use app\common\model\BaseModel; + +class UserReceipt extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'user_receipt_id'; + } + + public static function tableName(): string + { + return 'user_receipt'; + } + + + + /* + ------------------------------------------------------------------------------------------------------------ + | + | 搜索器 + ------------------------------------------------------------------------------------------------------------ + */ + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + + public function searchIsDelAttr($query,$value) + { + $query->where('is_del',$value); + } + + public function searchReceiptTypeAttr($query,$value) + { + $query->where('receipt_type',$value); + } + + public function searchReceiptTitleTypeAttr($query,$value) + { + $query->where('receipt_title_type',$value); + } + + public function searchIsDefaultAttr($query,$value) + { + $query->where('is_default',$value); + } + + public function searchUserReceiptIdAttr($query,$value) + { + $query->where('user_receipt_id',$value); + } +} diff --git a/app/common/model/user/UserRecharge.php b/app/common/model/user/UserRecharge.php new file mode 100644 index 00000000..507c0ea7 --- /dev/null +++ b/app/common/model/user/UserRecharge.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +/** + * Class UserRecharge + * @package app\common\model\user + * @author xaboy + * @day 2020/6/2 + */ +class UserRecharge extends BaseModel +{ + + /** + * @return string|null + * @author xaboy + * @day 2020/6/2 + */ + public static function tablePk(): ?string + { + return 'recharge_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020/6/2 + */ + public static function tableName(): string + { + return 'user_recharge'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function searchDateAttr($query,$value) + { + getModelTime($query, $value); + } + + public function getPayParams($return_url = '') + { + $params = [ + 'order_sn' => $this->order_id, + 'pay_price' => $this->price, + 'attach' => 'user_recharge', + 'body' => '用户充值' + ]; + if ($return_url) { + $params['return_url'] = $return_url; + } + return $params; + } +} diff --git a/app/common/model/user/UserRelation.php b/app/common/model/user/UserRelation.php new file mode 100644 index 00000000..be7b2930 --- /dev/null +++ b/app/common/model/user/UserRelation.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\user; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; +use app\common\model\store\product\Spu; +use app\common\model\system\merchant\Merchant; + +class UserRelation extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'uid'; + } + + public static function tableName(): string + { + return 'user_relation'; + } + + public function merchant() + { + return $this->hasOne(Merchant::class,'mer_id','type_id'); + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','type_id'); + } + + public function spu() + { + return $this->hasOne(Spu::class,'spu_id','type_id'); + } +} diff --git a/app/common/model/user/UserSign.php b/app/common/model/user/UserSign.php new file mode 100644 index 00000000..02b6b80d --- /dev/null +++ b/app/common/model/user/UserSign.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserSign extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'sign_id'; + } + + public static function tableName(): string + { + return 'user_sign'; + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } + + public function searchUidAttr($query,$value) + { + $query->where('uid',$value); + } + + public function searchDayAttr($query,$value) + { + $query->whereDay('create_time',$value); + } +} diff --git a/app/common/model/user/UserSpreadLog.php b/app/common/model/user/UserSpreadLog.php new file mode 100644 index 00000000..91d4dbd7 --- /dev/null +++ b/app/common/model/user/UserSpreadLog.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; + +class UserSpreadLog extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'user_spread_log_id'; + } + + public static function tableName(): string + { + return 'user_spread_log'; + } + + public function spread() + { + return $this->hasOne(User::class, 'uid', 'spread_uid'); + } +} diff --git a/app/common/model/user/UserVisit.php b/app/common/model/user/UserVisit.php new file mode 100644 index 00000000..b04715bc --- /dev/null +++ b/app/common/model/user/UserVisit.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\user; + + +use app\common\model\BaseModel; +use app\common\model\store\product\Product; + +class UserVisit extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'user_visit_id'; + } + + public static function tableName(): string + { + return 'user_visit'; + } + + public function product() + { + return $this->hasOne(Product::class,'product_id','type_id'); + } + + public function user() + { + return $this->hasOne(User::class, 'uid', 'uid'); + } +} diff --git a/app/common/model/wechat/RoutineQrcode.php b/app/common/model/wechat/RoutineQrcode.php new file mode 100644 index 00000000..7466aafc --- /dev/null +++ b/app/common/model/wechat/RoutineQrcode.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\wechat; + + +use app\common\model\BaseModel; + +class RoutineQrcode extends BaseModel +{ + + public static function tablePk(): ?string + { + return 'routine_qrcode_id'; + } + + public static function tableName(): string + { + return 'routine_qrcode'; + } +} diff --git a/app/common/model/wechat/TemplateMessage.php b/app/common/model/wechat/TemplateMessage.php new file mode 100644 index 00000000..962b945c --- /dev/null +++ b/app/common/model/wechat/TemplateMessage.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\model\wechat; + +use app\common\model\BaseModel; + +class TemplateMessage extends BaseModel +{ + + public static function tablePk(): string + { + return 'template_id'; + } + + + public static function tableName(): string + { + return 'template_message'; + } + +} diff --git a/app/common/model/wechat/WechatNews.php b/app/common/model/wechat/WechatNews.php new file mode 100644 index 00000000..2036f9ee --- /dev/null +++ b/app/common/model/wechat/WechatNews.php @@ -0,0 +1,81 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\wechat; + + +use app\common\model\article\Article; +use app\common\model\BaseModel; + +/** + * Class WechatReply + * @package app\common\model\wechat + * @author xaboy + * @day 2020-04-24 + */ +class WechatNews extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'wechat_news_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'wechat_news'; + } + + /** + * @param $val + * @return mixed + * @author xaboy + * @day 2020-04-24 + */ + public function getDataAttr($val) + { + return json_decode($val, true); + } + + /** + * @param $val + * @return false|string + * @author xaboy + * @day 2020-04-24 + */ + public function setDataAttr($val) + { + return json_encode($val); + } + + /** + * 一对多关联 + * @return \think\model\relation\BelongsTo + * @author Qinii + */ + public function article() + { + return $this->hasMany(Article::class ,'wechat_news_id','wechat_news_id') + ->field('article_id,title,author,image_input,synopsis,wechat_news_id'); + } +} diff --git a/app/common/model/wechat/WechatQrcode.php b/app/common/model/wechat/WechatQrcode.php new file mode 100644 index 00000000..1d2cb7b2 --- /dev/null +++ b/app/common/model/wechat/WechatQrcode.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\wechat; + + +use app\common\model\BaseModel; + +/** + * Class WechatQrcode + * @package app\common\model\wechat + * @author xaboy + * @day 2020-04-28 + */ +class WechatQrcode extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'wechat_qrcode_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'wechat_qrcode'; + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-28 + */ + public function incTicket() + { + return self::getDB()->where('wechat_qrcode_id', $this->wechat_qrcode_id)->inc('scan')->update(); + } +} diff --git a/app/common/model/wechat/WechatReply.php b/app/common/model/wechat/WechatReply.php new file mode 100644 index 00000000..cb31ab33 --- /dev/null +++ b/app/common/model/wechat/WechatReply.php @@ -0,0 +1,69 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\wechat; + + +use app\common\model\BaseModel; + +/** + * Class WechatReply + * @package app\common\model\wechat + * @author xaboy + * @day 2020-04-24 + */ +class WechatReply extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'wechat_reply_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'wechat_reply'; + } + + /** + * @param $val + * @return mixed + * @author xaboy + * @day 2020-04-24 + */ + public function getDataAttr($val) + { + return json_decode($val, true); + } + + /** + * @param $val + * @return false|string + * @author xaboy + * @day 2020-04-24 + */ + public function setDataAttr($val) + { + return json_encode($val); + } +} diff --git a/app/common/model/wechat/WechatUser.php b/app/common/model/wechat/WechatUser.php new file mode 100644 index 00000000..88623e3c --- /dev/null +++ b/app/common/model/wechat/WechatUser.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\model\wechat; + + +use app\common\model\BaseModel; + +class WechatUser extends BaseModel +{ + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tablePk(): string + { + return 'wechat_user_id'; + } + + /** + * @return string + * @author xaboy + * @day 2020-03-30 + */ + public static function tableName(): string + { + return 'wechat_user'; + } +} diff --git a/app/common/repositories/BaseRepository.php b/app/common/repositories/BaseRepository.php new file mode 100644 index 00000000..8f970df7 --- /dev/null +++ b/app/common/repositories/BaseRepository.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories; + +/** + * Class BaseRepository + * @package app\common\repositories + */ +class BaseRepository +{ + /** + * @var $dao + */ + protected $dao; + + public function setDao($dao){ + $this->dao = $dao; + } + + public function __call($name, $arguments) + { + return call_user_func_array([$this->dao, $name], $arguments); + } +} diff --git a/app/common/repositories/article/ArticleCategoryRepository.php b/app/common/repositories/article/ArticleCategoryRepository.php new file mode 100644 index 00000000..6a1e2f53 --- /dev/null +++ b/app/common/repositories/article/ArticleCategoryRepository.php @@ -0,0 +1,118 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\article; + + +use app\common\dao\article\ArticleCategoryDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; + +/** + * Class ArticleCategoryRepository + * @package app\common\repositories\article + * @author xaboy + * @day 2020-04-20 + * @mixin ArticleCategoryDao + */ +class ArticleCategoryRepository extends BaseRepository +{ + /** + * ArticleCategoryRepository constructor. + * @param ArticleCategoryDao $dao + */ + public function __construct(ArticleCategoryDao $dao) + { + $this->dao = $dao; + } + + /** + * @param int $merId + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-20 + */ + public function getFormatList($merId = 0,$status = null) + { + return formatCategory($this->dao->getAll($merId,$status)->toArray(), 'article_category_id'); + } + + + /** + * @return \think\Collection + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/9/18 + */ + public function apiGetArticleCategory() + { + return $this->dao->search(['status' => 1, 'pid' => 0])->select(); + } + + /** + * @param int $merId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function form(int $merId, ?int $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemArticleCategoryCreate')->build() : Route::buildUrl('systemArticleCategoryUpdate', ['id' => $id])->build()); + $form->setRule([ +// Elm::cascader('pid', '上级分类')->options(function () use ($id, $merId) { +// $menus = $this->dao->getAllOptions($merId); +// if ($id && isset($menus[$id])) unset($menus[$id]); +// $menus = formatCascaderData($menus, 'title'); +// array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); +// return $menus; +// })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]), + Elm::input('title', '分类名称')->required(), + Elm::input('info', '分类简介'), + Elm::frameImage('image', '分类图片', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=image&type=1')->width('896px')->height('480px')->props(['footer' => false])->modal(['modal' => false, 'custom-class' => 'suibian-modal']), + Elm::switches('status', '状态', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加文章配置' : '编辑文章分类')->formData($formData); + } + + /** + * @param int $merId + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function updateForm(int $merId, $id) + { + return $this->form($merId, $id, $this->dao->get($id, $merId)->toArray()); + } +} diff --git a/app/common/repositories/article/ArticleContentRepository.php b/app/common/repositories/article/ArticleContentRepository.php new file mode 100644 index 00000000..a9ea43d0 --- /dev/null +++ b/app/common/repositories/article/ArticleContentRepository.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\article; + + +use app\common\dao\article\ArticleContentDao; +use app\common\repositories\BaseRepository; + +class ArticleContentRepository extends BaseRepository +{ + public function __construct(ArticleContentDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/article/ArticleRepository.php b/app/common/repositories/article/ArticleRepository.php new file mode 100644 index 00000000..ef9a583a --- /dev/null +++ b/app/common/repositories/article/ArticleRepository.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\article; + + +use app\common\dao\article\ArticleDao; +use app\common\model\article\ArticleContent; +use app\common\repositories\BaseRepository; +use think\facade\Db; + +class ArticleRepository extends BaseRepository +{ + public function __construct(ArticleDao $dao) + { + $this->dao = $dao; + } + + public function getFormatList($merId = 0) + { + return $this->dao->getAll($merId)->toArray(); + } + + /** + * @param int $merId + * @param array $where + * @param $page + * @param $limit + * @return array + * @author Qinii + */ + public function search(int $merId, array $where, $page, $limit) + { + $where['wechat_news_id'] = 0; + $query = $this->dao->search($merId, $where)->order('create_time DESC'); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->hidden(['update_time'])->select(); + return compact('count', 'list'); + } + + /** + * 根据主键查询 + * @param int $merId + * @param int $id + * @param null $except + * @return bool + * @author Qinii + */ + public function merExists(int $merId, int $id, $except = null) + { + return $this->dao->merFieldExists($merId, $this->dao->getPk(), $id, $except); + } + + + public function merApiExists(int $id) + { + return $this->dao->getWhere([$this->dao->getPk() => $id,'status' => 1]); + } + + public function clearByNewId($newId) + { + Db::transaction(function()use($newId){ + $article_id = $this->dao->search(0,['wechat_news_id' => $newId])->column('article_id'); + foreach ($article_id as $item){ + $this->dao->delete($item,0); + } + }); + } +} diff --git a/app/common/repositories/community/CommunityCategoryRepository.php b/app/common/repositories/community/CommunityCategoryRepository.php new file mode 100644 index 00000000..aa1bb219 --- /dev/null +++ b/app/common/repositories/community/CommunityCategoryRepository.php @@ -0,0 +1,112 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\community; + +use app\common\dao\community\CommunityCategoryDao; +use app\common\repositories\BaseRepository; +use app\controller\api\community\CommunityTopic; + +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class CommunityCategoryRepository extends BaseRepository +{ + /** + * @var CommunityCategoryDao + */ + protected $dao; + + /** + * CommunityCategoryRepository constructor. + * @param CommunityCategoryDao $dao + */ + public function __construct(CommunityCategoryDao $dao) + { + $this->dao = $dao; + } + + public function form(?int $id) + { + $formData = []; + if (!$id) { + $form = Elm::createForm(Route::buildUrl('systemCommunityCategoryCreate')->build()); + } else { + $formData = $this->dao->get($id)->toArray(); + $form = Elm::createForm(Route::buildUrl('systemCommunityCategoryUpdate', ['id' => $id])->build()); + } + + $form->setRule([ + Elm::input('cate_name', '分类名称')->required(), + Elm::switches('is_show', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序')->precision(0)->max(99999), + ]); + return $form->setTitle(is_null($id) ? '添加分类' : '编辑分类')->formData($formData); + } + + public function delete(int $id) + { + $make = app()->make(CommunityTopicRepository::class); + if ( $make->getWhereCount(['category_id' => $id]) ) throw new ValidateException('该分类下存在数据'); + $this->dao->delete($id); + } + + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->order('sort DESC,category_id DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count','list'); + } + + public function options() + { + $data = $this->dao->getSearch(['is_show' => 1])->order('sort DESC,category_id DESC') + ->field('category_id as value,cate_name as label')->select(); + if ($data) $res = $data->toArray(); + return $res; + } + + + public function getApiList() + { + $res = $this->dao->getSearch(['is_show' => 1])->order('sort DESC') + ->setOption('filed',[])->field('category_id,cate_name')->with(['children'])->order('sort DESC,category_id DESC')->select(); + $list = []; + if ($res) $list = $res->toArray(); +// $hot = app()->make(CommunityTopicRepository::class)->getHotList(); +// $data[] = [ +// 'category_id' => 0, +// "cate_name" => "推荐", +// "children" => $hot['list'] +// ]; +// return array_merge($data,$list); + return $list; + } + + public function checkName($name, $id) + { + $this->dao->fieldExists(); + $this->dao->getSearch(['cate_name' => $name]); + if ($id) { + $this->dao->getSearch(['cate_name' => $name])->where('categ'); + } + } + + public function clearCahe() + { + // CacheService::clearByTag(0, CacheService::TAG_TOPIC); + } +} + diff --git a/app/common/repositories/community/CommunityReplyRepository.php b/app/common/repositories/community/CommunityReplyRepository.php new file mode 100644 index 00000000..947845e0 --- /dev/null +++ b/app/common/repositories/community/CommunityReplyRepository.php @@ -0,0 +1,204 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\community; + +use app\common\dao\community\CommunityReplyDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\RelevanceRepository; +use Carbon\Exceptions\InvalidDateException; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +class CommunityReplyRepository extends BaseRepository +{ + /** + * @var CommunityReplyDao + */ + protected $dao; + + /** + * CommunityReplyRepository constructor. + * @param CommunityReplyDao $dao + */ + public function __construct(CommunityReplyDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->search($where)->with([ + 'community' => function ($query) { + $query->field('community_id,title'); + }, + 'author' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'reply' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'hasReply' => function ($query) { + $query->field('pid, reply_id, status'); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + + public function getApiList(array $where, int $page, int $limit, $userInfo) + { + $make = app()->make(CommunityRepository::class); + + $where_['community_id'] = $where['community_id']; + $where_ = CommunityRepository::IS_SHOW_WHERE; + + if ($userInfo && $make->uidExists((int)$where['community_id'], $userInfo->uid)) { + $where_ = ['is_del' => 0]; + } + + $where_['community_id'] = $where['community_id']; + + if (!$make->getWhereCount($where_)) throw new ValidateException('内容不存在,可能被删删除了哦~'); + + $where['status'] = 1; + $all = $this->dao->getSearch($where)->count(); + $start = $this->dao->getSearch($where)->sum('count_start'); + $where['pid'] = 0; + + $query = $this->dao->getSearch($where) + ->order('create_time DESC') + ->hidden(['refusal']) + ->with([ + 'author' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'is_start' => function ($query) use ($userInfo) { + $query->where('left_id', $userInfo->uid ?? null); + }, + 'children' => [ + 'author' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'reply' => function ($query) { + $query->field('uid,nickname,avatar')->order('create_time ASC'); + }, + 'is_start' => function ($query) use ($userInfo) { + $query->where('left_id', $userInfo->uid ?? null); + } + ], + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('all', 'start', 'count', 'list'); + } + + + /** + * TODO 发表评论 + * @param int $replyId + * @param array $data + * @author Qinii + * @day 10/29/21 + */ + public function create(int $replyId, array $data) + { + $make = app()->make(CommunityRepository::class); + + if (!$make->exists($data['community_id'])) + throw new ValidateException('内容不存在,可能已被删除了哦~'); + + $data['pid'] = $replyId; + if ($replyId) { + $get = $this->dao->get($replyId); + if (!$get) throw new ValidateException('您回复的评论不存在'); + if ($get->pid) { + $data['re_uid'] = $get->uid; + $data['pid'] = $get->pid; + } + } + + $res = Db::transaction(function () use ($replyId, $data, $make) { + $res = $this->dao->create($data); + if ($replyId) $this->dao->incField($data['pid'], 'count_reply', 1); + return $res; + }); + + $ret = $this->dao->getWhere(['reply_id' => $res->reply_id], '*', [ + 'author' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'reply' => function ($query) { + $query->field('uid,nickname,avatar')->order('create_time ASC'); + }, + ]); + return $ret; + } + + public function delete($id) + { + Db::transaction(function () use ($id) { + $get = $this->dao->get($id); + $make = app()->make(CommunityRepository::class); + if ($get->pid) $this->dao->decField($get['pid'], 'count_reply', 1); + $make->decField($get['community_id'], 'count_reply', 1); + $get->delete(); + }); + } + + + public function setStart(int $id, int $uid, int $status) + { + $make = app()->make(RelevanceRepository::class); + $check = $make->checkHas($uid, $id, RelevanceRepository::TYPE_COMMUNITY_REPLY_START); + if ($status) { + if ($check) throw new ValidateException('您已经赞过过他了~'); + $make->create($uid, $id, RelevanceRepository::TYPE_COMMUNITY_REPLY_START, true); + $this->dao->incField($id, 'count_start', 1); + } else { + if (!$check) throw new ValidateException('您还未赞过他哦~'); + $make->destory($uid, $id, RelevanceRepository::TYPE_COMMUNITY_REPLY_START); + $this->dao->decField($id, 'count_start', 1); + } + return; + } + + + public function statusForm(int $id) + { + $formData = $this->dao->get($id)->toArray(); + + if ($formData['status'] !== 0) throw new ValidateException('请勿重复审核'); + $form = Elm::createForm(Route::buildUrl('systemCommunityReplyStatus', ['id' => $id])->build()); + + $form->setRule([ + Elm::textarea('content', '评论内容')->disabled(true), + + Elm::radio('status', '审核状态', 1)->options([ + ['value' => -1, 'label' => '未通过'], + ['value' => 1, 'label' => '通过']] + )->control([ + ['value' => -1, 'rule' => [ + Elm::textarea('refusal', '未通过原因', '')->required() + ]] + ]), + ]); + $formData['status'] = 1; + return $form->setTitle('审核评论')->formData($formData); + } +} diff --git a/app/common/repositories/community/CommunityRepository.php b/app/common/repositories/community/CommunityRepository.php new file mode 100644 index 00000000..18456de9 --- /dev/null +++ b/app/common/repositories/community/CommunityRepository.php @@ -0,0 +1,510 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\community; + +use app\common\dao\community\CommunityDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\RelevanceRepository; +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserRepository; +use crmeb\services\QrcodeService; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +class CommunityRepository extends BaseRepository +{ + /** + * @var CommunityDao + */ + protected $dao; + + const IS_SHOW_WHERE = [ + 'is_show' => 1, + 'status' => 1, + 'is_del' => 0, + ]; + + public const COMMUNIT_TYPE_FONT = '1'; + public const COMMUNIT_TYPE_VIDEO = '2'; + + /** + * CommunityRepository constructor. + * @param CommunityDao $dao + */ + public function __construct(CommunityDao $dao) + { + $this->dao = $dao; + } + + public function title(array $where) + { + $where['is_type'] = self::COMMUNIT_TYPE_FONT; + $list[] = [ + 'count' => $this->dao->search($where)->count(), + 'title' => '图文列表', + 'type' => self::COMMUNIT_TYPE_FONT, + ]; + $where['is_type'] = self::COMMUNIT_TYPE_VIDEO; + $list[] = [ + 'count' => $this->dao->search($where)->count(), + 'title' => '短视频列表', + 'type' => self::COMMUNIT_TYPE_VIDEO, + ]; + return $list; + } + + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->search($where)->with([ + 'author' => function($query) { + $query->field('uid,real_name,status,avatar,nickname,count_start'); + }, + 'topic' => function($query) { + $query->where('status', 1)->where('is_del',0); + $query->field('topic_id,topic_name,status,category_id,pic,is_del'); + }, + 'category' + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + + public function getApiList(array $where, int $page, int $limit, $userInfo) + { + $config = systemConfig("community_app_switch"); + if (!isset($where['is_type']) && $config) $where['is_type'] = $config; + $where['is_del'] = 0; + + $query = $this->dao->search($where)->order('start DESC,Community.create_time DESC,community_id DESC'); + $query->with([ + 'author' => function($query) use($userInfo){ + $query->field('uid,real_name,status,avatar,nickname,count_start'); + }, + 'is_start' => function($query) use ($userInfo) { + $query->where('left_id',$userInfo->uid ?? null); + }, + 'topic' => function($query) { + $query->where('status', 1)->where('is_del',0); + $query->field('topic_id,topic_name,status,category_id,pic,is_del'); + }, + 'relevance' => [ + 'spu' => function($query) { + $query->field('spu_id,store_name,image,price,product_type,activity_id,product_id'); + } + ], + 'is_fans' => function($query) use($userInfo){ + $query->where('left_id',$userInfo->uid?? 0); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[]) + ->field('community_id,title,image,topic_id,Community.count_start,count_reply,start,Community.create_time,Community.uid,Community.status,is_show,content,video_link,is_type,refusal') + ->select()->append(['time']); + if ($list) $list = $list->toArray(); + return compact('count','list'); + } + + public function getFirtVideo($where,$page, $userInfo) + { + $with =[]; + if ($page == 1) { + $with = [ + 'author' => function($query) { + $query->field('uid,real_name,status,avatar,nickname,count_start'); + }, + 'is_start' => function($query) use ($userInfo) { + $query->where('left_id',$userInfo->uid ?? null); + }, + 'topic' => function($query) { + $query->where('status', 1)->where('is_del',0); + $query->field('topic_id,topic_name,status,category_id,pic,is_del'); + }, + 'relevance' => [ + 'spu' => function($query) { + $query->field('spu_id,store_name,image,price,product_type,activity_id,product_id,status'); + } + ], + 'is_fans' => function($query) use($userInfo){ + $query->where('left_id',$userInfo->uid?? 0); + } + ]; + } + return $this->dao->getSearch($where)->with($with)->field('community_id,image,title,topic_id,count_start,count_reply,start,create_time,uid,status,is_show,content,video_link,is_type,refusal')->find(); + } + + public function getApiVideoList(array $where, int $page, int $limit, $userInfo, $type = 0) + { + $where['is_type'] = self::COMMUNIT_TYPE_VIDEO; + $first = $this->getFirtVideo($where,$page, $userInfo); + if ($type) { // 点赞过的内容 + $where['uid'] = $userInfo->uid; + $where['community_ids'] = $this->dao->joinUser($where)->column('community_id'); + } else { // 条件视频 + if (!isset($where['uid']) && $first) $where['topic_id'] = $first['topic_id']; + } + $where['not_id'] = $where['community_id']; + unset($where['community_id']); + $data = $this->getApiList($where, $page, $limit, $userInfo); + if (empty($data['list']) && isset($where['topic_id'])) { + unset($where['topic_id']); + $data = $this->getApiList($where, $page, $limit, $userInfo); + } + if ($page == 1 && $first) { + array_unshift($data['list'],$first->toArray()); + } + return $data; + } + + /** + * TODO 后台详情 + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 10/28/21 + */ + public function detail(int $id) + { + $where = [ + $this->dao->getPk() => $id, + 'is_del' => 0 + ]; + $config = systemConfig("community_app_switch"); + if ($config) $where['is_type'] = $config; + return $this->dao->getSearch($where)->with([ + 'author' => function($query) { + $query->field('uid,real_name,status,avatar,nickname,count_start'); + }, + 'topic', + 'category', + 'relevance.spu' + ])->find(); + } + + /** + * TODO 移动端详情展示 + * @param int $id + * @param $user + * @return array|\think\Model|null + * @author Qinii + * @day 10/27/21 + */ + + public function show(int $id, $user) + { + $where = self::IS_SHOW_WHERE; + $is_author = 0; + if ($user && $this->dao->uidExists($id, $user->uid)) { + $where = ['is_del' => 0]; + $is_author = 1; + } + $config = systemConfig("community_app_switch"); + if ($config) $where['is_type'] = $config; + $where[$this->dao->getPk()] = $id; + $data = $this->dao->getSearch($where) + ->with([ + 'author' => function ($query) { + $query->field('uid,real_name,status,avatar,nickname,count_start,member_level'); + if (systemConfig('member_status')) $query->with(['member' => function ($query) { + $query->field('brokerage_icon,brokerage_level'); + }]); + }, + 'relevance' => [ + 'spu' => function ($query) { + $query->field('spu_id,store_name,image,price,product_type,activity_id,product_id'); + } + ], + 'topic' => function ($query) { + $query->where('status', 1)->where('is_del', 0); + $query->field('topic_id,topic_name,status,category_id,pic,is_del'); + }, + 'is_start' => function ($query) use ($user) { + $query->where('left_id', $user->uid ?? ''); + }, + ])->hidden(['is_del'])->find(); + + if (!$data) throw new ValidateException('内容不存在,可能已被删除了哦~'); + + $data['is_author'] = $is_author; + $is_fans = 0; + if ($user && !$data['is_author']) + $is_fans = app()->make(RelevanceRepository::class)->getWhereCount([ + 'left_id' => $user->uid, + 'right_id' => $data['uid'], + 'type' => RelevanceRepository::TYPE_COMMUNITY_FANS, + ]); + $data['is_fans'] = $is_fans; + return $data; + } + + public function getSpuByOrder($id, $uid) + { + $where = app()->make(StoreOrderProductRepository::class)->selectWhere(['order_id' => $id]); + if (!$where) throw new ValidateException('商品已下架'); + + $make = app()->make(SpuRepository::class); + foreach ($where as $item) { + switch ($item['product_type']){ + case 0: + $sid = $item['product_id']; + // nobreak; + case 1: + $sid = $item['product_id']; + break; + case 2: + $sid = $item['activity_id']; + break; + case 3: + $sid = $item['cart_info']['productAssistSet']['product_assist_id']; + break; + case 4: + $sid = $item['cart_info']['product']['productGroup']['product_group_id']; + break; + default: + $sid = $item['product_id']; + break; + + } + $data[] = $make->getSpuData($sid, $item['product_type'],0); + } + return $data; + } + + /** + * TODO 创建 + * @param array $data + * @author Qinii + * @day 10/29/21 + */ + public function create(array $data) + { + event('community.create.before',compact('data')); + if ($data['topic_id']) { + $getTopic = app()->make(CommunityTopicRepository::class)->get($data['topic_id']); + if (!$getTopic || !$getTopic->status) throw new ValidateException('话题不存在或已关闭'); + $data['category_id'] = $getTopic->category_id; + } + return Db::transaction(function () use($data) { + $community = $this->dao->create($data); + if ($data['spu_id'])$this->joinProduct($community->community_id,$data['spu_id']); + event('community.create',compact('community')); + return $community->community_id; + }); + } + + /** + * TODO 编辑 + * @param int $id + * @param array $data + * @author Qinii + * @day 10/29/21 + */ + public function edit(int $id, array $data) + { + event('community.update.before',compact('id','data')); + if ($data['topic_id']) { + $getTopic = app()->make(CommunityTopicRepository::class)->get($data['topic_id']); + + if (!$getTopic || !$getTopic->status) throw new ValidateException('话题不存在或已关闭'); + $data['category_id'] = $getTopic->category_id; + } + + Db::transaction(function () use($id, $data) { + $spuId = $data['spu_id']; + unset($data['spu_id']); + $community = $this->dao->update($id, $data); + if ($spuId) $this->joinProduct($id, $spuId); + event('community.update.before',compact('id','community')); + }); + } + + public function joinProduct($id, array $data) + { + $make = app()->make(RelevanceRepository::class); + $data = array_unique($data); + $res = []; + foreach ($data as $value) { + if ($value) { + $res[] = [ + 'left_id' => $id, + 'right_id' => $value, + 'type' => RelevanceRepository::TYPE_COMMUNITY_PRODUCT + ]; + } + } + $make->clear($id,RelevanceRepository::TYPE_COMMUNITY_PRODUCT,'left_id'); + if($res) $make->insertAll($res); + } + + /** + * TODO 获取某用户信息 + * @param int $uid + * @param null $self + * @return mixed + * @author Qinii + * @day 10/29/21 + */ + public function getUserInfo(int $uid, $self = null) + { + $relevanceRepository = app()->make(RelevanceRepository::class); + $data['focus'] = $relevanceRepository->getFieldCount('left_id', $uid,RelevanceRepository::TYPE_COMMUNITY_FANS); + + + $is_start = $is_self = false; + if ($self && $self->uid == $uid) { + $user = $self; + $is_self = true; + } else { + $user = app()->make(UserRepository::class)->get($uid); + $is_start = $relevanceRepository->checkHas($self->uid, $uid, RelevanceRepository::TYPE_COMMUNITY_FANS) > 0; + } + $data['start'] = $user->count_start; + $data['uid'] = $user->uid; + $data['avatar'] = $user->avatar; + $data['nickname'] = $user->nickname; + $data['is_start'] = $is_start; + $data['member_icon'] = systemConfig('member_status') ? ($user->member->brokerage_icon ?? '') : ''; + $data['is_self'] = $is_self; + $data['fans'] = $user->count_fans; + + return $data; + } + + public function setFocus(int $id, int $uid,int $status) + { + $make = app()->make(RelevanceRepository::class); + $check = $make->checkHas($uid, $id, RelevanceRepository::TYPE_COMMUNITY_FANS); + if ($status) { + if ($check) throw new ValidateException('您已经关注过他了~'); + $make->create($uid, $id,RelevanceRepository::TYPE_COMMUNITY_FANS,true); + app()->make(UserRepository::class)->incField($id, 'count_fans', 1); + } else { + if (!$check) throw new ValidateException('您还未关注他哦~'); + $make->destory($uid, $id,RelevanceRepository::TYPE_COMMUNITY_FANS); + app()->make(UserRepository::class)->decField($id, 'count_fans', 1); + } + return ; + } + + public function form($id) + { + $form = Elm::createForm(Route::buildUrl('systemCommunityUpdate', ['id' => $id])->build()); + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $formData = $data->toArray(); + + return $form->setRule([ + Elm::rate('start', '排序星级')->max(5) + ])->setTitle('编辑星级')->formData($formData); + } + + public function showForm($id) + { + $form = Elm::createForm(Route::buildUrl('systemCommunityStatus', ['id' => $id])->build()); + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $formData = $data->toArray(); + return $form->setRule([ + Elm::radio('status', '强制下架')->options([ + ['value' => -2, 'label' => '下架'], ['value' => 1, 'label' => '上架']])->control([ + ['value' => -2, 'rule' => [ + Elm::textarea('refusal', '下架理由', '信息存在违规')->required() + ]] + ]), + ])->setTitle('强制下架')->formData($formData); + } + + public function setCommunityStart(int $id, $userInfo, int $status) + { + $make = app()->make(RelevanceRepository::class); + $userRepository = app()->make(UserRepository::class); + + if ($status) { + $res = $make->create($userInfo->uid, $id, RelevanceRepository::TYPE_COMMUNITY_START,true); + if (!$res) throw new ValidateException('您已经点赞过了'); + + $ret = $this->dao->get($id); + $user = $userRepository->get($ret['uid']); + $this->dao->incField($id,'count_start',1); + if ($user) $userRepository->incField((int)$user->uid,'count_start',1); + } + if (!$status) { + if (!$make->checkHas($userInfo->uid, $id, RelevanceRepository::TYPE_COMMUNITY_START)) + throw new ValidateException('您还没有点赞呢~'); + $make->destory($userInfo->uid, $id, RelevanceRepository::TYPE_COMMUNITY_START); + + $ret = $this->dao->get($id); + $user = $userRepository->get($ret['uid']); + $this->dao->decField($id,'count_start',1); + if ($user) $userRepository->decField((int)$user->uid, 'count_start',1); + } + } + + public function setStatus($id, $data) + { + $ret = $this->dao->get($id); + event('community.status.before',compact('id','data')); + Db::transaction(function () use($ret,$id, $data) { + + if ($data['status'] == 1) { + $make = app()->make(UserBrokerageRepository::class); + $make->incMemberValue($ret['uid'], 'member_community_num', $id); + } + $data['status_time'] = date('Y-m-d H:i;s', time()); + $this->dao->update($id, $data); + event('community.status',compact('id')); + }); + + } + + public function destory($id, $user = null) + { + event('community.delete.before',compact('id','user')); + $this->dao->update($id, ['is_del' => 1]); + event('community.delete',compact('id', 'user')); + } + + public function getDataBySpu($spuId) + { + $where = array_merge(['spu_id' => $spuId], self::IS_SHOW_WHERE); + return $this->dao->getSearch($where) + ->order('create_time DESC') + ->field('community_id,title,image,is_type') + ->limit(3)->select(); + } + + public function qrcode($id, $type,$user) + { + $res = $this->dao->search(['is_type' => self::COMMUNIT_TYPE_VIDEO,'community_id' => $id, 'status' => 1, 'is_show' => 1])->find(); + if (!$res) return false; + $make = app()->make(QrcodeService::class); + if ($type == 'routine') { + $name = md5('rcwx' . $id . $type . $user->uid . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $params = 'id=' . $id . '&spid=' . $user['uid']; + $link = 'pages/short_video/nvueSwiper/index'; + return $make->getRoutineQrcodePath($name, $link, $params); + } else { + $name = md5('cwx' . $id . $type . $user->uid . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $link = 'pages/short_video/nvueSwiper/index'; + $link = $link . '?id=' . $id . '&spid=' . $user['uid']; + $key = 'com' . $type . '_' . $id . '_' . $user['uid']; + return $make->getWechatQrcodePath($name, $link, false, $key); + } + } +} + diff --git a/app/common/repositories/community/CommunityTopicRepository.php b/app/common/repositories/community/CommunityTopicRepository.php new file mode 100644 index 00000000..7d66a4b6 --- /dev/null +++ b/app/common/repositories/community/CommunityTopicRepository.php @@ -0,0 +1,129 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\community; + +use app\common\dao\community\CommunityTopicDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class CommunityTopicRepository extends BaseRepository +{ + /** + * @var CommunityTopicDao + */ + protected $dao; + + /** + * CommunityTopicRepository constructor. + * @param CommunityTopicDao $dao + */ + public function __construct(CommunityTopicDao $dao) + { + $this->dao = $dao; + } + + public function form(?int $id) + { + $formData = []; + if (!$id) { + $form = Elm::createForm(Route::buildUrl('systemCommunityTopicCreate')->build()); + } else { + $formData = $this->dao->get($id)->toArray(); + $form = Elm::createForm(Route::buildUrl('systemCommunityTopicUpdate', ['id' => $id])->build()); + } + + $form->setRule([ + Elm::select('category_id', '社区分类')->options(function () { + return app()->make(CommunityCategoryRepository::class)->options(); + })->requiredNum(), + + Elm::frameImage('pic', '图标', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=pic&type=1') + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::input('topic_name', '社区话题')->required(), + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::switches('is_hot', '是否推荐', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序')->precision(0)->max(99999), + ]); + return $form->setTitle(is_null($id) ? '添加话题' : '编辑话题')->formData($formData); + } + + public function delete(int $id) + { + $make = app()->make(CommunityRepository::class); + if ( $make->getWhereCount(CommunityRepository::IS_SHOW_WHERE) ) throw new ValidateException('该话题下存在数据'); + $this->dao->delete($id); + } + + public function getList(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->getSearch($where)->with(['category']) + ->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count','list'); + } + + /** + * TODO 获取推荐的话题 + * @return array + * @author Qinii + * @day 10/27/21 + */ + public function getHotList() + { + $list = $this->dao->getSearch([ + 'is_hot' => 1, + 'status' => 1, + 'is_del' => 0 + ]) + ->setOption('field',[])->field('category_id,topic_name,topic_id,pic,count_view,count_use') + ->order('create_time DESC')->select(); + + return compact('list'); + } + + /** + * TODO + * @param int|null $id + * @author Qinii + * @day 11/3/21 + */ + public function sumCountUse(?int $id) + { + if (!$id) { + $id = $this->dao->getSearch(['status' => 1,'is_del' =>0])->column('topic_id'); + } else { + $id = [$id]; + } + foreach ($id as $item) { + $count = app()->make(CommunityRepository::class) + ->getSearch(CommunityRepository::IS_SHOW_WHERE)->where('topic_id',$item)->count(); + $this->dao->update($item, ['count_use' => $count]); + } + } + + public function options() + { + $data = $this->dao->getSearch(['status' => 1,'is_del' =>0])->order('sort DESC,create_time DESC') + ->field('topic_id as value,topic_name as label')->select(); + if ($data) $res = $data->toArray(); + return $res; + } +} + diff --git a/app/common/repositories/delivery/DeliveryOrderRepository.php b/app/common/repositories/delivery/DeliveryOrderRepository.php new file mode 100644 index 00000000..d97740f8 --- /dev/null +++ b/app/common/repositories/delivery/DeliveryOrderRepository.php @@ -0,0 +1,508 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\delivery; + +use app\common\dao\delivery\DeliveryOrderDao; +use app\common\model\delivery\DeliveryStation; +use app\common\model\store\order\StoreOrder; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\common\repositories\user\UserRepository; +use crmeb\services\DeliverySevices; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Log; +use think\facade\Route; + +class DeliveryOrderRepository extends BaseRepository +{ + + protected $statusData = [ + 2 => '待取货', + 3 => '配送中', + 4 => '已完成', + -1 => '已取消', + 9 => '物品返回中', + 10 => '物品返回完成', + 100 => '骑士到店', + ]; + + protected $message = [ + 2 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_WAITING, + 3 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_ING, + 4 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_OVER, + -1 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_CANCEL, + 9 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_REFUNDING, + 10 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_REFUND, + 100 => StoreOrderStatusRepository::ORDER_DELIVERY_CITY_ARRIVE, + ]; + + public function __construct(DeliveryOrderDao $dao) + { + $this->dao = $dao; + } + + public function merList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with(['station','storeOrder'])->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + public function sysList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with([ + 'merchant' => function($query) { + $query->field('mer_id,mer_name'); + }, + 'station', + 'storeOrder'=> function($query) { + $query->field('order_id,order_sn'); + }, + ])->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + public function detail(int $id, ?int $merId) + { + $where[$this->dao->getPk()] = $id; + if ($merId) $where['mer_id'] = $merId; + $res = $this->dao->getSearch($where)->with([ + 'merchant' => function($query) { + $query->field('mer_id,mer_name'); + }, + 'station', + ])->find(); + $order = DeliverySevices::create($res['station_type'])->getOrderDetail($res); + $res['data'] = [ + 'order_code' => $order['order_code'], + 'to_address' => $order['to_address'], + 'from_address' => $order['from_address'], + 'state' => $order['state'], + 'note' => $order['note'], + 'order_price' => $order['order_price'], + 'distance' => round(($order['distance'] / 1000),2) . ' km', + ]; + if (!$res) throw new ValidateException('订单不存在'); + return $res; + } + + public function cancelForm($id) + { + $formData = $this->dao->get($id); + if (!$formData) throw new ValidateException('订单不存在'); + if ($formData['status'] == -1) throw new ValidateException('订单已取消,无法操作'); + + $form = Elm::createForm(Route::buildUrl('merchantStoreDeliveryOrderCancel',['id' => $id])->build()); + $rule = []; + if ($formData['station_type'] == DeliverySevices::DELIVERY_TYPE_DADA){ + $options = DeliverySevices::create(DeliverySevices::DELIVERY_TYPE_DADA)->reasons(); + $rule[] = Elm::select('reason', '取消原因')->options($options); + $rule[] = Elm::text('cancel_reason', '其他原因说明'); + } + if ($formData['station_type'] == DeliverySevices::DELIVERY_TYPE_UU){ + $rule[] = Elm::input('reason', '取消原因')->required(1); + } + $form->setRule($rule); + return $form->setTitle('取消同城配送订单',$formData); + } + + public function cancel($id, $merId, $reason) + { + $order = $this->dao->getWhere([$this->dao->getPk() => $id, 'mer_id' => $merId]); + if (!$order) throw new ValidateException('配送订单不存在'); + if ($order['status'] == -1) throw new ValidateException('请勿重复操作'); + $data = [ + 'origin_id' => $order['order_sn'], + 'order_code'=> $order['order_code'], + 'reason' => $reason['reason'], + 'cancel_reason' => $reason['cancel_reason'], + ]; + return Db::transaction(function () use($order, $data){ + $mark = $data['reason']; + if ($order['station_type'] == DeliverySevices::DELIVERY_TYPE_DADA) { + $options = DeliverySevices::create(DeliverySevices::DELIVERY_TYPE_DADA)->reasons(); + $mark = $options[$data['reason']]; + } + if ($data['cancel_reason']) $mark .= ','.$data['cancel_reason']; + $res = DeliverySevices::create($order['station_type'])->cancelOrder($data); + $deduct_fee = $res['deduct_fee'] ?? 0; + $this->cancelAfter($order, $deduct_fee, $mark); + //订单记录 + $statusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '同城配送订单已取消', + 'change_type' => $statusRepository::ORDER_DELIVERY_CITY_CANCEL, + ]; + $statusRepository->createAdminLog($orderStatus); + }); + } + + public function cancelAfter($deliveryOrder, $deductFee, $mark) + { + //修改配送订单 + $deliveryOrder->status = -1; + $deliveryOrder->reason = $mark; + $deliveryOrder->deduct_fee = $deductFee; + $deliveryOrder->save(); + + //修改商城订单 + $res = app()->make(StoreOrderRepository::class)->get($deliveryOrder['order_id']); + $res->status = 0; + $res->delivery_type = 0; + $res->delivery_name = ''; + $res->delivery_id = ''; + $res->save(); + + //修改商户 + $merchant = app()->make(MerchantRepository::class)->get($deliveryOrder['mer_id']); + $balance = bcadd(bcsub($deliveryOrder['fee'], $deductFee, 2), $merchant->delivery_balance, 2); + $merchant->delivery_balance = $balance; + $merchant->save(); + } + + + + + /** + * TODO 回调 + * @param $data + * @author Qinii + * @day 2/17/22 + */ + public function notify($data) + { + //达达 + /** + * 订单状态(待接单=1,待取货=2,配送中=3,已完成=4,已取消=5, 指派单=8,妥投异常之物品返回中=9, 妥投异常之物品返回完成=10, 骑士到店=100,创建达达运单失败=1000 可参考文末的状态说明) + */ + Log::info('同城回调参数:'.var_export(['=======',$data,'======='],1)); + if (isset($data['data'])) { + $data = json_decode($data['data'], 1); + } + + $reason = ''; + $deductFee = 0; + $delivery = []; + if (isset($data['order_status'])){ + $order_sn = $data['order_id']; + if ($data['order_status'] == 1) { + $orderData = $this->dao->getSearch(['sn' => $data['order_id']])->find(); + if (!$orderData['finish_code']) { + $orderData->finish_code = $data['finish_code']; + $orderData->save(); + } + return ; + } else if (in_array( $data['order_status'],[2,3,4,5,9,10,100])){ + $status = $data['order_status']; + if ($data['order_status'] == 5){ + $msg = [ + '取消:', + '达达配送员取消:', + '商家主动取消:', + '系统或客服取消:', + ]; + //1:达达配送员取消;2:商家主动取消;3:系统或客服取消;0:默认值 + $status = -1; + $reason = $msg[$data['cancel_from']].$data['cancel_reason']; + } + $deductFee = $data['deductFee'] ?? 0; + if (isset($data['dm_name']) && $data['dm_name']) { + $delivery = [ + 'delivery_name' => $data['dm_name'], + 'delivery_id' => $data['dm_mobile'], + ]; + } + + } + } else if (isset($data['state'])){ //uu + if (!$data['origin_id']) $deliveryOrder = $this->dao->getWhere(['order_code' => $data['order_code']]); + $order_sn = $data['origin_id'] ?: $deliveryOrder['order_sn'] ; + //当前状态 1下单成功 3跑男抢单 4已到达 5已取件 6到达目的地 10收件人已收货 -1订单取消 + switch ($data['state']) { + case 3: + $status = 2; + break; + case 4: + $status = 100; + break; + case 5: + $status = 3; + break; + case 10: + $status = 4; + break; + case -1: + $status = -1; + $reason = $data['state_text']; + break; + default: + break; + } + if (isset($data['driver_name']) && $data['driver_name']) { + $delivery = [ + 'delivery_name' => $data['driver_name'], + 'delivery_id' => $data['driver_mobile'], + ]; + } + } + + if (isset($order_sn) && isset($status)){ + $res = $this->dao->getWhere(['order_sn' => $order_sn]); + if ($res) { + $this->notifyAfter($status, $reason, $res, $delivery, $deductFee); + }else { + Log::info('同城配送回调,未查询到订单:'.$order_sn); + } + } + } + + + + + public function notifyAfter($status, $reason, $res, $data, $deductFee) + { + if (!isset($this->statusData[$status])) return ; + + $make = app()->make(StoreOrderRepository::class); + $orderData = $make->get($res['order_id']); + + if ($orderData['status'] != $status ) { + $res->status = $status; + $res->reason = $reason; + $res->save(); + //订单记录 + $statusRepository = app()->make(StoreOrderStatusRepository::class); + $message = '订单同城配送【'. $this->statusData[$status].'】'; + $orderStatus = [ + 'order_id' => $orderData['order_id'], + 'order_sn' => $orderData['order_sn'], + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => $message, + 'change_type' => $this->message[$status], + ]; + $statusRepository->createSysLog($orderStatus); + if ($status == 2 && !empty($data)) + $make->update($res['order_id'],$data); + if ($status == 4){ + $order = $make->get($res['order_id']); + $user = app()->make(UserRepository::class)->get($order['uid']); + $make->update($res['order_id'],['status' => 2]); + $make->takeAfter($order, $user); + } + if ($status == -1) + $this->cancelAfter($res, $deductFee , $reason); + } + } + + + + public function create($id, $merId, $data, $order) + { + $type = systemConfig('delivery_type'); + $callback_url = rtrim(systemConfig('site_url'), '/') . '/api/notice/callback'; + $where = ['station_id' => $data['station_id'], 'mer_id' => $merId, 'status' => 1, 'type' => $type]; + $station = app()->make(DeliveryStationRepository::class)->getWhere($where); + + if (!$station) throw new ValidateException('门店信息不存在'); + if (!$station['city_name']) throw new ValidateException('门店缺少所在城市,请重新编辑门店信息'); + //地址转经纬度 + try{ + $addres = lbs_address($station['city_name'], $order['user_address']); + if($type == DeliverySevices::DELIVERY_TYPE_UU) { + [$location['lng'],$location['lat']] = gcj02ToBd09($addres['location']['lng'],$addres['location']['lat']); + } else { + $location = $addres['location']; + } + }catch (\Exception $e) { + throw new ValidateException('获取经纬度失败'); + } + + $getPriceParams = $this->getPriceParams($station, $order,$location,$type); + $orderSn = $this->getOrderSn(); + $getPriceParams['origin_id'] = $orderSn; + $getPriceParams['callback_url'] = $callback_url; + $getPriceParams['cargo_weight'] = $data['cargo_weight'] ?? ''; + + $service = DeliverySevices::create($type); + //计算价格 + $priceData = $service->getOrderPrice($getPriceParams); + if ($type == DeliverySevices::DELIVERY_TYPE_UU) { //uu + $priceData['receiver'] = $order['real_name']; + $priceData['receiver_phone'] = $order['user_phone']; + $priceData['note'] = $data['mark']; + $priceData['callback_url'] = $callback_url; + $priceData['push_type'] = 2; + $priceData['special_type'] = $data['special_type'] ?? 0; + } + app()->make(MerchantRepository::class)->changeDeliveryBalance($merId, $priceData['fee'] ?? $priceData['need_paymoney']); + //发布订单 + Db::startTrans(); + try{ + $res = $service->addOrder($priceData); + $ret = [ + 'station_id' => $data['station_id'], + 'order_sn' => $orderSn, + 'city_code' => $station['city_name'], + 'receiver_phone' => $order['user_phone'], + 'user_name' => $order['real_name'], + 'from_address' => $station['station_address'], + 'to_address' => $order['user_address'], + 'order_code' => $type == 2 ? $res['ordercode'] : $priceData['deliveryNo'], + 'order_id' => $id, + 'mer_id' => $merId, + 'info' => $data['mark'], + 'status' => $res['status'] ?? 0, + 'station_type' => $type, + 'to_lat' => $addres['location']['lat'], + 'to_lng' => $addres['location']['lng'], + 'from_lat' => $station['lat'], + 'from_lng' => $station['lng'], + 'distance' => $priceData['distance'], + 'fee' => $priceData['fee'] ?? $priceData['need_paymoney'], + 'mark' => $data['mark'], + 'uid' => $order['uid'], + ]; + //入库操作 + $this->dao->create($ret); + Db::commit(); + return true; + }catch (\Exception $exception) { + if (isset($res['status']) && $res['status'] == 'success'){ + $error['origin_id'] = $orderSn; + $error['reason'] = $type == 1 ? 36 : '信息错误'; + $error['order_code'] = $type == 2 ? $res['ordercode'] : $priceData['deliveryNo']; + sleep(1); + $service->cancelOrder($error); + } + Db::rollback(); + throw new ValidateException($exception->getMessage()); + } + + } + + public function getPriceParams(DeliveryStation $deliveryStation, StoreOrder $order, array $addres, int $type) + { + $data = []; + $type = (int)$type; + switch ($type) { + case 1: + $city = DeliverySevices::create(DeliverySevices::DELIVERY_TYPE_DADA)->getCity([]); + $res = []; + foreach ($city as $item) { + $res[$item['label']] = $item['key']; + } + $data = [ + 'shop_no' => $deliveryStation['origin_shop_id'], + 'city_code' => $res[$deliveryStation['city_name']], + 'cargo_price' => $order['pay_price'], + 'is_prepay' => 0, + 'receiver_name' => $order['real_name'], + 'receiver_address' => $order['user_address'], + 'cargo_weight' => 0, + 'receiver_phone' => $order['user_phone'], + 'is_finish_code_needed' => 1, + ]; + break; + case 2: + $data = [ + 'from_address' => $deliveryStation['station_address'], + 'to_address' => $order['user_address'], + 'city_name' => $deliveryStation['city_name'], + 'goods_type' => $deliveryStation['business']['label'], + 'send_type' =>'0', + 'to_lat' => $addres['lat'], + 'to_lng' => $addres['lng'], + 'from_lat' => $deliveryStation['lat'], + 'from_lng' => $deliveryStation['lng'], + ]; + break; + } + return $data; + } + + public function getTitle() + { + $query = app()->make(MerchantRepository::class)->getSearch(['is_del' => 0]); + $merchant = $query->count(); + $price = app()->make(ServeOrderRepository::class) + ->getSearch(['type' => 10,'status' => 1])->sum('pay_price'); + $balance = $query->sum('delivery_balance'); + return [ + [ + 'className' => 'el-icon-s-order', + 'count' => $merchant, + 'field' => '个', + 'name' => '商户数' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $price, + 'field' => '元', + 'name' => '商户充值总金额' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $balance, + 'field' => '元', + 'name' => '商户当前余额' + ], + ]; + } + + public function destory($id, $merId) + { + $where = [ + $this->dao->getPk() => $id, + 'mer_id' => $merId, + ]; + $res = $this->dao->getSearch($where)->find(); + if (!$res) throw new ValidateException('订单不存在'); + + return $this->dao->delete($id); + } + + /** + * TODO 订单SN + * @return string + * @author Qinii + * @day 2/17/22 + */ + public function getOrderSn() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = 'dc' . $msectime . random_int(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + public function show(int $id, int $uid) + { + $where['order_id'] = $id; + $where['uid'] = $uid; + $res = $this->dao->getSearch($where)->with(['storeOrderStatus','storeOrder'])->find(); + if (!$res) throw new ValidateException('订单不存在'); + return $res; + } + +} diff --git a/app/common/repositories/delivery/DeliveryStationRepository.php b/app/common/repositories/delivery/DeliveryStationRepository.php new file mode 100644 index 00000000..a9921d6e --- /dev/null +++ b/app/common/repositories/delivery/DeliveryStationRepository.php @@ -0,0 +1,236 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\delivery; + +use app\common\dao\delivery\DeliveryStationDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use crmeb\services\DeliverySevices; +use FormBuilder\Factory\Elm; +use think\Exception; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Route; + +class DeliveryStationRepository extends BaseRepository +{ + public function __construct(DeliveryStationDao $dao) + { + $this->dao = $dao; + } + + public function deliveryForm() + { + $formData = systemConfig([ + 'delivery_status', + 'uupt_appkey', + 'uupt_app_id', + 'uupt_open_id', + 'delivery_type', + 'dada_app_key', + 'dada_app_sercret', + 'dada_source_id', + ]); + $form = Elm::createForm(Route::buildUrl('systemDeliveryConfigSave')->build()); + $form->setRule([ + Elm::switches('delivery_status', '是否开启同城配送', $formData['delivery_status'])->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::radio('delivery_type', '配送类型', $formData['delivery_type']) + ->setOptions([ + ['value' => DeliverySevices::DELIVERY_TYPE_DADA, 'label' => '达达快送'], + ['value' => DeliverySevices::DELIVERY_TYPE_UU, 'label' => 'UU跑腿'], + ])->control([ + [ + 'value' => DeliverySevices::DELIVERY_TYPE_DADA, + 'rule' => [ + Elm::input('dada_app_key', 'AppKey (达达)')->value($formData['dada_app_key'])->required(), + Elm::input('dada_app_sercret', 'AppSercret (达达)')->value($formData['dada_app_sercret'])->required(), + Elm::input('dada_source_id', '商户ID (达达)')->value($formData['dada_source_id'])->required(), + ] + ], + [ + 'value' => DeliverySevices::DELIVERY_TYPE_UU, + 'rule' => [ + Elm::input('uupt_appkey', 'AppKey (UU跑腿)')->value($formData['uupt_appkey'])->required(), + Elm::input('uupt_app_id', 'AppId (UU跑腿)')->value($formData['uupt_app_id'])->required(), + Elm::input('uupt_open_id', 'OpenId (UU跑腿)')->value($formData['uupt_open_id'])->required(), + ] + ], + ]), + ]); + return $form->setTitle('同城配送设置'); + } + + public function getBusiness() + { + $type = systemConfig('delivery_type'); + return DeliverySevices::create($type)->getBusiness(); + } + + /** + * TODO 创建门店 + * @param array $data + * @return mixed + * @author Qinii + * @day 2/14/22 + */ + public function save(array $data) + { + return Db::transaction(function () use($data){ + $data['origin_shop_id'] = 'Deliver'.$data['mer_id'].'_'.$this->getSn(); + DeliverySevices::create(systemConfig('delivery_type'))->addShop([$data]); + return $this->dao->create($data); + }); + + } + + public function getSn() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = $msectime . random_int(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + /** + * TODO 更新门店 + * @param $id + * @param $data + * @return mixed + * @author Qinii + * @day 2/14/22 + */ + public function edit($id, $merId, $data) + { + $res = $this->dao->getSearch([$this->dao->getPk() => $id, 'mer_id' => $merId])->find(); + if (!$res) throw new ValidateException('门店不存在或不属于您'); + $type = systemConfig('delivery_type'); + + $data['origin_shop_id'] = $res['origin_shop_id']; + return Db::transaction(function () use($id, $type, $data, $res){ + if ($res['type'] == 2 && $data['type'] == 1) { + DeliverySevices::create($type)->addShop($data); + } else { + DeliverySevices::create($type)->updateShop($data); + } + return $this->dao->update($id, $data); + }); + } + + /** + * TODO + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2/17/22 + */ + public function merList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page, $limit)->order('create_time DESC')->select(); + return compact('count', 'list'); + } + + public function sysList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with([ + 'merchant' => function($query) { + $query->field('mer_id,mer_name'); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->order('create_time DESC')->select(); + return compact('count', 'list'); + } + + public function detail(int $id, ?int $merId) + { + $where[$this->dao->getPk()] = $id; + if ($merId) $where['mer_id'] = $merId; + $res = $this->dao->getSearch($where)->with([ + 'merchant' => function($query) { + $query->field('mer_id,mer_name'); + } + ])->find(); + + if (!$res) throw new ValidateException('门店不存在'); + return $res; + } + + public function destory($id, $merId) + { + $where = [ + $this->dao->getPk() => $id, + 'mer_id' => $merId, + ]; + $res = $this->dao->getSearch($where)->find(); + if (!$res) throw new ValidateException('数据不存在'); +// $data = [ +// 'origin_shop_id' => $res['origin_shop_id'], +// 'status' => 0, +// ]; +// if ($res['type'] == DeliverySevices::DELIVERY_TYPE_DADA) { +// try{ +// DeliverySevices::create($res['type'])->updateShop($data); +// }catch (\Exception $exception) { +// } +// } + return $this->dao->delete($id); + } + + public function markForm($id, $merId) + { + $where = [ + $this->dao->getPk() => $id, + 'mer_id' => $merId, + ]; + $formData = $this->dao->getWhere($where); + $form = Elm::createForm(Route::buildUrl('merchantStoreDeliveryMark',['id' => $id])->build()); + $form->setRule([ + Elm::text('mark', '备注', $formData['mark']), + ]); + return $form->setTitle('备注'); + } + + public function getOptions($where) + { + return $this->dao->getSearch($where)->field('station_id value, station_name label')->order('create_time DESC')->select(); + } + + + public function getCityLst() + { + $type = systemConfig('delivery_type'); + $key = 'delivery_get_city_lst_'.$type; + if (!$data = Cache::get($key)) { + $data = DeliverySevices::create($type)->getCity([]); + Cache::set($key, $data,3600); + } + return $data; + } + + public function getBalance() + { + $type = systemConfig('delivery_type'); + if (!$type) return ['deliverBalance' => 0]; + return DeliverySevices::create(systemConfig('delivery_type'))->getBalance([]); + } + + public function getRecharge() + { + return DeliverySevices::create(systemConfig('delivery_type'))->getRecharge([]); + } + +} diff --git a/app/common/repositories/store/CityAreaRepository.php b/app/common/repositories/store/CityAreaRepository.php new file mode 100644 index 00000000..3cab1f24 --- /dev/null +++ b/app/common/repositories/store/CityAreaRepository.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + + +use app\common\dao\store\CityAreaDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +/** + * @mixin CityAreaDao + */ +class CityAreaRepository extends BaseRepository +{ + public function __construct(CityAreaDao $dao) + { + $this->dao = $dao; + } + + public function getChildren($pid) + { + return $this->search(['pid' => $pid])->select(); + } + + public function getList($where) + { + return $this->dao->getSearch($where)->with(['parent'])->order('id ASC')->select()->append(['children','hasChildren']); + } + + public function form(?int $id, ?int $parentId) + { + $parent = ['id' => 0, 'name' => '全国', 'level' => 0,]; + $formData = []; + if ($id) { + $formData = $this->dao->getWhere(['id' => $id],'*',['parent'])->toArray(); + if (!$formData) throw new ValidateException('数据不存在'); + $form = Elm::createForm(Route::buildUrl('systemCityAreaUpdate', ['id' => $id])->build()); + if (!is_null($formData['parent'])) $parent = $formData['parent']; + } else { + $form = Elm::createForm(Route::buildUrl('systemCityAreaCreate')->build()); + if ($parentId) $parent = $this->dao->getWhere(['id' => $parentId]); + } + $form->setRule([ + Elm::input('parent_id', '', $parent['id'] ?? 0)->hiddenStatus(true), + Elm::input('level', '', $parent['level'] + 1)->hiddenStatus(true), + Elm::input('parent_name', '上级地址', $parent['name'])->disabled(true), + Elm::input('name', '地址名称', '')->required(), + ]); + return $form->setTitle($id ? '编辑城市' : '添加城市')->formData($formData); + } +} diff --git a/app/common/repositories/store/ExcelRepository.php b/app/common/repositories/store/ExcelRepository.php new file mode 100644 index 00000000..f5584f3e --- /dev/null +++ b/app/common/repositories/store/ExcelRepository.php @@ -0,0 +1,110 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store; + +use app\common\dao\store\ExcelDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\admin\AdminRepository; +use app\common\repositories\system\merchant\MerchantAdminRepository; +use crmeb\services\ExcelService; +use think\facade\Db; +use think\facade\Queue; +use crmeb\jobs\SpreadsheetExcelJob; + +class ExcelRepository extends BaseRepository +{ + /** + * @var ExcelDao + */ + protected $dao; + + + /** + * StoreAttrTemplateRepository constructor. + * @param ExcelDao $dao + */ + public function __construct(ExcelDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO + * @param array $where + * @param int $admin_id + * @param string $type + * @author Qinii + * @day 2020-07-30 + */ + public function create(array $where ,int $admin_id, string $type,int $merId) + { + $excel = $this->dao->create([ + 'mer_id' => $merId, + 'admin_id' => $admin_id, + 'type' => $type + ]); + $data = ['where' => $where,'type' => $type,'excel_id' => $excel->excel_id]; + Queue::push(SpreadsheetExcelJob::class,$data); +// app()->make(ExcelService::class)->$type($where,1); + } + + /** + * TODO + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-07-30 + */ + public function getList(array $where,int $page, int $limit) + { + $mer_make = app()->make(MerchantAdminRepository::class); + $sys_make = app()->make(AdminRepository::class); + $query = $this->dao->search($where); + $count = $query->count(); + + $list = $query->page($page,$limit)->select() + ->each(function($item) use ($mer_make,$sys_make){ + if (isset($item['admin_id']) && $item['admin_id']) { + if($item['mer_id']){ + $admin = $mer_make->get($item['admin_id']); + }else{ + $admin = $sys_make->get($item['admin_id']); + } + return $item['admin_id'] = $admin['real_name'] ??""; + } + + }); + return compact('count','list'); + } + + /** + * TODO 删除文件 + * @param int $id + * @param string $path + * @author Qinii + * @day 2020-08-15 + */ + public function del(int $id,?string $path) + { + Db::transaction(function()use($id,$path){ + $this->dao->delete($id); + if(!is_null($path)){ + $path = app()->getRootPath().'public'.$path; + if(file_exists($path))unlink($path); + } + }); + } +} + diff --git a/app/common/repositories/store/GuaranteeRepository.php b/app/common/repositories/store/GuaranteeRepository.php new file mode 100644 index 00000000..4e143cd7 --- /dev/null +++ b/app/common/repositories/store/GuaranteeRepository.php @@ -0,0 +1,134 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store; + +use app\common\dao\store\GuaranteeDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use FormBuilder\Factory\Elm; +use think\facade\Route; + +class GuaranteeRepository extends BaseRepository +{ + /** + * @var GuaranteeDao + */ + protected $dao; + + + /** + * GuaranteeRepository constructor. + * @param GuaranteeDao $dao + */ + public function __construct(GuaranteeDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 平台列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 5/17/21 + */ + public function getList($where,$page, $limit) + { + $query = $this->dao->getSearch($where)->order('sort DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + public function select(array $where) + { + $list = $this->dao->getSearch($where)->field('guarantee_id,guarantee_name,guarantee_info,image')->order('sort DESC')->select(); + return $list; + } + /** + * TODO 添加form + * @param int|null $id + * @param array $formData + * @return \FormBuilder\Form + * @author Qinii + * @day 5/17/21 + */ + public function form(?int $id,array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemGuaranteeCreate')->build() : Route::buildUrl('systemGuaranteeUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::input('guarantee_name', '服务条款')->required(), + Elm::textarea('guarantee_info', '服务内容描述')->autosize([ + 'minRows'=>1000, + ])->required(), + Elm::frameImage('image', '服务条款图标(100*100px)', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=image&type=1')->value($formData['image']??'')->modal(['modal' => false])->width('896px')->height('480px')->required(), + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + return $form->setTitle(is_null($id) ? '添加服务条款' : '编辑服务条款')->formData($formData); + } + + /** + * TODO 编辑form + * @param $id + * @return \FormBuilder\Form + * @author Qinii + * @day 5/17/21 + */ + public function updateForm($id) + { + $ret = $this->dao->get($id); + return $this->form($id,$ret->toArray()); + } + + /** + * TODO 获取详情 + * @param $id + * @return array|\think\Model|null + * @author Qinii + * @day 5/17/21 + */ + public function get($id) + { + $where = [ + $this->dao->getPk() => $id, + 'is_del' => 0, + ]; + $ret = $this->dao->getWhere($where); + return $ret; + } + + public function countGuarantee() + { + /** + * 获取所有条款 + * 计算商户数量 + * 计算商品数量 + */ + $ret = $this->dao->getSearch(['status' => 1,'is_del' => 0])->column($this->dao->getPk()); + $make = app()->make(GuaranteeValueRepository::class); + $makeProduct = app()->make(ProductRepository::class); + if($ret){ + foreach ($ret as $k => $v){ + $item = []; + $item['mer_count'] = $make->getSearch(['guarantee_id' => $v])->group('mer_id')->count('*'); + $template = $make->getSearch(['guarantee_id' => $v])->group('guarantee_template_id')->column('guarantee_template_id'); + $item['product_cout'] = $makeProduct->getSearch(['guarantee_template_id' => $template])->count('*'); + $item['update_time'] = date('Y-m-d H:i:s',time()); + $this->dao->update($v,$item); + } + } + return ; + } + +} diff --git a/app/common/repositories/store/GuaranteeTemplateRepository.php b/app/common/repositories/store/GuaranteeTemplateRepository.php new file mode 100644 index 00000000..a8fb78ea --- /dev/null +++ b/app/common/repositories/store/GuaranteeTemplateRepository.php @@ -0,0 +1,161 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store; + +use app\common\dao\store\GuaranteeTemplateDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +class GuaranteeTemplateRepository extends BaseRepository +{ + /** + * @var GuaranteeTemplateDao + */ + protected $dao; + + + /** + * GuaranteeRepository constructor. + * @param GuaranteeTemplateDao $dao + */ + public function __construct(GuaranteeTemplateDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 平台列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 5/17/21 + */ + public function getList($where,$page, $limit) + { + $query = $this->dao->getSearch($where)->with(['template_value.value'])->order('sort DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + /** + * TODO 创建 + * @param array $data + * @author Qinii + * @day 5/17/21 + */ + public function create(array $data) + { + Db::transaction(function() use($data){ + $template = [ + 'template_name' => $data['template_name'], + 'mer_id' => $data['mer_id'], + 'status' => $data['status'], + 'sort' => $data['sort'] + ]; + $guaranteeData = $this->dao->create($template); + $make = app()->make(GuaranteeRepository::class); + + foreach ($data['template_value'] as $datum){ + + $where = [ 'status' => 1,'is_del' => 0,'guarantee_id' => $datum]; + $ret = $make->getWhere($where); + if(!$ret) throw new ValidateException('ID['.$datum.']不存在'); + $value[] = [ + 'guarantee_id' => $datum , + 'guarantee_template_id' => $guaranteeData->guarantee_template_id, + 'mer_id' => $data['mer_id'] + ]; + } + app()->make(GuaranteeValueRepository::class)->insertAll($value); + }); + } + + /** + * TODO 编辑 + * @param int $id + * @param array $data + * @author Qinii + * @day 5/17/21 + */ + public function edit(int $id,array $data) + { + Db::transaction(function() use($id,$data){ + $template = [ + 'template_name' => $data['template_name'], + 'status' => $data['status'], + 'sort' => $data['sort'] + ]; + $make = app()->make(GuaranteeRepository::class); + $makeValue = app()->make(GuaranteeValueRepository::class); + foreach ($data['template_value'] as $datum){ + $where = [ 'status' => 1,'is_del' => 0,'guarantee_id' => $datum]; + $ret = $make->getWhere($where); + if(!$ret) throw new ValidateException('ID['.$datum.']不存在'); + $value[] = [ + 'guarantee_id' => $datum , + 'guarantee_template_id' => $id, + 'mer_id' => $data['mer_id'] + ]; + } + $this->dao->update($id,$template); + $makeValue->clear($id); + $makeValue->insertAll($value); + }); + } + + /** + * TODO 详情 + * @param int $id + * @param int $merId + * @return array|\think\Model|null + * @author Qinii + * @day 5/17/21 + */ + public function detail(int $id,int $merId) + { + $where = [ + 'mer_id' => $merId, + 'guarantee_template_id' => $id, + ]; + $ret = $this->dao->getSearch($where)->find(); + $ret->append(['template_value']); + if(!$ret) throw new ValidateException('数据不存在'); + return $ret; + } + + public function delete($id) + { + $productId = app()->make(ProductRepository::class)->getSearch(['guarantee_template_id' => $id])->column('product_id'); + if($productId) throw new ValidateException('有商品正在使用此模板,商品ID:'.implode(',',$productId)); + Db::transaction(function() use($id){ + $this->dao->delete($id); + app()->make(GuaranteeValueRepository::class)->clear($id); + }); + } + + public function list($merId) + { + $where = [ + 'status' => 1, + 'is_del' => 0, + 'mer_id' => $merId + ]; + return $this->dao->getSearch($where)->order('sort DESC')->select()->toArray(); + } + +} diff --git a/app/common/repositories/store/GuaranteeValueRepository.php b/app/common/repositories/store/GuaranteeValueRepository.php new file mode 100644 index 00000000..10ac3b5e --- /dev/null +++ b/app/common/repositories/store/GuaranteeValueRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store; + +use app\common\dao\store\GuaranteeValueDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\facade\Route; + +class GuaranteeValueRepository extends BaseRepository +{ + /** + * @var GuaranteeValueDao + */ + protected $dao; + + + /** + * GuaranteeRepository constructor. + * @param GuaranteeValueDao $dao + */ + public function __construct(GuaranteeValueDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/IntegralRepository.php b/app/common/repositories/store/IntegralRepository.php new file mode 100644 index 00000000..5c768821 --- /dev/null +++ b/app/common/repositories/store/IntegralRepository.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + + +use app\common\repositories\BaseRepository; +use think\facade\Cache; + +class IntegralRepository extends BaseRepository +{ + const CACHE_KEY = 'sys_int_next_day'; + + public function getNextDay() + { + return strtotime(date('Y-m-d', strtotime('first day of +1 month 00:00:00'))); + } + + public function getInvalidDay() + { + $month = systemConfig('integral_clear_time'); + if ($month <= 0) return 0; + return strtotime('last day of -' . $month . ' month 23:59:59', $this->getTimeoutDay() - 1); + } + + public function getTimeoutDay($clear = false) + { + $driver = Cache::store('file'); + if (!$driver->has(self::CACHE_KEY) || $clear) { + $driver->set(self::CACHE_KEY, $this->getNextDay(), (20 * 24 * 3600) + 3600 * 12); + } + return $driver->get(self::CACHE_KEY); + } + + public function clearTimeoutDay() + { + Cache::store('file')->delete(self::CACHE_KEY); + } +} diff --git a/app/common/repositories/store/MerchantTakeRepository.php b/app/common/repositories/store/MerchantTakeRepository.php new file mode 100644 index 00000000..452576d4 --- /dev/null +++ b/app/common/repositories/store/MerchantTakeRepository.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + + +use app\common\repositories\system\config\ConfigValueRepository; + +class MerchantTakeRepository +{ + public function get($merId) + { + return merchantConfig($merId, [ + 'mer_take_status', 'mer_take_name', 'mer_take_phone', 'mer_take_address', 'mer_take_location', 'mer_take_day', 'mer_take_time' + ]); + } + + public function set($merId, array $data) + { + $configValueRepository = app()->make(ConfigValueRepository::class); + $configValueRepository->setFormData($data, $merId); + } + + public function has($merId) + { + return merchantConfig($merId, 'mer_take_status') == '1'; + } +} diff --git a/app/common/repositories/store/PriceRuleRepository.php b/app/common/repositories/store/PriceRuleRepository.php new file mode 100644 index 00000000..1e948832 --- /dev/null +++ b/app/common/repositories/store/PriceRuleRepository.php @@ -0,0 +1,89 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + + +use app\common\dao\store\PriceRuleDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\RelevanceRepository; +use think\facade\Db; + +/** + * @mixin PriceRuleDao + */ +class PriceRuleRepository extends BaseRepository +{ + public function __construct(PriceRuleDao $dao) + { + $this->dao = $dao; + } + + public function lst(array $where, $page, $limit) + { + $query = $this->dao->search($where)->order('sort DESC, rule_id DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->with(['cate'])->select(); + return compact('count', 'list'); + } + + public function createRule(array $data) + { + $cateIds = (array)$data['cate_id']; + unset($data['cate_id']); + return Db::transaction(function () use ($cateIds, $data) { + $data['is_default'] = count($cateIds) ? 0 : 1; + $rule = $this->dao->create($data); + $inserts = []; + foreach ($cateIds as $id) { + $inserts[] = [ + 'left_id' => $rule['rule_id'], + 'right_id' => (int)$id, + 'type' => RelevanceRepository::PRICE_RULE_CATEGORY + ]; + } + if (count($inserts)) { + app()->make(RelevanceRepository::class)->insertAll($inserts); + } + + return $rule; + }); + } + + public function updateRule(int $id, array $data) + { + $cateIds = (array)$data['cate_id']; + unset($data['cate_id']); + $data['update_time'] = date('Y-m-d H:i:s'); + return Db::transaction(function () use ($id, $cateIds, $data) { + $data['is_default'] = count($cateIds) ? 0 : 1; + $this->dao->update($id, $data); + $inserts = []; + foreach ($cateIds as $cid) { + $inserts[] = [ + 'left_id' => $id, + 'right_id' => (int)$cid, + 'type' => RelevanceRepository::PRICE_RULE_CATEGORY + ]; + } + app()->make(RelevanceRepository::class)->query([ + 'left_id' => $id, + 'type' => RelevanceRepository::PRICE_RULE_CATEGORY + ])->delete(); + if (count($inserts)) { + app()->make(RelevanceRepository::class)->insertAll($inserts); + } + }); + } + + +} diff --git a/app/common/repositories/store/StoreActivityRepository.php b/app/common/repositories/store/StoreActivityRepository.php new file mode 100644 index 00000000..be94ec38 --- /dev/null +++ b/app/common/repositories/store/StoreActivityRepository.php @@ -0,0 +1,189 @@ + +// +--------------------------------------------------------------------- +namespace app\common\repositories\store; + +use app\common\dao\store\StoreActivityDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\RelevanceRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class StoreActivityRepository extends BaseRepository +{ + //活动边框 + const ACTIVITY_TYPE_ATMOSPHERE = 1; + //氛围图 + const ACTIVITY_TYPE_BORDER = 2; + + //指定范围类型 + //0全部商品 + const TYPE_ALL = 0; + //指定商品 + const TYPE_MUST_PRODUCT = 1; + //指定分类 + const TYPE_MUST_CATEGORY = 2; + //指定商户 + const TYPE_MUST_STORE = 3; + + /** + * @var StoreActivityDao + */ + protected $dao; + + /** + * StoreActivityDao constructor. + * @param StoreActivityDao $dao + */ + public function __construct(StoreActivityDao $dao) + { + $this->dao = $dao; + } + + public function createActivity(array $data,$extend = null, $func = null) + { + $paramsData = $this->getParams($data,$extend); + Db::transaction(function() use($data, $extend, $func,$paramsData){ + $createData = $this->dao->create($data); + if (isset($paramsData['ids']) && !empty($paramsData['ids'])) + app()->make(RelevanceRepository::class)->createMany($createData->activity_id, $paramsData['ids'], $paramsData['type']); + if ($func && function_exists($func)) $this->$func($createData,$extend); + }); + } + + public function getParams($data,$extend) + { + if (!$extend) return []; + $res = []; + $type = ''; + switch ($data['scope_type']) { + case self::TYPE_ALL; + break; + case self::TYPE_MUST_PRODUCT: + if (!isset($extend['spu_ids']) || empty($extend['spu_ids'])) throw new ValidateException('请选择指定商品'); + $res = app()->make(SpuRepository::class)->getSearch(['spu_ids' => $extend['spu_ids'],'status' => 1])->column('spu_id'); + $type = RelevanceRepository::SCOPE_TYPE_PRODUCT; + break; + case self::TYPE_MUST_CATEGORY: + if (!isset($extend['cate_ids']) || empty($extend['cate_ids'])) throw new ValidateException('请选择指定商品分类'); + $res = app()->make(StoreCategoryRepository::class)->getSearch(['ids' => $extend['cate_ids'],'status' => 1])->column('store_category_id'); + $type = RelevanceRepository::SCOPE_TYPE_CATEGORY; + break; + case self::TYPE_MUST_STORE: + if (!isset($extend['mer_ids']) || empty($extend['mer_ids'])) throw new ValidateException('请选择指定商户'); + $res = app()->make(MerchantRepository::class)->getSearch(['mer_ids' => $extend['mer_ids']])->column('mer_id'); + $type = RelevanceRepository::SCOPE_TYPE_STORE; + break; + } + $ids = array_unique($res); + return compact('ids','type'); + } + + public function updateActivity(int $id,array $data,$extend = null, $func = null) + { + $paramsData = $this->getParams($data, $extend); + Db::transaction(function() use($id,$data, $extend, $func,$paramsData){ + $createData = $this->dao->update($id,$data); + app()->make(RelevanceRepository::class)->clear($id, [RelevanceRepository::SCOPE_TYPE_PRODUCT,RelevanceRepository::SCOPE_TYPE_STORE,RelevanceRepository::SCOPE_TYPE_CATEGORY],'left_id'); + if (isset($paramsData['ids']) && !empty($paramsData['ids'])) + app()->make(RelevanceRepository::class)->createMany($id, $paramsData['ids'], $paramsData['type']); + if ($func && function_exists($func)) $this->$func($createData,$extend); + }); + } + + /** + * TODO 详情 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2022/9/17 + */ + public function getAdminList($where, $page, $limit) + { + $query = $this->dao->search($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + /** + * TODO 详情 + * @param $id + * @return array + * @author Qinii + * @day 2022/9/16 + */ + public function detail($id) + { + $data = $this->dao->getSearch([$this->dao->getPk() => $id])->with(['socpeData',])->find()->toArray(); + try{ + $arr = array_column($data['socpeData'],'right_id'); + if ($data['scope_type'] == self::TYPE_MUST_CATEGORY) { + $data['cate_ids'] = $arr; + } else if ($data['scope_type'] == self::TYPE_MUST_STORE) { + $data['mer_ids'] = $arr; + } else { + $data['spu_ids'] = $arr; + } + }catch (\Exception $e) { + } + unset($data['socpeData']); + return $data; + } + + /** + * TODO 删除活动 + * @param $id + * @return mixed + * @author Qinii + * @day 2022/9/17 + */ + public function deleteActivity($id) + { + return Db::transaction(function() use($id){ + $this->dao->delete($id); + app()->make(RelevanceRepository::class)->clear($id,[RelevanceRepository::SCOPE_TYPE_PRODUCT,RelevanceRepository::SCOPE_TYPE_STORE,RelevanceRepository::SCOPE_TYPE_CATEGORY],'left_id'); + }); + } + + public function getActivityBySpu(int $type, $spuId, $cateId, $merId) + { + $make = app()->make(RelevanceRepository::class); + $list = $this->dao->getSearch(['activity_type' => $type,'status' => 1,'is_show' => 1,'gt_end_time' => date('Y-m-d H:i:s',time())])->setOption('field',[])->field('activity_id,scope_type,activity_type,pic')->order('create_time DESC')->select()->toArray(); + foreach ($list as $item) { + switch ($item['scope_type']) { + case self::TYPE_ALL: + return $item; + break; + case self::TYPE_MUST_PRODUCT: + $_type = RelevanceRepository::SCOPE_TYPE_PRODUCT; + $right_id = $spuId ?:0; + break; + case self::TYPE_MUST_CATEGORY: + $_type = RelevanceRepository::SCOPE_TYPE_CATEGORY; + $right_id = $cateId ?:0; + break; + case self::TYPE_MUST_STORE: + $_type = RelevanceRepository::SCOPE_TYPE_STORE; + $right_id = $merId ?:0; + break; + } + if (isset($_type)) { + $res = $make->checkHas($item['activity_id'], $right_id, $_type); + if ($res) return $item; + } + } + return []; + } +} diff --git a/app/common/repositories/store/StoreAttrTemplateRepository.php b/app/common/repositories/store/StoreAttrTemplateRepository.php new file mode 100644 index 00000000..1e019ee4 --- /dev/null +++ b/app/common/repositories/store/StoreAttrTemplateRepository.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + + +use app\common\dao\BaseDao; +use app\common\dao\store\StoreAttrTemplateDao; +use app\common\repositories\BaseRepository; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\Model; + +/** + * Class StoreAttrTemplateRepository + * @package app\common\repositories\store + * @author xaboy + * @day 2020-05-06 + * @mixin StoreAttrTemplateDao + */ +class StoreAttrTemplateRepository extends BaseRepository +{ + /** + * @var StoreAttrTemplateDao + */ + protected $dao; + + /** + * StoreAttrTemplateRepository constructor. + * @param StoreAttrTemplateDao $dao + */ + public function __construct(StoreAttrTemplateDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $merId + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function getList($merId, array $where, $page, $limit) + { + $query = $this->dao->search($merId, $where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @param array $data + * @return array + * @author xaboy + * @day 2020-05-06 + */ + protected function checkValue(array $data) + { + $arr = []; + foreach ($data['template_value'] as $k => $value) { + if (!is_array($value)) throw new ValidateException('规则有误'); + if (!($value['value'] ?? null)) throw new ValidateException('请输入规则名称'); + if (!($value['detail'] ?? null) || !count($value['detail'])) throw new ValidateException('请添加规则值'); + if(in_array($value['value'],$arr)) throw new ValidateException('规格重复'); + $arr[] = $value['value']; + if (count($value['detail']) != count(array_unique($value['detail']))) throw new ValidateException('属性重复') ; + $data['template_value'][$k] = [ + 'value' => $value['value'], + 'detail' => $value['detail'], + ]; + } + return $data; + } + + /** + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-05-06 + */ + public function create(array $data) + { + $data = $this->checkValue($data); + return $this->dao->create($data); + } + + /** + * @param int $id + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function update(int $id, array $data) + { + $data = $this->checkValue($data); + $data['template_value'] = json_encode($data['template_value']); + return $this->dao->update($id, $data); + } + + public function list(int $merId) + { + return $this->dao->getList($merId); + } +} diff --git a/app/common/repositories/store/StoreBrandCategoryRepository.php b/app/common/repositories/store/StoreBrandCategoryRepository.php new file mode 100644 index 00000000..e6c2c367 --- /dev/null +++ b/app/common/repositories/store/StoreBrandCategoryRepository.php @@ -0,0 +1,102 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + +use FormBuilder\Form; +use think\facade\Route; +use FormBuilder\Factory\Elm; +use think\db\exception\DbException; +use app\common\repositories\BaseRepository; +use think\db\exception\DataNotFoundException; +use think\db\exception\ModelNotFoundException; +use FormBuilder\Exception\FormBuilderException; + +use crmeb\traits\CategoresRepository; +use app\common\dao\store\StoreBrandCategoryDao as dao; + +/** + * @mixin dao + */ +class StoreBrandCategoryRepository extends BaseRepository +{ + + use CategoresRepository; + + public function __construct(dao $dao) + { + $this->dao = $dao; + + } + + /** + * @param int $merId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function form(int $merId, ?int $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemStoreBrandCategoryCreate')->build() : Route::buildUrl('systemStoreBrandCategoryUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::cascader('pid', '上级分类')->options(function () use ($id, $merId) { + $menus = $this->dao->getAllOptions(null); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'cate_name'); + array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]), + Elm::input('cate_name', '分类名称')->required(), + Elm::switches('is_show', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加分类' : '编辑分类')->formData($formData); + } + + /** + * @param int $merId + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function updateForm(int $merId, $id) + { + return $this->form($merId, $id, $this->dao->get($id, $merId)->toArray()); + } + + /** + * @return array + * @author xaboy + * @day 2020/7/22 + */ + public function getAncestorsChildList() + { + $res = $this->dao->options(); + $res = formatCascaderData($res, 'cate_name'); + foreach ($res as $k => $v) { + if (!isset($v['children']) || !count($v['children'])) + unset($res[$k]); + } + return array_values($res); + } + +} diff --git a/app/common/repositories/store/StoreBrandRepository.php b/app/common/repositories/store/StoreBrandRepository.php new file mode 100644 index 00000000..6df8b6bc --- /dev/null +++ b/app/common/repositories/store/StoreBrandRepository.php @@ -0,0 +1,128 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\StoreBrandDao as dao; +use app\common\repositories\store\product\ProductRepository; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\facade\Route; + +class StoreBrandRepository extends BaseRepository +{ + + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + public function parentExists(int $id) + { + $make = app()->make(StoreBrandCategoryRepository::class); + return ($make->get($id)) ?? false; + } + + public function meExists($id) + { + return $this->dao->merFieldExists($this->dao->getPk(), $id); + } + + public function merExistsBrand(string $value) + { + return $this->dao->merFieldExists('brand_name', $value); + } + + public function getCategorySearch($where) + { + $make = app()->make(ProductRepository::class); + $where = array_merge($where, $make->productShow()); + $brandIds = app()->make(ProductRepository::class)->getBrandByCategory($where); + $count = 0; + $list = []; + if ($brandIds) { + $query = $this->dao->search(['ids' => $brandIds]); + $count = $query->count(); + $list = $query->select()->toArray(); + array_push($list, [ + "brand_id" => 0, + "brand_category_id" => 0, + "brand_name" => "其他", + "sort" => 999, + "pic" => "", + "is_show" => 1, + "create_time" => "", + ]); + } + return compact('count', 'list'); + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where) + ->with('brandCategory', function ($query) { + $query->field('store_brand_category_id,cate_name,path'); + }); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @param $id + * @return Form + */ + public function updateForm($id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @param int|null $id + * @param array $formData + * @return Form + */ + public function form(?int $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemStoreBrandCreate')->build() : Route::buildUrl('systemStoreBrandUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::cascader('brand_category_id', '上级分类')->options(function () use ($id) { + $menus = app()->make(StoreBrandCategoryRepository::class)->getAncestorsChildList(); + return $menus; + })->props(['props' => ['emitPath' => false]])->appendValidate(Elm::validateInt()->required()->message('请选择上级分类')), + Elm::input('brand_name', '品牌名称')->required(), + Elm::switches('is_show', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + return $form->setTitle(is_null($id) ? '添加品牌' : '编辑品牌')->formData($formData); + } + + /** + * TODO 品牌下是否存在商品 + * @param int $id + * @return bool + * @author Qinii + * @day 12/15/20 + */ + public function getBrandHasProduct(int $id) + { + $make = app()->make(ProductRepository::class); + $count = $make->getSearch(['brand_id' => [$id]])->where('is_del', 0)->count(); + return $count ? true : false; + } +} diff --git a/app/common/repositories/store/StoreCategoryRepository.php b/app/common/repositories/store/StoreCategoryRepository.php new file mode 100644 index 00000000..bc5e72d4 --- /dev/null +++ b/app/common/repositories/store/StoreCategoryRepository.php @@ -0,0 +1,156 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + +use app\common\dao\store\StoreCategoryDao as dao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; +use crmeb\traits\CategoresRepository; + +/** + * @mixin dao + */ +class StoreCategoryRepository extends BaseRepository +{ + + use CategoresRepository; + + public function __construct(dao $dao) + { + $this->dao = $dao; + + } + + /** + * @param int $merId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function form(int $merId, ?int $id = null, array $formData = []) + { + if ($merId) { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('merchantStoreCategoryCreate')->build() : Route::buildUrl('merchantStoreCategoryUpdate', ['id' => $id])->build()); + } else { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemStoreCategoryCreate')->build() : Route::buildUrl('systemStoreCategoryUpdate', ['id' => $id])->build()); + } + $form->setRule([ + Elm::cascader('pid', '上级分类')->options(function () use ($id, $merId) { + $menus = $this->dao->getAllOptions($merId,1,$this->dao->getMaxLevel($merId)-1); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'cate_name'); + array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]])->filterable(true)->appendValidate(Elm::validateInt()->required()->message('请选择上级分类')), + Elm::input('cate_name', '分类名称')->required(), + Elm::frameImage('pic', '分类图片(110*110px)', '/' . config('admin.' . ($merId ? 'merchant' : 'admin') . '_prefix') . '/setting/uploadPicture?field=pic&type=1')->width('896px')->height('480px')->props(['footer' => false])->modal(['modal' => false, 'custom-class' => 'suibian-modal']), + Elm::switches('is_show', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加分类' : '编辑分类')->formData($formData); + } + + /** + * @param int $merId + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function updateForm(int $merId, $id) + { + return $this->form($merId, $id, $this->dao->get($id, $merId)->toArray()); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/16 + * @return mixed + */ + public function getList($status = null,$lv = null) + { + $menus = $this->dao->getAllOptions(0,$status,$lv); + $menus = formatCascaderData($menus, 'cate_name', $lv ?: 3); + return $menus; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getBrandList() + { + return app()->make(StoreBrandRepository::class)->getAll(); + } + + /** + * TODO + * @param int $id + * @param int $pid + * @return bool + * @author Qinii + * @day 5/16/22 + */ + public function checkChildLevel(int $id,int $pid, $merId) + { + $childLevel = max($this->dao->getChildLevelById($id)); //1 + if(!$childLevel) $childLevel = $this->dao->getLevelById($id); + $changLevel = $childLevel + ($this->changeLevel($id,$pid)); //2 + return $this->checkLevel($id, $changLevel,$merId); + } + + /** + * 检测是否超过最低等级限制 + * @param int $id + * @param int $level + * @return bool + * @author Qinii + */ + public function checkLevel(int $id,int $level = 0, $merId = null) + { + $check = $this->getLevelById($id); + if($level) + $check = $level; + return ($check < $this->dao->getMaxLevel($merId)) ? true : false; + } + + public function updateStatus($id, $data) + { + return $this->dao->update($id, $data); + } + + public function getHot($merId) + { + $hot = $this->dao->getSearch(['is_hot' => 1,'mer_id' => $merId])->hidden(['path','level','mer_id','create_time'])->select(); + if ($hot) $hot->toArray(); + return compact('hot'); + } + +} diff --git a/app/common/repositories/store/StoreCategoryRepository.php.bak b/app/common/repositories/store/StoreCategoryRepository.php.bak new file mode 100644 index 00000000..461d789b --- /dev/null +++ b/app/common/repositories/store/StoreCategoryRepository.php.bak @@ -0,0 +1,140 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + +use app\common\dao\store\StoreCategoryDao as dao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; +use crmeb\traits\CategoresRepository; + +/** + * @mixin dao + */ +class StoreCategoryRepository extends BaseRepository +{ + + use CategoresRepository; + + public function __construct(dao $dao) + { + $this->dao = $dao; + + } + + /** + * @param int $merId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function form(int $merId, ?int $id = null, array $formData = []) + { + if ($merId) { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('merchantStoreCategoryCreate')->build() : Route::buildUrl('merchantStoreCategoryUpdate', ['id' => $id])->build()); + } else { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemStoreCategoryCreate')->build() : Route::buildUrl('systemStoreCategoryUpdate', ['id' => $id])->build()); + } + $form->setRule([ + Elm::cascader('pid', '上级分类')->options(function () use ($id, $merId) { + $menus = $this->dao->getAllOptions($merId,1,$this->dao->getMaxLevel($merId)-1); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'cate_name'); + array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]])->filterable(true)->appendValidate(Elm::validateInt()->required()->message('请选择上级分类')), + Elm::input('cate_name', '分类名称')->required(), + Elm::frameImage('pic', '分类图片(110*110px)', '/' . config('admin.' . ($merId ? 'merchant' : 'admin') . '_prefix') . '/setting/uploadPicture?field=pic&type=1')->width('896px')->height('480px')->props(['footer' => false])->modal(['modal' => false, 'custom-class' => 'suibian-modal']), + Elm::switches('is_show', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加分类' : '编辑分类')->formData($formData); + } + + /** + * @param int $merId + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function updateForm(int $merId, $id) + { + return $this->form($merId, $id, $this->dao->get($id, $merId)->toArray()); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/16 + * @return mixed + */ + public function getList($status = null,$lv = null) + { + $menus = $this->dao->getAllOptions(0,$status,$lv); + $menus = formatCascaderData($menus, 'cate_name', $lv ?: 3); + return $menus; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getBrandList() + { + return app()->make(StoreBrandRepository::class)->getAll(); + } + + /** + * 检测是否超过最低等级限制 + * @param int $id + * @param int $level + * @return bool + * @author Qinii + */ + public function checkLevel(int $id,int $level = 0, $merId = null) + { + $check = $this->getLevelById($id); + if($level) + $check = $level; + return ($check < $this->dao->getMaxLevel($merId)) ? true : false; + } + + public function updateStatus($id, $data) + { + return $this->dao->update($id, $data); + } + + public function getHot($merId) + { + $hot = $this->dao->getSearch(['is_hot' => 1,'mer_id' => $merId])->hidden(['path','level','mer_id','create_time'])->select(); + if ($hot) $hot->toArray(); + return compact('hot'); + } + +} diff --git a/app/common/repositories/store/StorePrinterRepository.php b/app/common/repositories/store/StorePrinterRepository.php new file mode 100644 index 00000000..f580d5f0 --- /dev/null +++ b/app/common/repositories/store/StorePrinterRepository.php @@ -0,0 +1,122 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store; + +use app\common\dao\store\StorePrinterDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class StorePrinterRepository extends BaseRepository +{ + public function __construct(StorePrinterDao $dao) + { + $this->dao = $dao; + } + + + public function form(?int $id) + { + if ($id) { + $formData = $this->dao->get($id)->toArray(); + $form = Elm::createForm(Route::buildUrl('merchantStorePrinterUpdate',['id' => $id])->build()); + } else { + $formData = []; + $form = Elm::createForm(Route::buildUrl('merchantStorePrinterCreate')->build()); + } + $form->setRule([ + Elm::input('printer_name','打印机名称')->required(), + Elm::input('printer_appkey','应用ID')->required(), + Elm::input('printer_appid','用户ID')->required(), + Elm::input('printer_secret','应用密匙')->required(), + Elm::input('printer_terminal','打印机终端号')->required()->appendRule('suffix', [ + 'type' => 'div', + 'style' => ['color' => '#999999'], + 'domProps' => [ + 'innerHTML' =>'易联云打印机终端号打印机型号: 易联云打印机 K4无线版', + ] + ]), + Elm::switches('status', '是否开启', 1)->inactiveValue(0)->activeValue(1)->inactiveText('关')->activeText('开') + ]); + return $form->setTitle($id ? '修改打印机' : '添加打印机')->formData($formData); + + } + + public function merList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + public function sysList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with([ + 'merchant' => function($query) { + $query->field('mer_id,mer_name'); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + public function checkPrinterConfig(int $merId) + { + if (!merchantConfig($merId, 'printing_status')) + throw new ValidateException('打印功能未开启'); + $config = [ + 'clientId' => merchantConfig($merId, 'printing_client_id'), + 'apiKey' => merchantConfig($merId, 'printing_api_key'), + 'partner' => merchantConfig($merId, 'develop_id'), + 'terminal' => merchantConfig($merId, 'terminal_number') + ]; + if (!$config['clientId'] || !$config['apiKey'] || !$config['partner'] || !$config['terminal']) + throw new ValidateException('打印机配置错误'); + return $config; + } + + + public function getPrinter(int $merId) + { + if (!merchantConfig($merId, 'printing_status')) + throw new ValidateException('打印功能未开启'); + + $res = $this->dao->getSearch(['mer_id' => $merId, 'status' => 1])->column(' + printer_appkey clientId, + printer_terminal terminal, + printer_appid partner, + printer_secret apiKey + '); + + if (!$res){ + $config = [ + 'clientId' => merchantConfig($merId, 'printing_client_id'), + 'apiKey' => merchantConfig($merId, 'printing_api_key'), + 'partner' => merchantConfig($merId, 'develop_id'), + 'terminal' => merchantConfig($merId, 'terminal_number') + ]; + + if (!$config['clientId'] || !$config['apiKey'] || !$config['partner'] || !$config['terminal']) { + $res[] = $config; + } + } + + if (!$res) throw new ValidateException('请添加打印机'); + return $res; + } +} diff --git a/app/common/repositories/store/StoreSeckillActiveRepository.php b/app/common/repositories/store/StoreSeckillActiveRepository.php new file mode 100644 index 00000000..97e11714 --- /dev/null +++ b/app/common/repositories/store/StoreSeckillActiveRepository.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store; + +use app\common\dao\store\StoreSeckillActiveDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class StoreSeckillActiveRepository extends BaseRepository +{ + + /** + * @var StoreSeckillActiveDao + */ + protected $dao; + + /** + * StoreSeckillTimeRepository constructor. + * @param StoreSeckillActiveDao $dao + */ + public function __construct(StoreSeckillActiveDao $dao) + { + $this->dao = $dao; + } + + public function updateSort(int $id,?int $merId,array $data) + { + $where[$this->dao->getPk()] = $id; + if($merId) $where['mer_id'] = $merId; + $ret = $this->dao->getWhere($where); + if(!$ret) throw new ValidateException('数据不存在'); + app()->make(ProductRepository::class)->update($ret['product_id'],$data); + $make = app()->make(SpuRepository::class); + return $make->updateSort($ret['product_id'],$ret[$this->dao->getPk()],1,$data); + } +} diff --git a/app/common/repositories/store/StoreSeckillTimeRepository.php b/app/common/repositories/store/StoreSeckillTimeRepository.php new file mode 100644 index 00000000..86defcda --- /dev/null +++ b/app/common/repositories/store/StoreSeckillTimeRepository.php @@ -0,0 +1,138 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store; + +use app\common\dao\store\StoreSeckillTimeDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\facade\Route; + +class StoreSeckillTimeRepository extends BaseRepository +{ + /** + * @var StoreSeckillDao + */ + protected $dao; + + /** + * StoreSeckillTimeRepository constructor. + * @param StoreSeckillDao $dao + */ + public function __construct(StoreSeckillTimeDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where,int $page, int$limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + + return compact('count','list'); + } + + public function select() + { + $query = $this->dao->search(['status' => 1]); + $list = $query->select(); + return $list; + } + + public function form(?int $id = null ,array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemSeckillConfigCreate')->build() : Route::buildUrl('systemSeckillConfigUpdate', ['id' => $id])->build()); + + $form->setRule([ + Elm::input('title','标题'), + Elm::select('start_time','开始时间')->options($this->dao->getTime(1)), + Elm::select('end_time','结束时间')->options($this->dao->getTime(0)), + Elm::switches('status','是否启用')->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::frameImage('pic', '图片', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=pic&type=1')->width('896px')->height('480px')->spin(0)->modal(['modal' => false])->props(['footer' => false]), + ]); + return $form->setTitle(is_null($id) ? '添加' : '编辑')->formData($formData); + } + + + public function updateForm($id) + { + return $this->form($id,$this->dao->get($id)->toArray()); + } + + /** + * TODO 所选时间段是否重叠 + * @param $where + * @return bool + * @author Qinii + * @day 2020-07-31 + */ + public function checkTime(array $where,?int $id) + { + if(!$this->dao->valStartTime($where['start_time'],$id) && !$this->dao->valEndTime($where['end_time'],$id) && !$this->dao->valAllTime($where,$id)) return true; + return false; + } + + /** + * TODO APi秒杀时间列表 + * @return array + * @author Qinii + * @day 2020-08-11 + */ + public function selectTime() + { + $seckillTimeIndex = 0; + $_h = date('H',time()); + $query = $this->dao->search(['status' => 1]); + $list = $query->select(); + $seckillEndTime = time(); + $seckillTime = []; + foreach($list as $k => $item){ + $item['stop'] = strtotime((date('Y-m-d ',time()).$item['end_time'].':00:00')); + if($item['end_time'] <= $_h) { + $item['pc_status'] = 0; + $item['state'] = '已结束'; + } + if($item['start_time'] > $_h ) { + $item['pc_status'] = 2; + $item['state'] = '待开始'; + } + if($item['start_time'] <= $_h && $_h < $item['end_time']){ + $item['pc_status'] = 1; + $item['state'] = '抢购中'; + $seckillTimeIndex = $k; + $seckillEndTime = strtotime((date('Y-m-d ',time()).$item['end_time'].':00:00')); + $item['stop_time'] = date('Y-m-d H:i:s', $seckillEndTime); + } + + $seckillTime[$k] = $item; + } + return compact('seckillTime','seckillTimeIndex','seckillEndTime'); + } + + /** + * TODO 获取某个时间是否有开启秒杀活动 + * @param array $where + * @return mixed + * @author Qinii + * @day 2020-08-19 + */ + public function getBginTime(array $where) + { + if($where['start_time'] == '' || $where['end_time'] == ''){ + $where['start_time'] = date('H',time()); + $where['end_time'] = date('H',time()) + 1; + } + $where['status'] = 1; + return $this->dao->search($where)->find(); + } +} diff --git a/app/common/repositories/store/broadcast/BroadcastAssistantRepository.php b/app/common/repositories/store/broadcast/BroadcastAssistantRepository.php new file mode 100644 index 00000000..533daf39 --- /dev/null +++ b/app/common/repositories/store/broadcast/BroadcastAssistantRepository.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\broadcast; + +use app\common\dao\store\broadcast\BroadcastAssistantDao; +use app\common\repositories\BaseRepository; +use crmeb\services\MiniProgramService; +use FormBuilder\Exception\FormBuilderException; +use think\facade\Route; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; + +class BroadcastAssistantRepository extends BaseRepository +{ + /** + * @var BroadcastAssistantDao + */ + protected $dao; + + public function __construct(BroadcastAssistantDao $dao) + { + $this->dao = $dao; + } + + public function form(?int $id) + { + $formData = []; + if ($id) { + $form = Elm::createForm(Route::buildUrl('merchantBroadcastAssistantUpdate', ['id' => $id])->build()); + $data = $this->dao->get($id); + if (!$data) throw new FormBuilderException('数据不存在'); + $formData = $data->toArray(); + + } else { + $form = Elm::createForm(Route::buildUrl('merchantBroadcastAssistantCreate')->build()); + } + + $rules = [ + Elm::input('username', '微信号')->required(), + Elm::input('nickname', '微信昵称')->required(), + Elm::input('mark', '备注'), + ]; + $form->setRule($rules); + return $form->setTitle(is_null($id) ? '添加小助手账号' : '编辑小助手账号')->formData($formData); + } + + public function getList($where, int $page, int $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count('*'); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + public function options(int $merId) + { + return $this->dao->getSearch(['mer_id' => $merId])->column('nickname','assistant_id'); + } + + +} diff --git a/app/common/repositories/store/broadcast/BroadcastGoodsRepository.php b/app/common/repositories/store/broadcast/BroadcastGoodsRepository.php new file mode 100644 index 00000000..171a1ccb --- /dev/null +++ b/app/common/repositories/store/broadcast/BroadcastGoodsRepository.php @@ -0,0 +1,337 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\broadcast; + + +use app\common\dao\store\broadcast\BroadcastGoodsDao; +use app\common\repositories\BaseRepository; +use crmeb\jobs\ApplyBroadcastGoodsJob; +use crmeb\services\DownloadImageService; +use crmeb\services\MiniProgramService; +use crmeb\services\SwooleTaskService; +use Exception; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class BroadcastGoodsRepository + * @package app\common\repositories\store\broadcast + * @author xaboy + * @day 2020/7/30 + * @mixin BroadcastGoodsDao + */ +class BroadcastGoodsRepository extends BaseRepository +{ + /** + * @var BroadcastGoodsDao + */ + protected $dao; + + public function __construct(BroadcastGoodsDao $dao) + { + $this->dao = $dao; + } + + public function getList($merId, array $where, $page, $limit) + { + $where['mer_id'] = $merId; + $query = $this->dao->search($where)->with('product')->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function adminList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with(['merchant' => function ($query) { + $query->field('mer_name,mer_id,is_trader'); + },'product'])->order('BroadcastGoods.sort DESC,BroadcastGoods.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + + /** + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/7/30 + */ + public function createForm(array $formData = []) + { + if (isset($formData['product_id'])) { + $formData['product_id'] = [ + 'id' => $formData['product_id'], + 'src' => $formData['cover_img'] + ]; + } + return Elm::createForm((isset($formData['broadcast_goods_id']) ? Route::buildUrl('merchantBroadcastGoodsUpdate', ['id' => $formData['broadcast_goods_id']]) : Route::buildUrl('merchantBroadcastGoodsCreate'))->build(), [ + Elm::frameImage('product_id', '商品', '/' . config('admin.merchant_prefix') . '/setting/storeProduct?field=product_id')->width('60%')->height('536px')->props(['srcKey' => 'src'])->modal(['modal' => false])->appendValidate(Elm::validateObject()->message('请选择商品')), + Elm::input('name', '商品名称')->required(), + Elm::frameImage('cover_img', '商品图', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=cover_img&type=1') + ->info('图片尺寸最大像素 300*300')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false])->required(), + Elm::number('price', '价格')->min(0.01)->info('该价格只做展示,不会影响原商品价格')->required(), + ])->setTitle('创建直播商品')->formData($formData); + } + + public function updateForm($id) + { + return $this->createForm($this->dao->get($id)->toArray())->setTitle('编辑直播商品'); + } + + /** + * @param $merId + * @param array $data + * @return mixed + * @author xaboy + * @day 2020/8/25 + */ + public function create($merId, array $data) + { + $data['status'] = request()->merchant()->is_bro_goods == 1 ? 0 : 1; + $data['mer_id'] = $merId; + return Db::transaction(function () use ($data) { + $goods = $this->dao->create($data); + if ($data['status'] == 1) { + $res = $this->wxCreate($goods); + $goods->goods_id = $res->goodsId; + $goods->audit_id = $res->auditId; + $goods->save(); + } else { + SwooleTaskService::admin('notice', [ + 'type' => 'new_goods', + 'data' => [ + 'title' => '新直播商品申请', + 'message' => '您有1个新的直播商品审核,请及时处理!', + 'id' => $goods->broadcast_goods_id + ] + ]); + } + return $goods; + }); + } + + public function batchCreate($merId, array $goodsList) + { + $status = request()->merchant()->is_bro_goods == 1 ? 0 : 1; + $ids = Db::transaction(function () use ($goodsList, $status, $merId) { + $ids = []; + foreach ($goodsList as $goods) { + $goods['status'] = $status; + $goods['mer_id'] = $merId; + $ids[] = $this->dao->create($goods)->broadcast_goods_id; + } + return $ids; + }); + foreach ($ids as $id) { + if ($status == 1) { + Queue::push(ApplyBroadcastGoodsJob::class, $id); + } else { + SwooleTaskService::admin('notice', [ + 'type' => 'new_goods', + 'data' => [ + 'title' => '新直播商品申请', + 'message' => '您有1个新的直播商品审核,请及时处理!', + 'id' => $id + ] + ]); + } + } + } + + /** + * @param $id + * @param array $data + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/8/25 + */ + public function update($id, array $data) + { + $goods = $this->dao->get($id); + $status = request()->merchant()->is_bro_goods == 1 ? 0 : 1; + if ($goods->status == 0) { + $goods->save($data); + if ($status == 1) { + if ($goods->goods_id) { + $this->wxUpdate($goods->goods_id, $data); + } else { + $res = $this->wxCreate($goods); + $goods->goods_id = $res->goodsId; + $goods->audit_id = $res->auditId; + } + $goods->save(); + } else { + SwooleTaskService::admin('notice', [ + 'type' => 'new_goods', + 'data' => [ + 'title' => '新直播商品申请', + 'message' => '您有1个新的直播商品审核,请及时处理!', + 'id' => $goods->broadcast_goods_id + ] + ]); + } + } else { + if ($status == 1 && $goods->goods_id) { + $this->wxUpdate($goods->goods_id, $data); + } + $data['status'] = $status; + $data['error_msg'] = ''; + $this->change($id, $data); + } + return $goods; + } + + public function change($id, array $data) + { + return $this->dao->update($id, $data); + } + + public function applyForm($id) + { + return Elm::createForm(Route::buildUrl('systemBroadcastGoodsApply', compact('id'))->build(), [ + Elm::radio('status', '审核状态', 1)->options([['value' => -1, 'label' => '未通过'], ['value' => 1, 'label' => '通过']])->control([ + ['value' => -1, 'rule' => [ + Elm::textarea('msg', '未通过原因', '信息有误,请完善')->required() + ]] + ]), + ])->setTitle('审核直播商品'); + } + + public function apply($id, $status, $msg = '') + { + $goods = $this->dao->get($id); + Db::transaction(function () use ($msg, $status, $goods) { + $goods->status = $status; + if ($status == -1) + $goods->error_msg = $msg; + else { + if ($goods->goods_id) { + $this->wxUpdate($goods->goods_id, $goods); + } else { + $res = $this->wxCreate($goods); + $goods->goods_id = $res->goodsId; + $goods->audit_id = $res->auditId; + } + $goods->status = 1; + } + $goods->save(); + SwooleTaskService::merchant('notice', [ + 'type' => 'goods_status_' . ($status == -1 ? 'fail' : 'success'), + 'data' => [ + 'title' => '直播商品审核通知', + 'message' => $status == -1 ? '您的直播商品审核未通过!' : '您的直播商品审核已通过', + 'id' => $goods->broadcast_goods_id + ] + ], $goods->mer_id); + }); + } + + public function wxCreate($goods) + { + if ($goods['goods_id']) + throw new ValidateException('商品已创建'); + + $goods = $goods->toArray(); + $miniProgramService = MiniProgramService::create(); + $path = './public' . app()->make(DownloadImageService::class)->downloadImage($goods['cover_img'],'def','',1)['path']; + $data = [ + 'name' => $goods['name'], + 'priceType' => 1, + 'price' => floatval($goods['price']), + 'url' => 'pages/goods_details/index?source=1:' . $goods['broadcast_goods_id'] . ':' . $goods['product_id'] . '&id=' . $goods['product_id'], + 'coverImgUrl' => $miniProgramService->material()->uploadImage($path)->media_id, + ]; + @unlink($path); + try { + return $miniProgramService->miniBroadcast()->create($data); + } catch (Exception $e) { + throw new ValidateException($e->getMessage()); + } + } + + public function wxUpdate($id,$data) + { + $miniProgramService = MiniProgramService::create(); + $path = './public' . app()->make(DownloadImageService::class)->downloadImage($data['cover_img'],'def','',1)['path']; + $params = [ + "goodsId" => $id, + 'name' => $data['name'], + 'priceType' => 1, + 'price' => floatval($data['price']), + 'coverImgUrl' => $miniProgramService->material()->uploadImage($path)->media_id, + ]; + @unlink($path); + try { + return $miniProgramService->miniBroadcast()->update($params); + } catch (Exception $e) { + throw new ValidateException($e->getMessage()); + } + } + + public function isShow($id, $isShow, bool $admin = false) + { + return $this->dao->update($id, [($admin ? 'is_show' : 'is_mer_show') => $isShow]); + } + + public function mark($id, $mark) + { + return $this->dao->update($id, compact('mark')); + } + + public function delete($id) + { + $goods = $this->dao->get($id); + if ($goods->goods_id) { + MiniProgramService::create()->miniBroadcast()->delete($goods->goods_id); + } + app()->make(BroadcastRoomGoodsRepository::class)->deleteGoods($id); + $this->dao->delete($id); + + } + + public function syncGoodStatus() + { + $goodsIds = $this->dao->goodsStatusAll(); + if (!count($goodsIds)) return; + $res = MiniProgramService::create()->miniBroadcast()->getGoodsWarehouse(array_keys($goodsIds))->toArray(); + foreach ($res['goods'] as $item) { + if (isset($goodsIds[$item['goods_id']]) && $item['audit_status'] != $goodsIds[$item['goods_id']]) { + $data = ['audit_status' => $item['audit_status']]; + if (in_array($item['audit_status'], [2, 3])) { + $data['status'] = $item['audit_status'] == 3 ? -1 : 2; + if (-1 == $data['status']) { + $data['error_msg'] = '微信审核未通过'; + } + } + //TODO 同步商品审核状态 + $this->dao->updateGoods($item['goods_id'], $data); + } + } + } +} diff --git a/app/common/repositories/store/broadcast/BroadcastRoomGoodsRepository.php b/app/common/repositories/store/broadcast/BroadcastRoomGoodsRepository.php new file mode 100644 index 00000000..46a83581 --- /dev/null +++ b/app/common/repositories/store/broadcast/BroadcastRoomGoodsRepository.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\broadcast; + + +use app\common\dao\store\broadcast\BroadcastRoomGoodsDao; +use app\common\repositories\BaseRepository; + +/** + * Class BroadcastRoomGoodsRepository + * @package app\common\repositories\store\broadcast + * @author xaboy + * @day 2020/7/31 + * @mixin BroadcastRoomGoodsDao + */ +class BroadcastRoomGoodsRepository extends BaseRepository +{ + public function __construct(BroadcastRoomGoodsDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/broadcast/BroadcastRoomRepository.php b/app/common/repositories/store/broadcast/BroadcastRoomRepository.php new file mode 100644 index 00000000..b9978e85 --- /dev/null +++ b/app/common/repositories/store/broadcast/BroadcastRoomRepository.php @@ -0,0 +1,500 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\broadcast; + + +use app\common\dao\store\broadcast\BroadcastRoomDao; +use app\common\model\store\broadcast\BroadcastRoom; +use app\common\repositories\BaseRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\DownloadImageService; +use crmeb\services\MiniProgramService; +use crmeb\services\SwooleTaskService; +use EasyWeChat\Core\Exceptions\HttpException; +use Exception; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +/** + * Class BroadcastRoomRepository + * @package app\common\repositories\store\broadcast + * @author xaboy + * @day 2020/7/29 + * @mixin BroadcastRoomDao + */ +class BroadcastRoomRepository extends BaseRepository +{ + /** + * @var BroadcastRoomDao + */ + protected $dao; + + /** + * BroadcastRoomRepository constructor. + * @param BroadcastRoomDao $dao + */ + public function __construct(BroadcastRoomDao $dao) + { + $this->dao = $dao; + } + + public function getList($merId, array $where, $page, $limit) + { + $where['mer_id'] = $merId; + $query = $this->dao->search($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function userList(array $where, $page, $limit) + { + $where['show_tag'] = 1; + $query = $this->dao->search($where)->with([ + 'broadcast' => function($query) { + $query->where('on_sale',1); + $query->with('goods'); + } + ])->where('room_id', '>', 0) + ->whereNotIn('live_status', [107])->order('star DESC, sort DESC, create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as $item) { + $item->show_time = date('m/d H:i', strtotime($item->start_time)); + } + return compact('count', 'list'); + } + + public function adminList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with(['merchant' => function ($query) { + $query->field('mer_name,mer_id,is_trader'); + }])->order('BroadcastRoom.star DESC, BroadcastRoom.sort DESC, BroadcastRoom.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/7/29 + */ + public function createForm() + { + return Elm::createForm(Route::buildUrl('merchantBroadcastRoomCreate')->build(), [ + Elm::input('name', '直播间名字')->required(), + Elm::frameImage('cover_img', '背景图', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=cover_img&type=1') + ->info('建议像素1080*1920,大小不超过2M')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false])->required(), + + Elm::frameImage('share_img', '分享图', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=share_img&type=1') + ->info('建议像素800*640,大小不超过1M')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false])->required(), + + Elm::frameImage('feeds_img', '封面图', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=feeds_img&type=1') + ->info('建议像素800*800,大小不超过1M')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false])->required(), + + Elm::input('anchor_name', '主播昵称')->required()->placeholder('请输入主播昵称,主播需通过小程序直播认证,否则会提交失败。'), + Elm::input('anchor_wechat', '主播微信号')->required()->placeholder('请输入主播微信号,主播需通过小程序直播认证,否则会提交失败。'), + Elm::input('phone', '联系电话')->required(), + Elm::dateTimeRange('start_time', '直播时间')->value([])->required(), + Elm::radio('type', '直播间类型', 0)->options([['value' => 0, 'label' => '手机直播'],['value' => 1, 'label' => '推流']]), + Elm::radio('screen_type', '显示样式', 0)->options([['value' => 0, 'label' => '竖屏'], ['value' => 1, 'label' => '横屏']]), + + Elm::switches('close_like', '是否开启点赞', 0) + ->activeValue(0)->inactiveValue(1) + ->activeText('开')->inactiveText('关'), + + Elm::switches('close_goods', '是否开启货架', 0) + ->activeValue(0)->inactiveValue(1) + ->activeText('开')->inactiveText('关'), + + Elm::switches('close_comment', '是否开启评论', 0) + ->activeValue(0)->inactiveValue(1) + ->activeText('开')->inactiveText('关'), + + Elm::switches('replay_status', '是否开启回放', 0) + ->activeValue(1)->inactiveValue(0) + ->activeText('开')->inactiveText('关'), + + Elm::switches('close_share', '是否开启分享', 0) + ->activeValue(0)->inactiveValue(1) + ->activeText('开')->inactiveText('关'), + + Elm::switches('close_kf', '是否开启客服', 0) + ->activeValue(0)->inactiveValue(1) + ->activeText('开')->inactiveText('关'), + + Elm::switches('is_feeds_public', '是否开启官方收录', 1) + ->activeValue(1)->inactiveValue(0) + ->activeText('开')->inactiveText('关'), + + ])->setTitle('创建直播间'); + } + + public function updateForm($id) + { + $data = $this->dao->get($id)->toArray(); + $data['start_time'] = [$data['start_time'], $data['end_time']]; + return $this->createForm()->setAction(Route::buildUrl('merchantBroadcastRoomUpdate', compact('id'))->build())->formData($data)->setTitle('编辑直播间'); + } + + public function create($merId, array $data) + { + $data['status'] = request()->merchant()->is_bro_room == 1 ? 0 : 1; + $data['mer_id'] = $merId; + return Db::transaction(function () use ($data) { + $room = $this->dao->create($data); + if ($data['status'] == 1) { + $room->room_id = $this->wxCreate($room); + $room->status = 2; + $room->save(); + } else { + SwooleTaskService::admin('notice', [ + 'type' => 'new_broadcast', + 'data' => [ + 'title' => '新直播间申请', + 'message' => '您有1个新的直播间审核,请及时处理!', + 'id' => $room->broadcast_room_id + ] + ]); + } + return $room; + }); + } + + public function updateRoom($merId, $id, array $data) + { + $data['status'] = 0; + $room = $this->dao->getWhere(['mer_id' => $merId, 'broadcast_room_id' => $id]); + $room->save($data); + SwooleTaskService::admin('notice', [ + 'type' => 'new_broadcast', + 'data' => [ + 'title' => '新直播间申请', + 'message' => '您有1个新的直播间审核,请及时处理!', + 'id' => $room->broadcast_room_id + ] + ]); + } + + public function applyForm($id) + { + return Elm::createForm(Route::buildUrl('systemBroadcastRoomApply', compact('id'))->build(), [ + Elm::radio('status', '审核状态', '1')->options([['value' => '-1', 'label' => '未通过'], ['value' => '1', 'label' => '通过']])->control([ + ['value' => '-1', 'rule' => [ + Elm::textarea('msg', '未通过原因', '信息有误,请完善')->required() + ]] + ]), + ])->setTitle('审核直播间'); + } + + public function apply($id, $status, $msg = '') + { + $room = $this->dao->get($id); + Db::transaction(function () use ($msg, $status, $room) { + $room->status = $status; + if ($status == -1) + $room->error_msg = $msg; + else { + $room_id = $this->wxCreate($room); + $room->room_id = $room_id; + $room->status = 2; + if ($room->type) { + $path = MiniProgramService::create()->miniBroadcast()->getPushUrl($room_id); + $room->push_url = $path->pushAddr; + } + } + $room->save(); + + SwooleTaskService::merchant('notice', [ + 'type' => 'broadcast_status_' . ($status == -1 ? 'fail' : 'success'), + 'data' => [ + 'title' => '直播间审核通知', + 'message' => $status == -1 ? '您的直播间审核未通过!' : '您的直播间审核已通过', + 'id' => $room->broadcast_room_id + ] + ], $room->mer_id); + + if ($status == -1) { + Queue::push(SendSmsJob::class, [ + 'tempId' => 'BROADCAST_ROOM_FAIL', + 'id' => $room['broadcast_room_id'] + ]); + } + }); + } + + public function wxCreate(BroadcastRoom $room) + { + if ($room['room_id']) + throw new ValidateException('直播间已创建'); + + $room = $room->toArray(); + $miniProgramService = MiniProgramService::create(); + $DownloadImageService = app()->make(DownloadImageService::class); + $coverImg = './public' . $DownloadImageService->downloadImage($room['cover_img'],'def','',1)['path']; + $shareImg = './public' . $DownloadImageService->downloadImage($room['share_img'],'def','',1)['path']; + $feedsImg = './public' . $DownloadImageService->downloadImage($room['feeds_img'],'def','',1)['path']; + $data = [ + 'startTime' => strtotime($room['start_time']), + 'endTime' => strtotime($room['end_time']), + 'name' => $room['name'], + 'anchorName' => $room['anchor_name'], + 'anchorWechat' => $room['anchor_wechat'], + 'screenType' => $room['screen_type'], + 'closeGoods' => $room['close_goods'], + 'closeLike' => $room['close_like'], + 'closeComment' => $room['close_comment'], + 'closeShare' => $room['close_share'], + 'closeKf' => $room['close_kf'], + 'closeReplay' => $room['replay_status'] == 1 ? 0 : 1, + 'isFeedsPublic' => $room['is_feeds_public'] == 1 ? 0 : 1, + 'coverImg' => $miniProgramService->material()->uploadImage($coverImg)->media_id, + 'shareImg' => $miniProgramService->material()->uploadImage($shareImg)->media_id, + 'feedsImg' => $miniProgramService->material()->uploadImage($feedsImg)->media_id, + ]; + @unlink($coverImg); + @unlink($shareImg); + @unlink($feedsImg); + + try { + $roomId = $miniProgramService->miniBroadcast()->createLiveRoom($data)->roomId; + } catch (Exception $e) { + throw new ValidateException($e->getMessage()); + } + Queue::push(SendSmsJob::class, [ + 'tempId' => 'BROADCAST_ROOM_CODE', + 'id' => $room['broadcast_room_id'] + ]); + return $roomId; + } + + public function isShow($id, $isShow, bool $admin = false) + { + return $this->dao->update($id, [($admin ? 'is_show' : 'is_mer_show') => $isShow]); + } + + public function mark($id, $mark) + { + return $this->dao->update($id, compact('mark')); + } + + /** + * @param $merId + * @param array $ids + * @param $roomId + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/7/31 + */ + public function exportGoods($merId, array $ids, $roomId) + { + $broadcastGoodsRepository = app()->make(BroadcastGoodsRepository::class); + if (count($ids) != count($goods = $broadcastGoodsRepository->goodsList($merId, $ids))) + throw new ValidateException('请选择正确的直播商品'); + if (!$room = $this->dao->validRoom($roomId, $merId)) + throw new ValidateException('直播间状态有误'); + $broadcastRoomGoodsRepository = app()->make(BroadcastRoomGoodsRepository::class); + $goodsId = $broadcastRoomGoodsRepository->goodsId($room->broadcast_room_id); + $ids = []; + $data = []; + foreach ($goods as $item) { + if (!in_array($item->broadcast_goods_id, $goodsId)) { + $data[] = [ + 'broadcast_room_id' => $room->broadcast_room_id, + 'broadcast_goods_id' => $item->broadcast_goods_id + ]; + $ids[] = $item->goods_id; + } + } + if (!count($ids)) return; + Db::transaction(function () use ($ids, $broadcastRoomGoodsRepository, $goods, $room, $data) { + $broadcastRoomGoodsRepository->insertAll($data); + MiniProgramService::create()->miniBroadcast()->addGoods(['roomId' => $room->room_id, 'ids' => $ids]); + }); + } + + public function rmExportGoods($merId, $roomId, $id) + { + if (!$this->dao->merExists($roomId, $merId)) + throw new ValidateException('直播间不存在'); + app()->make(BroadcastRoomGoodsRepository::class)->rmGoods($id, $roomId); + } + + /** + * @throws HttpException + * @throws DbException + * @author xaboy + * @day 2020/7/31 + */ + public function syncRoomStatus() + { + $start = 0; + $limit = 50; + $client = MiniProgramService::create()->miniBroadcast(); + do { + $data = $client->getRooms($start, $limit)->room_info; + $start += 50; + $rooms = $this->getRooms(array_column($data, 'roomid')); + foreach ($data as $room) { + if (isset($rooms[$room['roomid']]) && $room['live_status'] != $rooms[$room['roomid']]['live_status']) { + $this->dao->update($rooms[$room['roomid']]['broadcast_room_id'], ['live_status' => $room['live_status']]); + } + } + } while (count($data) >= $limit); + } + + public function merDelete($id) + { +// $room = $this->dao->get($id); +// if ($room && ($room->status == -1 || $room->status == 0 || $room->live_status == 107 || $room->live_status == 103)) { + return $this->dao->merDelete($id); +// } +// throw new ValidateException('状态有误,删除失败'); + } + + public function closeInfo($id, string $type, int $status, $check = true, $data = []) + { + $room = $this->dao->get($id); + if ($room->status !== 2) throw new ValidateException('直播间还未审核通过,无法修改'); + if (!$room) throw new ValidateException('数据不存在'); + + if ($check && $room[$type] == -1) { + throw new ValidateException('平台已关闭,您无法修改'); + } + + Db::transaction(function () use ($room, $id, $type, $status,$data) { + $client = MiniProgramService::create()->miniBroadcast(); + switch ($type) { + case 'close_kf': + $client->closeKf($room->room_id, $status); + $room->close_kf = $status; + break; + case 'close_comment': + $client->banComment($room->room_id, $status); + $room->close_comment = $status; + break; + case 'is_feeds_public': + $client->updateFeedPublic($room->room_id,$status); + $room->is_feeds_public = $status; + break; + case 'on_sale': + $ret = app()->make(BroadcastRoomGoodsRepository::class)->getWhere([ + 'broadcast_room_id' => $id, + 'broadcast_goods_id' => $data['goods_id'], + ],'*',['goods']); + if (!isset($ret['goods']['goods_id'])) throw new ValidateException('数据不存在'); + $ret->on_sale = $status; + $ret->save(); + $client->goodsOnsale($room->room_id,$ret['goods']['goods_id'],$status); + $room->is_feeds_public = $status; + break; + } + $room->save(); + }); + } + + public function assistantForm(int $id, int $merId) + { + $make = app()->make(BroadcastAssistantRepository::class); + $get = $this->dao->get($id); + if ($get->status !== 2) throw new ValidateException('直播间还未审核通过,无法操作'); + $data = $make->options($merId); + $has = $make->intersection($get->assistant_id, $merId); + return Elm::createForm(Route::buildUrl('merchantBroadcastAddAssistant', compact('id'))->build(), + [ + Elm::selectMultiple('assistant_id', '小助手')->options(function () use ($data) { + $options = []; + if ($data) { + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + } + return $options; + }) + ])->setTitle('修改小助手'); + } + + public function editAssistant(int $id, int $merId, array $data) + { + $make = app()->make(BroadcastAssistantRepository::class); + $make->existsAll($data, $merId); + Db::transaction(function() use($id, $data){ + $get = $this->dao->get($id); + $old = explode(',', $get->assistant_id); + $remove = array_diff($old, $data); + $add = array_diff($data, $old); + + $this->addAssistant($get->room_id, $add); + $this->removeAssistant($get->room_id, $remove); + $get->assistant_id = implode(',', $data); + $get->save(); + }); + + } + + public function removeAssistant($roomId, array $ids) + { + $make = app()->make(BroadcastAssistantRepository::class); + $data = $make->getSearch(['assistant_ids' => $ids])->select(); + + foreach ($data as $datum) { + MiniProgramService::create()->miniBroadcast()->removeAssistant($roomId,$datum->username); + } + } + + public function addAssistant($roomId, array $ids) + { + $make = app()->make(BroadcastAssistantRepository::class); + $data = $make->getSearch(['assistant_ids' => $ids])->column('username,nickname'); + $params = [ + 'roomId' => $roomId, + 'users' => $data + ]; + MiniProgramService::create()->miniBroadcast()->addAssistant($params); + } + + public function pushMessage(int $id) + { + $get = $this->dao->get($id); + $make = MiniProgramService::create()->miniBroadcast(); + $page_break = ''; + + do{ + $data = $make->getFollowers($page_break); + $restult = []; + if ($data['errcode'] !== 0) throw new ValidateException($data['errmsg']); + foreach ($data['followers'] as $datum) { + if ($datum['room_id'] == $get->room_id) { + $restult[] = $datum['openid']; + } + } + if ($restult) { + $make->pushMessage($get->room_id, $restult); + } + $page_break = $data['page_break'] ?? ''; + }while($page_break); + } +} diff --git a/app/common/repositories/store/coupon/StoreCouponIssueUserRepository.php b/app/common/repositories/store/coupon/StoreCouponIssueUserRepository.php new file mode 100644 index 00000000..271a9b25 --- /dev/null +++ b/app/common/repositories/store/coupon/StoreCouponIssueUserRepository.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\coupon; + + +use app\common\dao\store\coupon\StoreCouponIssueUserDao; +use app\common\repositories\BaseRepository; + +/** + * Class StoreCouponIssueUserRepository + * @package app\common\repositories\store\coupon + * @author xaboy + * @day 2020/6/1 + * @mixin StoreCouponIssueUserDao + */ +class StoreCouponIssueUserRepository extends BaseRepository +{ + /** + * StoreCouponIssueUserRepository constructor. + * @param StoreCouponIssueUserDao $dao + */ + public function __construct(StoreCouponIssueUserDao $dao) + { + $this->dao = $dao; + } + + public function issue($couponId, $uid) + { + return $this->dao->create([ + 'coupon_id' => $couponId, + 'uid' => $uid, + ]); + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->with(['coupon', 'user'])->page($page, $limit)->select(); + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/store/coupon/StoreCouponProductRepository.php b/app/common/repositories/store/coupon/StoreCouponProductRepository.php new file mode 100644 index 00000000..a751b317 --- /dev/null +++ b/app/common/repositories/store/coupon/StoreCouponProductRepository.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\coupon; + + +use app\common\dao\store\coupon\StoreCouponProductDao; +use app\common\repositories\BaseRepository; + +/** + * Class StoreCouponProductRepository + * @package app\common\repositories\store\coupon + * @author xaboy + * @day 2020/6/1 + * @mixin StoreCouponProductDao + */ +class StoreCouponProductRepository extends BaseRepository +{ + + /** + * StoreCouponProductRepository constructor. + * @param StoreCouponProductDao $dao + */ + public function __construct(StoreCouponProductDao $dao) + { + $this->dao = $dao; + } + + public function productList($coupon_id, $page, $limit) + { + $query = $this->dao->search(compact('coupon_id')); + $query->with(['product' => function ($query) { + $query->field('product_id,store_name,image,price,stock,sales'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/store/coupon/StoreCouponRepository.php b/app/common/repositories/store/coupon/StoreCouponRepository.php new file mode 100644 index 00000000..bcd007cf --- /dev/null +++ b/app/common/repositories/store/coupon/StoreCouponRepository.php @@ -0,0 +1,665 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\coupon; + + +use app\common\dao\store\coupon\StoreCouponDao; +use app\common\dao\store\coupon\StoreCouponProductDao; +use app\common\model\store\coupon\StoreCoupon; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\merchant\MerchantTypeRepository; +use app\common\repositories\user\UserRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +/** + * Class StoreCouponIssueRepository + * @package app\common\repositories\store\coupon + * @author xaboy + * @day 2020-05-13 + * @mixin StoreCouponDao + */ +class StoreCouponRepository extends BaseRepository +{ + + //店铺券 + const TYPE_STORE_ALL = 0; + //店铺商品券 + const TYPE_STORE_PRODUCT = 1; + //平台券 + const TYPE_PLATFORM_ALL = 10; + //平台分类券 + const TYPE_PLATFORM_CATE = 11; + //平台跨店券 + const TYPE_PLATFORM_STORE = 12; + + //获取方式 + const GET_COUPON_TYPE_RECEIVE = 0; + //消费满赠 + const GET_COUPON_TYPE_PAY_MEET = 1; + //新人券 + const GET_COUPON_TYPE_NEW = 2; + //买赠 + const GET_COUPON_TYPE_PAY = 3; + //首单赠送 + const GET_COUPON_TYPE_FIRST = 4; + //会员券 + const GET_COUPON_TYPE_SVIP = 5; + + /** + * @var StoreCouponDao + */ + protected $dao; + + /** + * StoreCouponIssueRepository constructor. + * @param StoreCouponDao $dao + */ + public function __construct(StoreCouponDao $dao) + { + $this->dao = $dao; + } + + /** + * @param int $merId + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-14 + */ + public function getList(?int $merId, array $where, $page, $limit) + { + $baseQuery = $this->dao->search($merId, $where)->with(['merchant' => function ($query) { + $query->field('mer_id,mer_name,is_trader'); + }]); + $count = $baseQuery->count($this->dao->getPk()); + $list = $baseQuery->page($page, $limit)->select(); + foreach ($list as $item) { + $item->append(['used_num', 'send_num']); + } + return compact('count', 'list'); + } + + public function sysLst(array $where, int $page, int $limit) + { + $baseQuery = $this->dao->search(0, $where); + $count = $baseQuery->count($this->dao->getPk()); + $list = $baseQuery->page($page, $limit)->select(); + foreach ($list as $item) { + $item->append(['used_num', 'send_num']); + } + return compact('count', 'list'); + } + public function sviplist(array $where,$uid) + { + $with = []; + if ($uid) $with['svipIssue'] = function ($query) use ($uid) { + $query->where('uid', $uid); + }; + $list = $this->validCouponQueryWithMerchant($where, $uid)->with($with)->setOption('field',[])->field('C.*')->select(); + return $list; + } + + public function apiList(array $where, int $page, int $limit, $uid) + { + $with = [ + 'merchant' => function ($query) { + $query->field('mer_id,mer_name,is_trader'); + }, + ]; + if ($uid) $with['issue'] = function ($query) use ($uid) { + $query->where('uid', $uid); + }; + $baseQuery = $this->validCouponQueryWithMerchant($where, $uid) + ->with($with); + $count = $baseQuery->count($this->dao->getPk()); + $list = $baseQuery->setOption('field',[])->field('C.*')->page($page, $limit)->select()->append(['ProductLst']); + $arr = []; + if ($where['is_pc']) { + foreach ($list as $item) { + if ($item['ProductLst']) { + $arr[] = $item; + } + if (count($arr) >= 3) break; + } + $list = $arr ?? $list ; + } + + return compact('count', 'list'); + } + /** + * @param array $data + * @author xaboy + * @day 2020/5/26 + */ + public function create1(array $data) + { + if (isset($data['total_count'])) $data['remain_count'] = $data['total_count']; + Db::transaction(function () use ($data) { + $products = array_column((array)$data['product_id'], 'id'); + unset($data['product_id']); + if ($data['type'] == 1 && !count($products)) + throw new ValidateException('请选择产品'); + $coupon = $this->dao->create($data); + if (!count($products)) return $coupon; + $lst = []; + foreach ($products as $product) { + $lst[] = [ + 'product_id' => (int)$product, + 'coupon_id' => $coupon->coupon_id + ]; + } + app()->make(StoreCouponProductDao::class)->insertAll($lst); + }); + } + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/26 + */ + public function cloneCouponForm($id) + { + $couponInfo = $this->dao->getWith($id, ['product'])->toArray(); + if ($couponInfo['is_timeout']) { + $couponInfo['range_date'] = [$couponInfo['start_time'], $couponInfo['end_time']]; + } + if ($couponInfo['coupon_type']) { + $couponInfo['use_start_time'] = [$couponInfo['use_start_time'], $couponInfo['use_end_time']]; + } + $couponInfo['product_id'] = []; + if (count($couponInfo['product'])) { + $productIds = array_column($couponInfo['product'], 'product_id'); + /** @var ProductRepository $make */ + $make = app()->make(ProductRepository::class); + $products = $make->productIdByImage($couponInfo['mer_id'], $productIds); + foreach ($products as $product) { + $couponInfo['product_id'][] = ['id' => $product['product_id'], 'src' => $product['image']]; + } + } + $couponInfo['use_type'] = $couponInfo['use_min_price'] > 0 ? 1 : 0; + return $this->form()->formData($couponInfo)->setTitle('复制优惠券'); + } + + /** + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/5/20 + */ + public function form() + { + return Elm::createForm(Route::buildUrl('merchantCouponCreate')->build(), [ + Elm::input('title', '优惠券名称')->required(), + Elm::radio('type', '优惠券类型', 0) + ->setOptions([ + ['value' => 0, 'label' => '店铺券'], + ['value' => 1, 'label' => '商品券'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::frameImages('product_id', '商品', '/' . config('admin.merchant_prefix') . '/setting/storeProduct?field=product_id') + ->width('680px')->height('480px')->modal(['modal' => false])->prop('srcKey', 'src')->required(), + ] + ], + ]), + Elm::number('coupon_price', '优惠券面值')->min(0)->precision(1)->required(), + Elm::radio('use_type', ' 使用门槛', 0) + ->setOptions([ + ['value' => 0, 'label' => '无门槛'], + ['value' => 1, 'label' => '有门槛'], + ])->appendControl(0, [ + Elm::hidden('use_min_price', 0) + ])->appendControl(1, [ + Elm::number('use_min_price', '优惠券最低消费')->min(0)->required(), + ]), + Elm::radio('coupon_type', '使用有效期', 0) + ->setOptions([ + ['value' => 0, 'label' => '天数'], + ['value' => 1, 'label' => '时间段'], + ])->control([ + [ + 'value' => 0, + 'rule' => [ + Elm::number('coupon_time', ' ', 0)->min(0)->required(), + ] + ], + [ + 'value' => 1, + 'rule' => [ + Elm::dateTimeRange('use_start_time', ' ')->required(), + ] + ], + ]), + Elm::radio('is_timeout', '领取时间', 0)->options([['label' => '限时', 'value' => 1], ['label' => '不限时', 'value' => 0]]) + ->appendControl(1, [Elm::dateTimeRange('range_date', ' ')->placeholder('不填为永久有效')]), + Elm::radio('send_type', '获取方式', 0)->setOptions([ + ['value' => 0, 'label' => '领取'], +// ['value' => 1, 'label' => '消费满赠'], + ['value' => 2, 'label' => '新人券'], + ['value' => 3, 'label' => '赠送券'] + ])->appendControl(1, [Elm::number('full_reduction', '满赠金额', 0)->min(0)->placeholder('赠送优惠券的最低消费金额')]), + Elm::radio('is_limited', '是否限量', 0)->options([['label' => '限量', 'value' => 1], ['label' => '不限量', 'value' => 0]]) + ->appendControl(1, [Elm::number('total_count', '发布数量', 0)->min(0)]), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]), + ])->setTitle('发布优惠券'); + } + + public function receiveCoupon($id, $uid) + { + $coupon = $this->dao->validCoupon($id, $uid); + if (!$coupon) + throw new ValidateException('优惠券失效'); + + if (!is_null($coupon['issue'])) + throw new ValidateException('优惠券已领取'); + $this->sendCoupon($coupon, $uid,StoreCouponUserRepository::SEND_TYPE_RECEIVE); + } + + public function receiveSvipCounpon($id,$uid) + { + $coupon = $this->dao->validSvipCoupon($id, $uid); + if (!$coupon) + throw new ValidateException('优惠券失效'); + + if (!is_null($coupon['svipIssue'])) + throw new ValidateException('优惠券已领取'); + $this->sendCoupon($coupon, $uid,StoreCouponUserRepository::SEND_TYPE_RECEIVE); + } + + public function sendCoupon(StoreCoupon $coupon, $uid, $type) + { + event('user.coupon.send.before', compact('coupon', 'uid', 'type')); + Db::transaction(function () use ($uid, $type, $coupon) { + $this->preSendCoupon($coupon, $uid, $type); + app()->make(StoreCouponIssueUserRepository::class)->issue($coupon['coupon_id'], $uid); + if ($coupon->is_limited) { + $coupon->remain_count--; + $coupon->save(); + } + }); + event('user.coupon.send', compact('coupon', 'uid', 'type')); + event('user.coupon.send.' . $type, compact('coupon', 'uid', 'type')); + } + + public function preSendCoupon(StoreCoupon $coupon, $uid, $type = 'send') + { + $data = $this->createData($coupon, $uid, $type); + return app()->make(StoreCouponUserRepository::class)->create($data); + } + + public function createData(StoreCoupon $coupon, $uid, $type = 'send') + { + $data = [ + 'uid' => $uid, + 'coupon_title' => $coupon['title'], + 'coupon_price' => $coupon['coupon_price'], + 'use_min_price' => $coupon['use_min_price'], + 'type' => $type, + 'coupon_id' => $coupon['coupon_id'], + 'mer_id' => $coupon['mer_id'] + ]; + if ($coupon['send_type'] == self::GET_COUPON_TYPE_SVIP) { + $data['start_time'] = date('Y-m-d 00:00:00',time()); + $firstday = date('Y-m-01', time()); + $data['end_time'] = date('Y-m-d 23:59:59', strtotime("$firstday +1 month -1 day")); + } else { + if ($coupon['coupon_type'] == 1) { + $data['start_time'] = $coupon['use_start_time']; + $data['end_time'] = $coupon['use_end_time']; + } else { + $data['start_time'] = date('Y-m-d H:i:s'); + $data['end_time'] = date('Y-m-d H:i:s', strtotime("+ {$coupon['coupon_time']}day")); + } + } + return $data; + } + + /** + * TODO 优惠券发送费多用户 + * @param $uid + * @param $id + * @author Qinii + * @day 2020-06-19 + */ + public function sendCouponByUser($uid, $id) + { + foreach ($uid as $item) { + $coupon = $this->dao->validCoupon($id, $item); + if (!$coupon || !is_null($coupon['issue'])) + continue; + if ($coupon->is_limited && 0 == $coupon->remain_count) + continue; + $this->sendCoupon($coupon, $item,StoreCouponUserRepository::SEND_TYPE_RECEIVE); + } + } + + public function updateForm(int $merId, int $id) + { + $data = $this->dao->getWhere(['mer_id' => $merId, 'coupon_id' => $id]); + if (!$data) throw new ValidateException('数据不存在'); + + $form = Elm::createForm(Route::buildUrl('systemCouponUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::input('title', '优惠券名称', $data['title'])->required(), + ]); + return $form->setTitle('编辑优惠券名称'); + } + + + public function sysForm() + { + return Elm::createForm(Route::buildUrl('systemCouponCreate')->build(), [ + Elm::input('title', '优惠券名称')->required(), + Elm::radio('type', '优惠券类型', 10) + ->setOptions([ + ['value' => self::TYPE_PLATFORM_ALL, 'label' => '通用券'], + ['value' => self::TYPE_PLATFORM_CATE, 'label' => '品类券'], + ['value' => self::TYPE_PLATFORM_STORE, 'label' => '跨店券'], + ])->control([ + [ + 'value' => self::TYPE_PLATFORM_CATE, + 'rule' => [ + Elm::cascader('cate_ids', '选择品类')->options(function (){ + return app()->make(StoreCategoryRepository::class)->getTreeList(0, 1); + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false, 'multiple' => true]]) + ] + ], + [ + 'value' => self::TYPE_PLATFORM_STORE, + 'rule' => [ + Elm::radio('mer_type', '选择商户',2) + ->setOptions([ + ['value' => 1, 'label' => '分类筛选'], + ['value' => 2, 'label' => '指定店铺'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::select('is_trader', '商户类别')->options([ + ['value' => '', 'label' => '全部'], + ['value' => 1, 'label' => '自营'], + ['value' => 0, 'label' => '非自营'], + ]), + Elm::select('category_id', '商户分类')->options(function (){ + $options = app()->make(MerchantCategoryRepository::class)->allOptions(); + $options = array_merge([['value' => '', 'label' => '全部']],$options); + return $options; + }), + Elm::select('type_id', '店铺类型')->options(function (){ + $options = app()->make(MerchantTypeRepository::class)->getOptions(); + return array_merge([['value' => '', 'label' => '全部']],$options); + }) + ] + ], + [ + 'value' => 2, + 'rule' => [ + Elm::frameImages('mer_ids', '选择商户', '/' . config('admin.admin_prefix') . '/setting/crossStore?field=mer_ids') + ->width('680px') + ->height('480px') + ->modal(['modal' => false]) + ->prop('srcKey', 'src') + ->required(), + ] + ], + ]), + + + ] + ], + ]), + Elm::number('coupon_price', '优惠券面值')->min(0)->precision(1)->required(), + Elm::radio('use_type', ' 使用门槛', 0) + ->setOptions([ + ['value' => 0, 'label' => '无门槛'], + ['value' => 1, 'label' => '有门槛'], + ])->appendControl(0, [ + Elm::hidden('use_min_price', 0) + ])->appendControl(1, [ + Elm::number('use_min_price', '优惠券最低消费')->min(0)->required(), + ]), + + Elm::radio('send_type', '获取方式', 0)->setOptions([ + ['value' => self::GET_COUPON_TYPE_RECEIVE, 'label' => '领取'], + ['value' => self::GET_COUPON_TYPE_NEW, 'label' => '新人券'], + ['value' => self::GET_COUPON_TYPE_SVIP, 'label' => '付费会员券'], + ])->control([ + [ + 'value' => self::GET_COUPON_TYPE_RECEIVE, + 'rule' => [ + Elm::radio('coupon_type', '使用有效期', 0) + ->setOptions([ + ['value' => 0, 'label' => '天数'], + ['value' => 1, 'label' => '时间段'], + ])->control([ + [ + 'value' => 0, + 'rule' => [ + Elm::number('coupon_time', ' ', 0)->min(0)->required(), + ] + ], + [ + 'value' => 1, + 'rule' => [ + Elm::dateTimeRange('use_start_time', ' ')->required(), + ] + ], + ]), + Elm::radio('is_timeout', '领取时间', 0)->options([['label' => '限时', 'value' => 1], ['label' => '不限时', 'value' => 0]]) + ->appendControl(1, [Elm::dateTimeRange('range_date', ' ')->placeholder('不填为永久有效')]), + ] + ], + [ + 'value' => self::GET_COUPON_TYPE_NEW, + 'rule' => [ + Elm::radio('coupon_type', '使用有效期', 0) + ->setOptions([ + ['value' => 0, 'label' => '天数'], + ['value' => 1, 'label' => '时间段'], + ])->control([ + [ + 'value' => 0, + 'rule' => [ + Elm::number('coupon_time', ' ', 0)->min(0)->required(), + ] + ], + [ + 'value' => 1, + 'rule' => [ + Elm::dateTimeRange('use_start_time', ' ')->required(), + ] + ], + ]), + Elm::radio('is_timeout', '领取时间', 0)->options([['label' => '限时', 'value' => 1], ['label' => '不限时', 'value' => 0]]) + ->appendControl(1, [Elm::dateTimeRange('range_date', ' ')->placeholder('不填为永久有效')]), + ] + ], + ])->appendControl(1, [ + Elm::number('full_reduction', '满赠金额', 0)->min(0)->placeholder('赠送优惠券的最低消费金额') + ])->appendRule('suffix', [ + 'type' => 'div', + 'style' => ['color' => '#999999'], + 'domProps' => [ + 'innerHTML' =>'会员优惠券创建成功后会自动发送给创建时间之后的新付费会员;之后每月1日零点自动发送给所有付费会员;在创建优惠券之前已成为付费会员的用户可在会员中心手动领取优惠券', + ] + ]), + Elm::radio('is_limited', '是否限量', 0)->options([['label' => '限量', 'value' => 1], ['label' => '不限量', 'value' => 0]]) + ->appendControl(1, [Elm::number('total_count', '发布数量', 0)->min(0)]), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]), + ])->setTitle('发布优惠券'); + } + + + public function create($data) + { + if (isset($data['total_count'])) $data['remain_count'] = $data['total_count']; + $productType = 0; + $products = []; + switch ($data['type']) { + case 1: //商品 + $products = array_column((array)$data['product_id'], 'id'); + unset($data['product_id']); + if (!count($products)) throw new ValidateException('请选择产品'); + break; + case 11: //商品分类 + $products = $data['cate_ids']; + unset($data['cate_ids']); + if (!count($products)) throw new ValidateException('请选择产品分类'); + $productType = 1; + break; + case 12: //商户 + if ($data['mer_type'] == 1) { + $where = [ + 'type_id' => $data['type_id'], + 'is_trader' => $data['is_trader'], + 'category_id' => $data['category_id'], + ]; + $products = app()->make(MerchantRepository::class)->search($where)->column('mer_id'); + if (!count($products)) throw new ValidateException('选择条件下无商户'); + } else { + $products = array_column((array)$data['mer_ids'], 'id'); + if (!count($products)) throw new ValidateException('请选择商户'); + } + $productType = 2; + break; + } + unset( + $data['product_id'], + $data['cate_ids'], + $data['is_trader'], + $data['mer_type'], + $data['category_id'], + $data['mer_ids'] + ); + Db::transaction(function () use ($data, $products, $productType) { + $coupon = $this->dao->create($data); + if (!count($products)) return $coupon; + $lst = []; + foreach ($products as $product) { + $lst[] = [ + 'product_id'=> (int)$product, + 'coupon_id' => $coupon->coupon_id, + ]; + } + app()->make(StoreCouponProductDao::class)->insertAll($lst); + }); + } + + + public function cloneSysCouponForm($id) + { + $couponInfo = $this->dao->getWith($id, ['product'])->toArray(); + if ($couponInfo['is_timeout']) { + $couponInfo['range_date'] = [$couponInfo['start_time'], $couponInfo['end_time']]; + } + if ($couponInfo['coupon_type']) { + $couponInfo['use_start_time'] = [$couponInfo['use_start_time'], $couponInfo['use_end_time']]; + } + $couponInfo['product_id'] = []; + if (count($couponInfo['product'])) { + if ($couponInfo['type'] == 11) { + foreach ($couponInfo['product'] as $product) { + $couponInfo['cate_ids'][] = $product['product_id']; + } + } else { + $productIds = array_column($couponInfo['product'], 'product_id'); + $make = app()->make(MerchantRepository::class); + $products = $make->merIdByImage($productIds); + foreach ($products as $product) { + $couponInfo['mer_ids'][] = ['id' => $product['mer_id'], 'src' => $product['mer_avatar']]; + } + } + } + $couponInfo['use_type'] = $couponInfo['use_min_price'] > 0 ? 1 : 0; + unset($couponInfo['product']); + return $this->sysForm()->formData($couponInfo)->setTitle('复制优惠券'); + } + + public function getProductList(int $id,int $page,int $limit) + { + $res = $this->dao->get($id); + $productRepository = app()->make(StoreCouponProductRepository::class); + $ids = $productRepository->search(['coupon_id' => $id])->column('product_id'); + $count = 0; + $list = []; + switch ($res['type']) { + case 11: //品类 + if (empty($ids)) throw new ValidateException('品类信息不存在'); + $storeCategoryRepository = app()->make(StoreCategoryRepository::class); + $cateId = $storeCategoryRepository->selectChildrenId($ids); + $cateId = array_merge($cateId, $ids); + $query = app()->make(ProductRepository::class)->getSearch([])->whereIn('cate_id', $cateId); + $field = 'product_id,store_name,image,stock,price,sales,cate_id'; + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[])->field($field)->select(); + break; + case 12: //商户 + if (empty($ids)) throw new ValidateException('商户信息不存在'); + $make = app()->make(MerchantRepository::class); + $field = 'mer_id,category_id,type_id,mer_name,mer_phone,is_trader'; + $with = ['merchantType','merchantCategory']; + $query = $make->search([])->whereIn($make->getPk(),$ids)->with($with); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[])->field($field)->select(); + break; + default : + break; + } + return compact('count', 'list'); + } + + public function sendSvipCoupon() + { + $data = ['mark' => [], 'is_all'=> '', 'search' => '',]; + $uids = app()->make(UserRepository::class)->search(['is_svip' => 1])->column('uid'); + $isMake = app()->make(StoreCouponIssueUserRepository::class); + $senMake = app()->make(StoreCouponSendRepository::class); + $couponIds = $this->dao->validCouponQuery(null,StoreCouponRepository::GET_COUPON_TYPE_SVIP)->column('coupon_id'); + if ($couponIds && $uids) { + foreach ($couponIds as $item) { + $issUids = $isMake->getSearch([])->whereMonth('create_time')->whereIn('uid',$uids)->column('uid'); + $uids_ = array_values(array_diff($uids,$issUids)); + $data['coupon_id'] = $item; + $data['uid'] = $uids_; + if (!empty($data['uid'])) return $senMake->create($data,0); + } + } + + } +} diff --git a/app/common/repositories/store/coupon/StoreCouponSendRepository.php b/app/common/repositories/store/coupon/StoreCouponSendRepository.php new file mode 100644 index 00000000..b502b80b --- /dev/null +++ b/app/common/repositories/store/coupon/StoreCouponSendRepository.php @@ -0,0 +1,105 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\coupon; + + +use app\common\dao\store\coupon\StoreCouponSendDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserMerchantRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\MerchantSendCouponJob; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Queue; + +/** + * @mixin StoreCouponSendDao + */ +class StoreCouponSendRepository extends BaseRepository +{ + public function __construct(StoreCouponSendDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with([ + 'coupon' => function($query) { + $query->field('coupon_id,type'); + } + ]); + $count = $query->count(); + $list = $query->setOption('field', [])->field('B.*,A.coupon_num,A.create_time,A.status as send_status, A.mark,A.coupon_send_id') + ->append(['useCount', 'used_num'])->page($page, $limit)->order('coupon_send_id DESC')->select(); + return compact('count', 'list'); + } + + public function create($data, $merId) + { + $query = null; + $coupon = app()->make(StoreCouponRepository::class)->getWhere(['mer_id' => $merId, 'coupon_id' => $data['coupon_id'], 'is_del' => 0]); + if (!$coupon) { + throw new ValidateException('优惠券不存在'); + } + + if ($merId){ + $userMerchantRepository = app()->make(UserMerchantRepository::class); + $where = ['mer_id' => $merId]; + $field = 'A.uid'; + } else { + $where = []; + $userMerchantRepository = app()->make(UserRepository::class); + $field = 'uid'; + } + + if ($data['is_all']) { + $query = $userMerchantRepository->search($where + $data['search']); + } else { + $query = $userMerchantRepository->search($where + ['uids' => $data['uid']]); + } + + $uid = $query->column($field); + $uTotal = count($uid); + if (!$uTotal) { + throw new ValidateException('请选择用户'); + } + if ($coupon['is_limited'] && $coupon->remain_count < $uTotal) { + throw new ValidateException('该优惠券可领取数不足' . $uTotal); + } + + return Db::transaction(function () use ($uid, $merId, $data, $coupon, $uTotal) { + $search = $data['mark']; + if($coupon['is_limited']){ + $coupon->remain_count -= $uTotal; + } + $send = $this->dao->create([ + 'mer_id' => $merId, + 'coupon_id' => $coupon->coupon_id, + 'coupon_num' => $uTotal, + 'status' => 0, + 'mark' => [ + 'type' => $data['is_all'], + 'search' => count($search) ? $search : null + ] + ]); + $coupon->save(); + Cache::store('file')->set('_send_coupon' . $send->coupon_send_id, $uid); + Queue::push(MerchantSendCouponJob::class, $send->coupon_send_id); + return $send; + }); + } + +} diff --git a/app/common/repositories/store/coupon/StoreCouponUserRepository.php b/app/common/repositories/store/coupon/StoreCouponUserRepository.php new file mode 100644 index 00000000..55a06924 --- /dev/null +++ b/app/common/repositories/store/coupon/StoreCouponUserRepository.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\coupon; + + +use app\common\dao\store\coupon\StoreCouponUserDao; +use app\common\repositories\BaseRepository; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class StoreCouponUserRepository + * @package app\common\repositories\store\coupon + * @author xaboy + * @day 2020-05-14 + * @mixin StoreCouponUserDao + */ +class StoreCouponUserRepository extends BaseRepository +{ + + //获取方式(receive:自己领取 send:后台发送 give:满赠 new:新人 buy:买赠送) + const SEND_TYPE_BUY = 'buy'; + const SEND_TYPE_RECEIVE = 'receive'; + const SEND_TYPE_SEND = 'send'; + const SEND_TYPE_GIVE = 'give'; + const SEND_TYPE_NEW = 'new'; + /** + * @var StoreCouponUserDao + */ + protected $dao; + + /** + * StoreCouponUserRepository constructor. + * @param StoreCouponUserDao $dao + */ + public function __construct(StoreCouponUserDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/3 + */ + public function userList(array $where, $page, $limit) + { + if ($page == 1) { + $this->dao->failCoupon(); + } + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->with(['coupon' => function ($query) { + $query->field('coupon_id,type,send_type'); + }, 'merchant' => function ($query) { + $query->field('mer_id,mer_name,mer_avatar'); + }])->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/3 + */ + public function getList(array $where, $page, $limit) + { + if ($page == 1) { + $this->dao->failCoupon(); + } + $query = $this->dao->search($where)->with([ + 'user' => function ($query) { + $query->field('avatar,uid,nickname,user_type'); + }, + 'coupon' => function ($query) { + $query->field('coupon_id,type'); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + +} diff --git a/app/common/repositories/store/order/MerchantReconciliationOrderRepository.php b/app/common/repositories/store/order/MerchantReconciliationOrderRepository.php new file mode 100644 index 00000000..7236af40 --- /dev/null +++ b/app/common/repositories/store/order/MerchantReconciliationOrderRepository.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\order; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\order\MerchantReconciliationOrderDao as dao; + +class MerchantReconciliationOrderRepository extends BaseRepository +{ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + public function getIds($where) + { + return $this->dao->search($where)->column('order_id'); + } +} diff --git a/app/common/repositories/store/order/MerchantReconciliationRepository.php b/app/common/repositories/store/order/MerchantReconciliationRepository.php new file mode 100644 index 00000000..0b73a9d5 --- /dev/null +++ b/app/common/repositories/store/order/MerchantReconciliationRepository.php @@ -0,0 +1,316 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\order; + +use app\common\model\store\order\MerchantReconciliationOrder; +use app\common\model\system\merchant\Merchant; +use app\common\repositories\BaseRepository; +use app\common\dao\store\order\MerchantReconciliationDao as dao; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\system\admin\AdminRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\services\SwooleTaskService; +use think\exception\ValidateException; +use think\facade\Db; +use FormBuilder\Factory\Elm; +use think\facade\Route; + +class MerchantReconciliationRepository extends BaseRepository +{ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + + public function getWhereCountById($id) + { + $where = ['reconciliation_id' => $id,'status' => 2]; + return $this->dao->getWhereCount($where) > 0 ; + } + + public function merWhereCountById($id,$merId) + { + $where = ['reconciliation_id' => $id,'mer_id' => $merId,'is_accounts' => 0,'status' => 0]; + return ($this->dao->getWhereCount($where) > 0) ; + } + + /** + * TODO 列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-15 + */ + public function getList($where,$page,$limit) + { + $query = $this->dao->search($where)->with([ + 'merchant' => function($query){ + $query->field('mer_id,mer_name'); + }, + 'admin' =>function($query){ + $query->field('admin_id,real_name'); + }]); + $count = $query->count(); + $list = $query->page($page,$limit)->select()->append(['charge'])->each(function($item){ + if($item->type == 1) return $item->price = '-'.$item->price; + }); + + return compact('count','list'); + } + + + /** + * TODO 创建对账单 + * @param $id + * @param $data + * @author Qinii + * @day 2020-06-15 + */ + public function create(int $id, array $data) + { + $orderMake = app()->make(StoreOrderRepository::class); + $refundMake = app()->make(StoreRefundOrderRepository::class); + + $bank = merchantConfig($id,'bank'); + $bank_name = merchantConfig($id,'bank_name'); + $bank_number = merchantConfig($id,'bank_number'); + $bank_address = merchantConfig($id,'bank_address'); + if( !$bank || !$bank_name || !$bank_number || !$bank_address ) + throw new ValidateException('商户未填写银行卡信息'); + + $order_ids = $data['order_ids']; + $refund_order_ids = $data['refund_order_ids']; + if($data['order_type']) { //全选 + $order_ids = $orderMake->search([ + 'date' => $data['date'], + 'mer_id' => $id, + 'reconciliation_type' => 0, + 'paid' => 1, + 'order_id' + ], null + )->whereNotIn('order_id', $data['order_out_ids'])->column('order_id'); + } + if($data['refund_type']){ //全选 + $refund_order_ids = $refundMake->search([ + 'date' => $data['date'], + 'mer_id' => $id, + 'reconciliation_type' => 0, + 'status' => 3 + ])->whereNotIn('refund_order_id',$data['refund_out_ids'])->column('refund_order_id'); + } + if(is_array($order_ids) && (count($order_ids) < 1) && is_array($refund_order_ids) && (count($refund_order_ids) < 1)){ + throw new ValidateException('没有数据可对账'); + } + $compute = $this->compute($id,$order_ids,$refund_order_ids); + $createData = [ + 'status' => 0, + 'mer_id' => $id, + 'is_accounts' => 0, + 'mer_admin_id' => 0, + 'bank' => $bank, + 'bank_name' => $bank_name, + 'bank_number' => $bank_number, + 'bank_address' => $bank_address, + 'admin_id' => $data['adminId'], + 'price' => round($compute['price'],2), + 'order_price' => round($compute['order_price'],2), + 'refund_price' => round($compute['refund_price'],2), + //'refund_rate' => round($compute['refund_rate'],2), + 'order_rate' => round($compute['order_rate'],2), + 'order_extension' => round($compute['order_extension'],2), + 'refund_extension' => round($compute['refund_extension'],2), + ]; + + Db::transaction(function()use($order_ids,$refund_order_ids,$orderMake,$refundMake,$createData){ + $res = $this->dao->create($createData); + $orderMake->updates($order_ids,['reconciliation_id' => $res['reconciliation_id']]); + $refundMake->updates($refund_order_ids,['reconciliation_id' => $res['reconciliation_id']]); + $this->reconciliationOrder($order_ids,$refund_order_ids,$res['reconciliation_id']); + + SwooleTaskService::merchant('notice', [ + 'type' => 'accoubts', + 'data'=>[ + 'title' => '新对账', + 'message' => '您有一条新的对账单', + 'id' => $res['reconciliation_id'] + ] + ], $createData['mer_id']); + }); + } + + /** + * TODO 计算对账单金额 + * @param $merId + * @param $order_ids + * @param $refund_order_ids + * @return array + * @author Qinii + * @day 2020-06-23 + */ + public function compute($merId,$order_ids,$refund_order_ids) + { + $order_price = $refund_price = $order_extension = $refund_extension = $order_rate = $refund_rate =0; + $orderMake = app()->make(StoreOrderRepository::class); + $refundMake = app()->make(StoreRefundOrderRepository::class); + + foreach($order_ids as $item){ + if(!$order = $orderMake->getWhere(['order_id' => $item,'mer_id' => $merId,'paid' => 1])) + throw new ValidateException('订单信息不存在或状态错误'); + + if($order['reconciliation_id']) throw new ValidateException('订单重复提交'); + + //(实付金额 - 一级佣金 - 二级佣金) * 抽成 + $commission_rate = ($order['commission_rate'] / 100); + //佣金 + $_order_extension = bcadd($order['extension_one'],$order['extension_two'],3); + $order_extension = bcadd($order_extension,$_order_extension,3); + + //手续费 = (实付金额 - 一级佣金 - 二级佣金) * 比例 + $_order_rate = bcmul(bcsub($order['pay_price'],$_order_extension,3),$commission_rate,3); + $order_rate = bcadd($order_rate,$_order_rate,3); + + //金额 + $_order_price = bcsub(bcsub($order['pay_price'],$_order_extension,3),$_order_rate,3); + $order_price = bcadd($order_price,$_order_price,3); + } + + foreach($refund_order_ids as $item){ + if(!$refundOrder = $refundMake->getWhere(['refund_order_id' => $item,'mer_id' => $merId,'status' => 3],'*',['order'])) + throw new ValidateException('退款订单信息不存在或状态错误'); + if($refundOrder['reconciliation_id']) throw new ValidateException('退款订单重复提交'); + + //退款金额 + 一级佣金 + 二级佣金 + $refund_commission_rate = ($refundOrder['order']['commission_rate'] / 100); + //佣金 + $_refund_extension = bcadd($refundOrder['extension_one'],$refundOrder['extension_two'],3); + $refund_extension = bcadd($refund_extension,$_refund_extension,3); + + //手续费 +// $_refund_rate = bcmul(bcsub($refundOrder['refund_price'],$_refund_extension,3),$refund_commission_rate,3); +// $refund_rate = bcadd($refund_rate,$_refund_rate,3); + + //金额 + $_refund_price = bcadd($refundOrder['refund_price'],$_refund_extension,3); + $refund_price = bcadd($refund_price,$_refund_price,3); + } + + $price = bcsub($order_price,$refund_price,3); + + return compact('price','refund_price','order_extension','refund_extension','order_price','order_rate'); + } + + /** + * TODO + * @param $order_ids + * @param $refund_ids + * @param $reconciliation_id + * @return mixed + * @author Qinii + * @day 2020-06-23 + */ + public function reconciliationOrder($order_ids,$refund_ids,$reconciliation_id) + { + $data = []; + foreach ($order_ids as $item){ + $data[] = [ + 'order_id' => $item, + 'reconciliation_id' => $reconciliation_id, + 'type' => 0, + ]; + } + foreach ($refund_ids as $item) { + $data[] = [ + 'order_id' => $item, + 'reconciliation_id' => $reconciliation_id, + 'type' => 1, + ]; + } + return app()->make(MerchantReconciliationOrderRepository::class)->insertAll($data); + } + + /** + * TODO 修改状态 + * @param $id + * @param $data + * @param $type + * @author Qinii + * @day 2020-06-15 + */ + public function switchStatus($id,$data) + { + Db::transaction(function()use($id,$data){ + if(isset($data['status']) && $data['status'] == 1){ + app()->make(StoreRefundOrderRepository::class)->reconciliationUpdate($id); + app()->make(StoreOrderRepository::class)->reconciliationUpdate($id); + } + $this->dao->update($id,$data); + }); + $res = $this->dao->get($id); + $mer = app()->make(MerchantRepository::class)->get($res['mer_id']); + if(isset($data['is_accounts']) && $data['is_accounts']){ +// $make = app()->make(FinancialRecordRepository::class); +// +// $make->dec([ +// 'order_id' => $id, +// 'order_sn' => $id, +// 'user_info' => $mer['mer_name'], +// 'user_id' => $res['mer_id'], +// 'financial_type' => 'sys_accoubts', +// 'number' => $res->price, +// ],0); +// +// $make->inc([ +// 'order_id' => $id, +// 'order_sn' => $id, +// 'user_info' => '总平台', +// 'user_id' => 0, +// 'financial_type' => 'mer_accoubts', +// 'number' => $res->price, +// ],$res->mer_id); + + SwooleTaskService::merchant('notice', [ + 'type' => 'accoubts', + 'data'=>[ + 'title' => '新对账打款', + 'message' => '您有一条新对账打款通知', + 'id' => $id + ] + ], $res['mer_id']); + } + } + + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('merchantReconciliationMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('mark', '备注',$data['mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + public function adminMarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantReconciliationMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('admin_mark', '备注',$data['admin_mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } +} diff --git a/app/common/repositories/store/order/PresellOrderRepository.php b/app/common/repositories/store/order/PresellOrderRepository.php new file mode 100644 index 00000000..6a1aff56 --- /dev/null +++ b/app/common/repositories/store/order/PresellOrderRepository.php @@ -0,0 +1,358 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\PresellOrderDao; +use app\common\model\store\order\PresellOrder; +use app\common\model\user\User; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductPresellSkuRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserMerchantRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\jobs\UserBrokerageLevelJob; +use crmeb\services\AlipayService; +use crmeb\services\CombinePayService; +use crmeb\services\MiniProgramService; +use crmeb\services\PayService; +use crmeb\services\WechatService; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Log; +use think\facade\Queue; + +/** + * Class PresellOrderRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/10/27 + * @mixin PresellOrderDao + */ +class PresellOrderRepository extends BaseRepository +{ + public function __construct(PresellOrderDao $dao) + { + $this->dao = $dao; + } + + public function createOrder($uid, $orderId, $price, $final_start_time, $final_end_time) + { + return $this->dao->create([ + 'uid' => $uid, + 'order_id' => $orderId, + 'final_start_time' => $final_start_time, + 'final_end_time' => $final_end_time, + 'pay_price' => $price, + 'presell_order_sn' => app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_PRESELL) + ]); + } + + public function pay($type, User $user, PresellOrder $order, $return_url = '', $isApp = false) + { + if ($type === 'balance') { + return $this->payBalance($user, $order); + } + + if (in_array($type, ['weixin', 'alipay'], true) && $isApp) { + $type .= 'App'; + } + event('order.presell.pay.before', compact('order', 'type', 'isApp')); + if (in_array($type, ['weixin', 'weixinApp', 'routine', 'h5', 'weixinQr'], true) && systemConfig('open_wx_combine')) { + $service = new CombinePayService($type, $order->getCombinePayParams()); + } else { + $service = new PayService($type, $order->getPayParams($type === 'alipay' ? $return_url : ''), 'presell'); + } + $config = $service->pay($user); + return app('json')->status($type, $config + ['order_id' => $order['presell_order_id']]); + } + + /** + * @param User $user + * @param PresellOrder $order + * @return mixed + * @author xaboy + * @day 2020/6/9 + */ + public function payBalance(User $user, PresellOrder $order) + { + if (!systemConfig('yue_pay_status')) + throw new ValidateException('未开启余额支付'); + if ($user['now_money'] < $order['pay_price']) + throw new ValidateException('余额不足,请更换支付方式'); + Db::transaction(function () use ($user, $order) { + $user->now_money = bcsub($user->now_money, $order['pay_price'], 2); + $user->save(); + $userBillRepository = app()->make(UserBillRepository::class); + $userBillRepository->decBill($user['uid'], 'now_money', 'presell', [ + 'link_id' => $order['presell_order_id'], + 'status' => 1, + 'title' => '支付预售尾款', + 'number' => $order['pay_price'], + 'mark' => '余额支付支付' . floatval($order['pay_price']) . '元购买商品', + 'balance' => $user->now_money + ]); + $this->paySuccess($order); + }); + return app('json')->status('success', '余额支付成功', ['order_id' => $order['presell_order_id']]); + } + + public function paySuccess(PresellOrder $order, $is_combine = 0, array $subOrders = []) + { + Db::transaction(function () use ($is_combine, $order, $subOrders) { + $time = date('Y-m-d H:i:s'); + $order->paid = 1; + $order->pay_time = $time; + if (isset($subOrders[$order->presell_order_sn])) { + $order->transaction_id = $subOrders[$order->presell_order_sn]['transaction_id']; + } + $order->is_combine = $is_combine; + $order->order->status = 0; + if ($order->order->order_type == 1) { + $order->order->verify_code = app()->make(StoreOrderRepository::class)->verifyCode(); + } + $order->order->save(); + $order->save(); + //订单记录 + $statusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '订单尾款支付成功', + 'change_type' => $statusRepository::ORDER_STATUS_PRESELL, + ]; + $i = 1; + $finance = []; + + $final_price = $order->order->pay_price; + $order_price = $order->pay_price; + $pay_price = bcadd($order_price, $final_price, 2); + $sn = app()->make(FinancialRecordRepository::class)->getSn(); + + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->presell_order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'presell', + 'financial_pm' => 1, + 'type' => 2, + 'number' => $order->pay_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . ($i++) + ]; + + $finance[] = [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'mer_presell', + 'financial_pm' => 1, + 'type' => 0, + 'number' => $pay_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . ($i++) + ]; + +// $pay_price = bcsub($pay_price, bcadd($order->order['extension_one'], $order->order['extension_two'], 3), 2); + if (isset($order->order->orderProduct[0]['cart_info']['presell_extension_one']) && $order->order->orderProduct[0]['cart_info']['presell_extension_one'] > 0) { + $order_price = bcsub($order_price, $order->order->orderProduct[0]['cart_info']['presell_extension_one'], 2); + } + if (isset($order->order->orderProduct[0]['cart_info']['presell_extension_two']) && $order->order->orderProduct[0]['cart_info']['presell_extension_two'] > 0) { + $order_price = bcsub($order_price, $order->order->orderProduct[0]['cart_info']['presell_extension_two'], 2); + } + if (isset($order->order->orderProduct[0]['cart_info']['final_extension_one']) && $order->order->orderProduct[0]['cart_info']['final_extension_one'] > 0) { + $final_price = bcsub($final_price, $order->order->orderProduct[0]['cart_info']['final_extension_one'], 2); + } + if (isset($order->order->orderProduct[0]['cart_info']['final_extension_two']) && $order->order->orderProduct[0]['cart_info']['final_extension_two'] > 0) { + $final_price = bcsub($final_price, $order->order->orderProduct[0]['cart_info']['final_extension_two'], 2); + } + if ($order->order['extension_one'] > 0) { + $finance[] = [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'brokerage_one', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order->order['extension_one'], + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . ($i++) + ]; + } + + if ($order->order['extension_two'] > 0) { + $finance[] = [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'brokerage_two', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order->order['extension_two'], + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . ($i++) + ]; + } + + if ($order->order->commission_rate > 0) { + $commission_rate = ($order->order->commission_rate / 100); + $finalRatePrice = bcmul($final_price, $commission_rate, 2); + $orderRatePrice = bcmul($order_price, $commission_rate, 2); + $ratePrice = bcadd($finalRatePrice, $orderRatePrice, 2); + $finance[] = [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'presell_charge', + 'financial_pm' => 1, + 'type' => 1, + 'number' => $ratePrice, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . ($i++) + ]; +// $pay_price = bcsub($pay_price, $ratePrice, 2); + $order_price = bcsub($order_price, $orderRatePrice, 2); + $final_price = bcsub($final_price, $finalRatePrice, 2); + } + $finance[] = [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'presell_true', + 'financial_pm' => 1, + 'type' => 2, + 'number' => bcadd($order_price, $final_price, 2), + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . ($i++) + ]; + if (!$is_combine) { + app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'presell', $order->presell_order_id, !$order->order->groupOrder->is_combine ? bcadd($order_price, $final_price, 2) : $order_price); +// app()->make(MerchantRepository::class)->addMoney($order->mer_id, !$order->order->groupOrder->is_combine ? bcadd($order_price, $final_price, 2) : $order_price); + } else if (!$order->order->groupOrder->is_combine) { + app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'presell', $order->presell_order_id, $final_price); +// app()->make(MerchantRepository::class)->addMoney($order->mer_id, $final_price); + } + + if ($is_combine) { + $storeOrderProfitsharingRepository = app()->make(StoreOrderProfitsharingRepository::class); + $storeOrderProfitsharingRepository->create([ + 'profitsharing_sn' => $storeOrderProfitsharingRepository->getOrderSn(), + 'order_id' => $order->order->order_id, + 'mer_id' => $order->mer_id, + 'transaction_id' => $order->transaction_id ?? '', + 'profitsharing_price' => $order->pay_price, + 'profitsharing_mer_price' => $order_price, + 'type' => $storeOrderProfitsharingRepository::PROFITSHARING_TYPE_PRESELL, + ]); + } + app()->make(UserRepository::class)->update($order->uid, [ + 'pay_price' => Db::raw('pay_price+' . $order->pay_price), + ]); + app()->make(ProductPresellSkuRepository::class)->incCount($order->order->orderProduct[0]['activity_id'], $order->order->orderProduct[0]['product_sku'], 'two_pay'); + app()->make(UserMerchantRepository::class)->updatePayTime($order->uid, $order->mer_id, $order->pay_price, false); + app()->make(FinancialRecordRepository::class)->insertAll($finance); + $statusRepository->createUserLog($orderStatus); + }); + if ($order->user->spread_uid) { + Queue::push(UserBrokerageLevelJob::class, ['uid' => $order->user->spread_uid, 'type' => 'spread_money', 'inc' => $order->pay_price]); + } + Queue::push(UserBrokerageLevelJob::class, ['uid' => $order->uid, 'type' => 'pay_money', 'inc' => $order->pay_price]); + event('order.presll.paySuccess', compact('order')); + } + + public function cancel($id) + { + $order = $this->dao->getWhere(['presell_order_id' => $id, 'paid' => 0]); + if (!$order) return; + //订单记录 + $statusRepository = app()->make(StoreOrderStatusRepository::class); + + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '预售订单超时支付自动关闭', + 'change_type' => $statusRepository::ORDER_STATUS_PRESELL_CLOSE, + ]; + event('order.presll.fail.before', compact('order')); + $productRepository = app()->make(ProductRepository::class); + Db::transaction(function () use ($productRepository, $order, $orderStatus,$statusRepository) { + $statusRepository->createSysLog($orderStatus); + $order->order->status = 11; + $order->status = 0; + $order->save();+ + $order->order->save(); + foreach ($order->order->orderProduct as $cart) { + $productRepository->orderProductIncStock($order->order, $cart); + } + if ($order->order->firstProfitsharing && $order->order->firstProfitsharing->profitsharing_price > 0) { + $make = app()->make(FinancialRecordRepository::class); + $sn = $make->getSn(); + $financial = [[ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'presell_charge', + 'financial_pm' => 1, + 'type' => 1, + 'number' => bcsub($order->order->firstProfitsharing->profitsharing_price, $order->order->firstProfitsharing->profitsharing_mer_price, 2), + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . '0' + ], [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'mer_presell', + 'financial_pm' => 1, + 'type' => 0, + 'number' => $order->order->firstProfitsharing->profitsharing_mer_pric, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . '1' + ], [ + 'order_id' => $order->order->order_id, + 'order_sn' => $order->order->order_sn, + 'user_info' => $order->user->nickname, + 'user_id' => $order->uid, + 'financial_type' => 'presell_true', + 'financial_pm' => 1, + 'type' => 2, + 'number' => $order->order->firstProfitsharing->profitsharing_mer_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $sn . '2' + ]]; + $make->insertAll($financial); + try { + app()->make(StoreOrderProfitsharingRepository::class)->profitsharing($order->order->firstProfitsharing); + } catch (\Exception $e) { + Log::info('预售定金分账失败' . $order->order_id . $e->getMessage()); + } + } + }); + event('order.presll.fail', compact('order')); + } +} diff --git a/app/common/repositories/store/order/StoreCartRepository.php b/app/common/repositories/store/order/StoreCartRepository.php new file mode 100644 index 00000000..b06c516a --- /dev/null +++ b/app/common/repositories/store/order/StoreCartRepository.php @@ -0,0 +1,130 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreCartDao; +use app\common\model\store\product\Product; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\coupon\StoreCouponProductRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\product\ProductRepository; +use think\exception\ValidateException; + +/** + * Class StoreCartRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/5/30 + * @mixin StoreCartDao + */ +class StoreCartRepository extends BaseRepository +{ + /** + * StoreCartRepository constructor. + * @param StoreCartDao $dao + */ + public function __construct(StoreCartDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $uid + * @return array + * @author Qinii + */ + public function getList($user,$product_type) + { + $res = $this->dao->getAll($user->uid,$product_type)->append(['checkCartProduct', 'UserPayCount', 'ActiveSku', 'attrValue', 'attr','spu']); + $make = app()->make(ProductRepository::class); + $res->map(function ($item) use ($make) { + $item['attr'] = $make->detailAttr($item['attr']); + }); + return $this->checkCartList($res, $user->uid, $user); + } + + public function checkCartList($res, $hasCoupon = 0, $user = null) + { + $arr = $fail = []; + $product_make = app()->make(ProductRepository::class); + $svip_status = ($user && $user->is_svip > 0 && systemConfig('svip_switch_status')) ? true : false; + foreach ($res as $item) { + if (!$item['checkCartProduct']) { + $item['product'] = $product_make->getFailProduct($item['product_id']); + $fail[] = $item; + } else { + $merchantData = $item['merchant']->append(['openReceipt'])->toArray(); + unset($item['merchant']); + $coupon_make = app()->make(StoreCouponRepository::class); + if (!isset($arr[$item['mer_id']])) { + if ($hasCoupon) + $merchantData['hasCoupon'] = $coupon_make->validMerCouponExists($item['mer_id'], $hasCoupon); + $arr[$item['mer_id']] = $merchantData; + } + if ($hasCoupon && !$arr[$item['mer_id']]['hasCoupon']) { + $couponIds = app()->make(StoreCouponProductRepository::class)->productByCouponId([$item['product']['product_id']]); + $arr[$item['mer_id']]['hasCoupon'] = count($couponIds) ? $coupon_make->validProductCouponExists([$item['product']['product_id']], $hasCoupon) : 0; + } + if ($svip_status && $item['product']['show_svip_price']) { + $item['productAttr']['show_svip_price'] = true; + $item['productAttr']['org_price'] = $item['productAttr']['price']; + $item['productAttr']['price'] = $item['productAttr']['svip_price']; + } else { + $item['productAttr']['show_svip_price'] = false; + } + $arr[$item['mer_id']]['list'][] = $item; + } + } + $list = array_values($arr); + return compact('list', 'fail'); + } + + /** + * 获取单条购物车信息 + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return mixed + */ + public function getOne(int $id,int $uid) + { + $where = [$this->dao->getPk() => $id,'is_del'=>0,'is_fail'=>0,'is_new'=>0,'is_pay'=>0,'uid' => $uid]; + return ($this->dao->getWhere($where)); + } + + /** + * 查看相同商品的sku是存在 + * @param $sku + * @param $uid + * @author Qinii + */ + public function getCartByProductSku($sku,$uid,$product_type=0) + { + $where = ['is_del'=>0,'is_fail'=>0,'is_new'=>0,'is_pay'=>0,'uid' => $uid,'product_type' => $product_type,'product_attr_unique' => $sku]; + return ($this->dao->getWhere($where)); + } + + + public function getProductById($productId) + { + $where = [ + 'is_del' =>0, + 'is_new'=>0, + 'is_pay'=>0, + 'product_id'=>$productId + ]; + return $this->dao->getWhereCount($where); + } +} diff --git a/app/common/repositories/store/order/StoreCartRepository.php.bak b/app/common/repositories/store/order/StoreCartRepository.php.bak new file mode 100644 index 00000000..1600c150 --- /dev/null +++ b/app/common/repositories/store/order/StoreCartRepository.php.bak @@ -0,0 +1,130 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreCartDao; +use app\common\model\store\product\Product; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\coupon\StoreCouponProductRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\product\ProductRepository; +use think\exception\ValidateException; + +/** + * Class StoreCartRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/5/30 + * @mixin StoreCartDao + */ +class StoreCartRepository extends BaseRepository +{ + /** + * StoreCartRepository constructor. + * @param StoreCartDao $dao + */ + public function __construct(StoreCartDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $uid + * @return array + * @author Qinii + */ + public function getList($user) + { + $res = $this->dao->getAll($user->uid)->append(['checkCartProduct', 'UserPayCount', 'ActiveSku', 'attrValue', 'attr','spu']); + $make = app()->make(ProductRepository::class); + $res->map(function ($item) use ($make) { + $item['attr'] = $make->detailAttr($item['attr']); + }); + return $this->checkCartList($res, $user->uid, $user); + } + + public function checkCartList($res, $hasCoupon = 0, $user = null) + { + $arr = $fail = []; + $product_make = app()->make(ProductRepository::class); + $svip_status = ($user && $user->is_svip > 0 && systemConfig('svip_switch_status')) ? true : false; + foreach ($res as $item) { + if (!$item['checkCartProduct']) { + $item['product'] = $product_make->getFailProduct($item['product_id']); + $fail[] = $item; + } else { + $merchantData = $item['merchant']->append(['openReceipt'])->toArray(); + unset($item['merchant']); + $coupon_make = app()->make(StoreCouponRepository::class); + if (!isset($arr[$item['mer_id']])) { + if ($hasCoupon) + $merchantData['hasCoupon'] = $coupon_make->validMerCouponExists($item['mer_id'], $hasCoupon); + $arr[$item['mer_id']] = $merchantData; + } + if ($hasCoupon && !$arr[$item['mer_id']]['hasCoupon']) { + $couponIds = app()->make(StoreCouponProductRepository::class)->productByCouponId([$item['product']['product_id']]); + $arr[$item['mer_id']]['hasCoupon'] = count($couponIds) ? $coupon_make->validProductCouponExists([$item['product']['product_id']], $hasCoupon) : 0; + } + if ($svip_status && $item['product']['show_svip_price']) { + $item['productAttr']['show_svip_price'] = true; + $item['productAttr']['org_price'] = $item['productAttr']['price']; + $item['productAttr']['price'] = $item['productAttr']['svip_price']; + } else { + $item['productAttr']['show_svip_price'] = false; + } + $arr[$item['mer_id']]['list'][] = $item; + } + } + $list = array_values($arr); + return compact('list', 'fail'); + } + + /** + * 获取单条购物车信息 + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return mixed + */ + public function getOne(int $id,int $uid) + { + $where = [$this->dao->getPk() => $id,'is_del'=>0,'is_fail'=>0,'is_new'=>0,'is_pay'=>0,'uid' => $uid]; + return ($this->dao->getWhere($where)); + } + + /** + * 查看相同商品的sku是存在 + * @param $sku + * @param $uid + * @author Qinii + */ + public function getCartByProductSku($sku,$uid) + { + $where = ['is_del'=>0,'is_fail'=>0,'is_new'=>0,'is_pay'=>0,'uid' => $uid,'product_type' => 0,'product_attr_unique' => $sku]; + return ($this->dao->getWhere($where)); + } + + + public function getProductById($productId) + { + $where = [ + 'is_del' =>0, + 'is_new'=>0, + 'is_pay'=>0, + 'product_id'=>$productId + ]; + return $this->dao->getWhereCount($where); + } +} diff --git a/app/common/repositories/store/order/StoreGroupOrderRepository.php b/app/common/repositories/store/order/StoreGroupOrderRepository.php new file mode 100644 index 00000000..c608d65a --- /dev/null +++ b/app/common/repositories/store/order/StoreGroupOrderRepository.php @@ -0,0 +1,179 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreGroupOrderDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\CancelGroupOrderJob; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\model\Relation; + +/** + * Class StoreGroupOrderRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/8 + * @mixin StoreGroupOrderDao + */ +class StoreGroupOrderRepository extends BaseRepository +{ + /** + * StoreGroupOrderRepository constructor. + * @param StoreGroupOrderDao $dao + */ + public function __construct(StoreGroupOrderDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->search($where); + $count = $query->count(); + $list = $query->with(['orderList' => function (Relation $query) { + $query->field('order_id,group_order_id,activity_type,pay_price')->with(['orderProduct','presellOrder']); + }])->page($page, $limit)->order('create_time DESC')->select(); + return compact('count', 'list'); + } + + /** + * @param $uid + * @param $id + * @return array|\think\Model|null + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function detail($uid, $id, $flag = true) + { + return $this->search(['paid' => 0, 'uid' => $uid])->where('group_order_id', $id)->with(['orderList' => function (Relation $query) use ($flag) { + $query->when($flag, function ($query) { + $query->field('order_id,group_order_id,mer_id,order_sn,activity_type,pay_price,order_extend,order_type,is_virtual'); + })->with(['merchant' => function ($query) use ($flag) { + $flag && $query->field('mer_id,mer_name'); + }, 'orderProduct', 'presellOrder']); + }])->find(); + } + + public function status($uid, $id) + { + return $this->search(['uid' => $uid])->where('group_order_id', $id)->append(['give_coupon'])->find(); + } + + /** + * @param $id + * @return array|\think\Model|null + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function getCancelDetail($id) + { + return $this->search(['paid' => 0, 'is_del' => 1])->where('group_order_id', $id)->with(['orderList.orderProduct'])->find(); + } + + /** + * @param $id + * @param null $uid + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function cancel($id, $uid = null) + { + $groupOrder = $this->search(['paid' => 0, 'uid' => $uid ?? ''])->where('group_order_id', $id)->with(['orderList'])->find(); + if (!$groupOrder) + throw new ValidateException('订单不存在'); + if ($groupOrder['paid'] != 0) + throw new ValidateException('订单状态错误,无法删除'); + //TODO 关闭订单 + Db::transaction(function () use ($groupOrder, $id, $uid) { + $groupOrder->is_del = 1; + $orderStatus = []; + + //退回积分 + if ($groupOrder->integral > 0) { + $make = app()->make(UserRepository::class); + $make->update($groupOrder->uid, ['integral' => Db::raw('integral+' . $groupOrder->integral)]); + app()->make(UserBillRepository::class)->incBill($groupOrder->uid, 'integral', 'cancel', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 1, + 'title' => '退回积分', + 'number' => $groupOrder['integral'], + 'mark' => '订单自动关闭,退回' . intval($groupOrder->integral) . '积分', + 'balance' => $make->get($groupOrder->uid)->integral + ]); + } + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + foreach ($groupOrder->orderList as $order) { + if ($order->activity_type == 3 && $order->presellOrder) { + $order->presellOrder->status = 0; + $order->presellOrder->save(); + } + $order->is_del = 1; + $order->save(); + $orderStatus[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '取消订单' . ($uid ? '' : '[自动]'), + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CANCEL, + 'uid' => 0, + 'nickname' => '系统', + 'user_type' => $storeOrderStatusRepository::U_TYPE_SYSTEM, + ]; + } + $groupOrder->save(); + $storeOrderStatusRepository->batchCreateLog($orderStatus); + }); + Queue::push(CancelGroupOrderJob::class, $id); + } + + public function isVipCoupon($groupOrder) + { + if (!$groupOrder->coupon_id) { + return false; + } + $cid = app()->make(StoreCouponUserRepository::class)->query(['coupon_user_id' => $groupOrder->coupon_id])->value('coupon_id'); + if ($cid) { + return app()->make(StoreCouponRepository::class)->query(['coupon_id' => $cid])->value('send_type') === StoreCouponRepository::GET_COUPON_TYPE_SVIP; + } + return false; + } +} diff --git a/app/common/repositories/store/order/StoreImportDeliveryRepository.php b/app/common/repositories/store/order/StoreImportDeliveryRepository.php new file mode 100644 index 00000000..2ad86b37 --- /dev/null +++ b/app/common/repositories/store/order/StoreImportDeliveryRepository.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\order; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\order\StoreImportDeliveryDao; + +class StoreImportDeliveryRepository extends BaseRepository +{ + /** + * StoreGroupOrderRepository constructor. + * @param StoreImportDeliveryDao $dao + */ + public function __construct(StoreImportDeliveryDao $dao) + { + $this->dao = $dao; + } + + public function getList($where,$page, $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count','list'); + } +} diff --git a/app/common/repositories/store/order/StoreImportRepository.php b/app/common/repositories/store/order/StoreImportRepository.php new file mode 100644 index 00000000..351210c7 --- /dev/null +++ b/app/common/repositories/store/order/StoreImportRepository.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\order; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\order\StoreImportDao; + +class StoreImportRepository extends BaseRepository +{ + /** + * StoreGroupOrderRepository constructor. + * @param StoreImportDeliveryDao $dao + */ + public function __construct(StoreImportDao $dao) + { + $this->dao = $dao; + } + + public function getList($where,$page,$limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page,$limit)->order('create_time DESC')->select(); + + return compact('count','list'); + } + + public function create(int $merId, string $import, int $type = 1) + { + $data = [ + 'import_type' => $import, + 'count' => 0, + 'success' => 0, + 'mer_id' => $merId, + 'status' => 0, + 'type' => $type + ]; + + return $this->dao->create($data); + } +} diff --git a/app/common/repositories/store/order/StoreOrderCreateRepository.php b/app/common/repositories/store/order/StoreOrderCreateRepository.php new file mode 100644 index 00000000..5fef10af --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderCreateRepository.php @@ -0,0 +1,1360 @@ +uid; + $userIntegral = $user->integral; + $key = md5(json_encode(compact('cartId', 'takes', 'useCoupon', 'useIntegral', 'addressId'))) . $uid; + app()->make(StoreCouponUserRepository::class)->failCoupon(); + $address = null; + //验证地址 + if ($addressId) { + $addressRepository = app()->make(UserAddressRepository::class); + $address = $addressRepository->getWhere(['uid' => $uid, 'address_id' => $addressId]); + } + + $storeCartRepository = app()->make(StoreCartRepository::class); + $res = $storeCartRepository->checkCartList($storeCartRepository->cartIbByData($cartId, $uid, $address), 0, $user); + $merchantCartList = $res['list']; + $fail = $res['fail']; + + //检查购物车失效数据 + if (count($fail)) { + if ($fail[0]['is_fail']) + throw new ValidateException('[已失效]' . mb_substr($fail[0]['product']['store_name'],0,10).'...'); + if (in_array($fail[0]['product_type'], [1, 2, 3]) && !$fail[0]['userPayCount']) { + throw new ValidateException('[超出限购数]' . mb_substr($fail[0]['product']['store_name'],0,10).'...'); + } + throw new ValidateException('[已失效]' . mb_substr($fail[0]['product']['store_name'],0,10).'...'); + } + + $svip_status = $user->is_svip > 0 && systemConfig('svip_switch_status') == '1'; + $svip_integral_rate = $svip_status ? app()->make(MemberinterestsRepository::class)->getSvipInterestVal(MemberinterestsRepository::HAS_TYPE_PAY) : 0; + //订单活动类型 + $order_type = 0; + //虚拟订单 + $order_model = 0; + //虚拟订单自定义数据 + $order_extend = []; + //检查商品类型, 活动商品只能单独购买 + foreach ($merchantCartList as $merchantCart) { + foreach ($merchantCart['list'] as $cart) { + if ($cart['product_type']==0) { + if ($cart['product']['once_min_count'] > 0 && $cart['product']['once_min_count'] > $cart['cart_num']) + throw new ValidateException('[低于起购数:'.$cart['product']['once_min_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...'); + if ($cart['product']['pay_limit'] == 1 && $cart['product']['once_max_count'] < $cart['cart_num']) + throw new ValidateException('[超出单次限购数:'.$cart['product']['once_max_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...'); + if ($cart['product']['pay_limit'] == 2){ + //如果长期限购 + //已购买数量 + $count = app()->make(StoreOrderRepository::class)->getMaxCountNumber($cart['uid'],$cart['product_id']); + if (($cart['cart_num'] + $count) > $cart['product']['once_max_count']) + throw new ValidateException('[超出限购总数:'. $cart['product']['once_max_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...'); + } + } + + if ($cart['product_type'] > 0) $order_type = $cart['product_type']; + if ($cart['product_type']<=97 &&$cart['product_type'] > 0 && (($cart['product_type'] != 10 && count($merchantCart['list']) != 1) || count($merchantCartList) != 1)) { + throw new ValidateException('活动商品必须单独购买'); + } + if ($cart['product']['type'] && (count($merchantCart['list']) != 1 || count($merchantCartList) != 1)) { + throw new ValidateException('虚拟商品必须单独购买'); + } + $order_model = $cart['product']['type']; + if ($cart['product']['extend']) { + $order_extend = json_decode($cart['product']['extend'], true); + } + } + } + unset($merchantCart, $cart); + + $order_price = 0; + $total_true_price = 0; + $order_total_price = 0; + $order_coupon_price = 0; + $noDeliver = false; + $presellType = 0; + $fn = []; + $enabledPlatformCoupon = !$order_type; + $order_total_postage = 0; + + + //套餐订单 + if ($order_type == 10) { + app()->make(StoreDiscountRepository::class) + ->check($merchantCartList[0]['list'][0]['source_id'], $merchantCartList[0]['list'], $user); + } + + $orderDeliveryStatus = true; + $order_svip_discount = 0; + // 循环计算每个店铺的订单数据 + foreach ($merchantCartList as &$merchantCart) { + $postageRule = []; + $total_price = 0; + $total_num = 0; + $valid_total_price = 0; + $postage_price = 0; + $product_price = []; + $final_price = 0; + $down_price = 0; + $total_svip_discount = 0; + + //是否自提 + $isTake = in_array($merchantCart['mer_id'], $takes ?? []); + +// if (!$createOrder && !$isTake) { +// $isTake = count($merchantCart['delivery_way']) == 1 && $merchantCart['delivery_way'][0] == '1'; +// } + + $merTake = in_array('1', $merchantCart['delivery_way'], true); + $merDelivery = (!$merchantCart['delivery_way'] || !count($merchantCart['delivery_way']) || in_array('2', $merchantCart['delivery_way'], true)); + $_merTake = $merTake; + $_merDelivery = $merDelivery; + $deliveryStatus = true; + if ($createOrder && $isTake && !$merTake) { + $deliveryStatus = false; +// throw new ValidateException('[仅支持快递配送]' . $merchantCart['mer_name']); + } + $product_cart = []; + + foreach ($merchantCart['list'] as $k => $cart) { + //获取订单类型, 活动商品单次只能购买一个 + if ($cart['product']['delivery_way']) { + $delivery_way = explode(',', $cart['product']['delivery_way']); + $proTake = in_array('1', $delivery_way, true); + $merTake = $merTake && $proTake; + $proDelivery = (!count($delivery_way) || in_array('2', $delivery_way, true)); + $merDelivery = $merDelivery && $proDelivery; + $merchantCart['list'][$k]['allow_take'] = $proTake; + $merchantCart['list'][$k]['allow_delivery'] = $proDelivery; + } else { + $merchantCart['list'][$k]['allow_take'] = $_merTake; + $merchantCart['list'][$k]['allow_delivery'] = $_merDelivery; + } + if ($createOrder && $isTake && !$merTake) { + $deliveryStatus = false; +// throw new ValidateException('[仅支持快递配送]' . $cart['product']['store_name']); + } + } + if (!$merDelivery && !$merTake) { + $deliveryStatus = false; +// throw new ValidateException('部分商品配送方式不一致,请单独下单'); + } + if ($deliveryStatus && !$isTake && ($merDelivery || $merTake)) { + $isTake = $merDelivery ? 0 : 1; + } + //加载商品数据 + foreach ($merchantCart['list'] as $cart) { + //预售订单 + if ($cart['product_type'] == 2) { + $cart->append(['productPresell', 'productPresellAttr']); + //助力订单 + } else if ($cart['product_type'] == 3) { + $cart->append(['productAssistAttr']); + //拼团订单 + } else if ($cart['product_type'] == 4) { + $cart->append(['activeSku']); + //套餐订单 + } else if ($cart['product_type'] == 10) { + $cart->append(['productDiscount', 'productDiscountAttr']); + } + + //如果是预售订单 获取预售的订单的首款,尾款预售类型 + if ($order_type == 2) { + $final_price = bcadd($final_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['final_price'], 2), 2); + $presellType = $cart['productPresell']['presell_type']; + if ($presellType == 2) + $down_price = bcadd($down_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['down_price'], 2), 2); + } + } + unset($cart); + + $enabledCoupon = !($order_type && $order_type != 2); + + //只有预售和普通商品可以用优惠券 + if (!$enabledCoupon) { + $merchantCart['coupon'] = []; + } + $svip_coupon_merge = merchantConfig($merchantCart['mer_id'], 'svip_coupon_merge'); + $use_svip = 0; + //获取运费规则和统计商品数据 + foreach ($merchantCart['list'] as &$cart) { + + if ($cart['product_type'] == 10 && $cart['productDiscountAttr']) { + $cart['productAttr']['price'] = $cart['productDiscountAttr']['active_price']; + $cart['productAttr']['show_svip_price'] = false; + } + + if ($cart['cart_num'] <= 0) { + throw new ValidateException('购买商品数必须大于0'); + } + $svip_discount = 0; + + $price = bcmul($cart['cart_num'], $this->cartByPrice($cart), 2); + $cart['total_price'] = $price; + $cart['postage_price'] = 0; + $cart['svip_discount'] = 0; + $total_price = bcadd($total_price, $price, 2); + $total_num += $cart['cart_num']; + $_price = bcmul($cart['cart_num'], $this->cartByCouponPrice($cart), 2); + $cart['svip_coupon_merge'] = 1; + if ($cart['productAttr']['show_svip_price'] && !$cart['product_type']) { + $svip_discount = max(bcmul($cart['cart_num'], bcsub($cart['productAttr']['org_price'] ?? 0, $cart['productAttr']['price'], 2), 2), 0); + if ($svip_coupon_merge != '1') { + $_price = 0; + $cart['svip_coupon_merge'] = 0; + } + $use_svip = 1; + } + $valid_total_price = bcadd($valid_total_price, $_price, 2); + $cart['allow_price'] = $_price; + $temp1 = $cart['product']['temp']; + $cart['temp_number'] = 0; + $total_svip_discount = bcadd($total_svip_discount, $svip_discount, 2); + $cart['svip_discount'] = $svip_discount; + + if (!isset($product_cart[$cart['product_id']])) + $product_cart[$cart['product_id']] = [$cart['cart_id']]; + else + $product_cart[$cart['product_id']][] = $cart['cart_id']; + + if ($_price > 0) { + $product_price[$cart['product_id']] = bcadd($product_price[$cart['product_id']] ?? 0, $_price, 2); + } + + if (!$temp1) continue; + + $number = $this->productByTempNumber($cart); + if ($number <= 0) continue; + $cart['temp_number'] = $number; + + if ($order_model || !$temp1 || ($cart['product_type'] == 10 && $cart['productDiscount']['free_shipping'])) { + continue; + } + + $free = $temp1['free'][0] ?? null; + $region = $temp1['region'][0] ?? null; + + if (!$cart['product']['delivery_free'] && !$isTake && (!$address || !$cart['product']['temp'] || ($temp1['undelivery'] == 2 && !$free && (!$region || !$region['city_id'])))) { + $cart['undelivered'] = true; + $noDeliver = true; + continue; + } + $cart['undelivered'] = (!$isTake) && $temp1['undelivery'] == 1 && isset($temp1['undelives']); + $fn[] = function () use ($cart) { + unset($cart['product']['temp']); + }; + + if ($cart['undelivered']) { + $noDeliver = true; + continue; + } + if ($cart['product']['delivery_free']) { + continue; + } + $tempId = $cart['product']['temp_id']; + if (!isset($postageRule[$tempId])) { + $postageRule[$tempId] = [ + 'free' => null, + 'region' => null, + 'cart' => [], + 'price' => 0, + ]; + } + + $freeRule = $postageRule[$tempId]['free']; + $regionRule = $postageRule[$tempId]['region']; + $postageRule[$tempId]['cart'][] = $cart['cart_id']; + $postageRule[$tempId]['price'] = bcadd($postageRule[$tempId]['price'], $cart['price'], 2); + + if ($temp1['appoint'] && $free) { + if (!isset($freeRule)) { + $freeRule = $free; + $freeRule['cart_price'] = 0; + $freeRule['cart_number'] = 0; + } + $freeRule['cart_number'] = bcadd($freeRule['cart_number'], $number, 2); + $freeRule['cart_price'] = bcadd($freeRule['cart_price'], $price, 2); + } + + if ($region) { + if (!isset($regionRule)) { + $regionRule = $region; + $regionRule['cart_price'] = 0; + $regionRule['cart_number'] = 0; + } + $regionRule['cart_number'] = bcadd($regionRule['cart_number'], $number, 2); + $regionRule['cart_price'] = bcadd($regionRule['cart_price'], $price, 2); + } + $postageRule[$tempId]['free'] = $freeRule; + $postageRule[$tempId]['region'] = $regionRule; + } + unset($cart); + + if (!$isTake) { + //计算运费 + foreach ($postageRule as $item) { + $freeRule = $item['free']; + if ($freeRule && $freeRule['cart_number'] >= $freeRule['number'] && $freeRule['cart_price'] >= $freeRule['price']) + continue; + if (!$item['region']) continue; + $regionRule = $item['region']; + $postage = $regionRule['first_price']; + if ($regionRule['first'] > 0 && $regionRule['cart_number'] > $regionRule['first']) { + $num = ceil(bcdiv(bcsub($regionRule['cart_number'], $regionRule['first'], 2), $regionRule['continue'], 2)); + $postage = bcadd($postage, bcmul($num, $regionRule['continue_price'], 2), 2); + } + $postage_price = bcadd($postage_price, $postage, 2); + $cartNum = count($item['cart']); + //计算每个商品的运费比例 + foreach ($merchantCart['list'] as &$cart) { + if (in_array($cart['cart_id'], $item['cart'])) { + if (--$cartNum) { + $cart['postage_price'] = bcmul($postage, bcdiv($cart['temp_number'], $regionRule['cart_number'], 3), 2); + $postage = bcsub($postage, $cart['postage_price'], 2); + } else { + $cart['postage_price'] = $postage; + } + } + } + unset($cart); + } + unset($item); + } + + $coupon_price = 0; + $use_coupon_product = []; + $use_store_coupon = 0; + + $useCouponFlag = isset($useCoupon[$merchantCart['mer_id']]); + $merCouponIds = (array)($useCoupon[$merchantCart['mer_id']] ?? []); + $merCouponIds = array_reverse($merCouponIds); + $sortIds = $merCouponIds; +// $all_coupon_product = []; + unset($defaultSort); + $defaultSort = []; + if (count($merCouponIds)) { + foreach ($merchantCart['coupon'] as &$item) { + $defaultSort[] = &$item; + if (!in_array($item['coupon_user_id'], $sortIds, true)) { + $sortIds[] = $item['coupon_user_id']; + } + } + unset($item); + usort($merchantCart['coupon'], function ($a, $b) use ($sortIds) { + return array_search($a['coupon_user_id'], $sortIds) > array_search($b['coupon_user_id'], $sortIds) ? 1 : -1; + }); + } + + //过滤不可用店铺优惠券 + foreach ($merchantCart['coupon'] as &$coupon) { + if (!$coupon['coupon']['type']) continue; + + $coupon['disabled'] = false; + $coupon['checked'] = false; + + if (count(array_intersect(array_column($coupon['product'], 'product_id'), array_keys($product_price))) == 0) { + $coupon['disabled'] = true; + continue; + } + if($svip_coupon_merge != '1' && $use_svip){ + $coupon['disabled'] = true; + continue; + } + $flag = false; + foreach ($coupon['product'] as $_product) { + if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) { + $flag = true; + break; + } + } + if (!$flag) { + $coupon['disabled'] = true; + } +// if (!$coupon['disabled']) { +// $all_coupon_product[] = $coupon['coupon_user_id']; +// } + } + + unset($coupon); + + //if ($useCouponFlag && count(array_diff($all_coupon_product, $use_coupon_product))) { + // throw new ValidateException('请选择有效的商品券'); + //} + //计算商品券金额 + foreach ($merchantCart['coupon'] as &$coupon) { + if (!$coupon['coupon']['type']) continue; + if ($coupon['disabled']) continue; + + foreach ($coupon['product'] as $_product) { + if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) { + if ($useCouponFlag) { + if (!in_array($coupon['coupon_user_id'], $merCouponIds) || isset($use_coupon_product[$_product['product_id']])) { + continue; + } + } else if (isset($use_coupon_product[$_product['product_id']])) { + continue; + } + $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2); + $use_coupon_product[$_product['product_id']] = $coupon; + $coupon['checked'] = true; + break; + } + } + unset($_product); + } + unset($coupon); + $pay_price = max(bcsub($valid_total_price, $coupon_price, 2), 0); + $_pay_price = $pay_price; + //计算店铺券 + foreach ($merchantCart['coupon'] as &$coupon) { + if ($coupon['coupon']['type']) continue; + $coupon['checked'] = false; + $coupon['disabled'] = $pay_price <= 0; + if ($use_store_coupon || $pay_price <= 0) continue; + if($svip_coupon_merge != '1' && $use_svip){ + $coupon['disabled'] = true; + continue; + } + //店铺券 + if ($valid_total_price >= $coupon['use_min_price']) { + if ($useCouponFlag) { + if (!in_array($coupon['coupon_user_id'], $merCouponIds)) { + continue; + } + } + $use_store_coupon = $coupon; + $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2); + $_pay_price = bcsub($_pay_price, $coupon['coupon_price'], 2); + $coupon['checked'] = true; + } else { + $coupon['disabled'] = true; + } + } + unset($coupon); + + $productCouponRate = []; + $storeCouponRate = null; + $useCouponIds = []; + //计算优惠占比 + foreach ($use_coupon_product as $productId => $coupon) { + $productCouponRate[$productId] = [ + 'rate' => $product_price[$productId] > 0 ? bcdiv($coupon['coupon_price'], $product_price[$productId], 4) : 1, + 'coupon_price' => $coupon['coupon_price'], + 'price' => $product_price[$productId] + ]; + $useCouponIds[] = $coupon['coupon_user_id']; + } + + if ($use_store_coupon) { + $storeCouponRate = [ + 'rate' => $pay_price > 0 ? bcdiv($use_store_coupon['coupon_price'], $pay_price, 4) : 1, + 'coupon_price' => $use_store_coupon['coupon_price'], + 'price' => $coupon_price + ]; + $useCouponIds[] = $use_store_coupon['coupon_user_id']; + } + + //计算单个商品实际支付金额 + foreach ($merchantCart['list'] as $_k => &$cart) { + $cartTotalPrice = bcmul($this->cartByPrice($cart), $cart['cart_num'], 2); + $_cartTotalPrice = $cartTotalPrice; + if (!$cart['product_type'] && $cartTotalPrice > 0) { + if (isset($productCouponRate[$cart['product_id']])) { + //计算每个商品优惠金额(商品券) + if ($productCouponRate[$cart['product_id']]['rate'] >= 1) { + $cartTotalPrice = 0; + } else { + array_pop($product_cart); + if (!count($product_cart)) { + $cartTotalPrice = bcsub($cartTotalPrice, $productCouponRate[$cart['product_id']]['coupon_price'], 2); + $productCouponRate[$cart['product_id']]['coupon_price'] = 0; + } else { + $couponPrice = bcmul($cartTotalPrice, $productCouponRate[$cart['product_id']]['rate'], 2); + $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2); + $productCouponRate[$cart['product_id']]['coupon_price'] = bcsub($productCouponRate[$cart['product_id']]['coupon_price'], $couponPrice, 2); + } + } + } + + //(店铺券) + if ($storeCouponRate && $cartTotalPrice > 0) { + if ($storeCouponRate['rate'] >= 1) { + $cartTotalPrice = 0; + } else { + if (count($merchantCart['list']) == $_k + 1) { + $cartTotalPrice = bcsub($cartTotalPrice, $storeCouponRate['coupon_price'], 2); + } else { + $couponPrice = bcmul($cartTotalPrice, $storeCouponRate['rate'], 2); + $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2); + $storeCouponRate['coupon_price'] = bcsub($storeCouponRate['coupon_price'], $couponPrice, 2); + } + } + } + } + + //单个商品实际支付金额 + $cart['coupon_price'] = bcsub($_cartTotalPrice, $cartTotalPrice, 2); + $cart['true_price'] = $cartTotalPrice; + } + unset($cart, $_k); + $total_true_price = bcadd($_pay_price, $total_true_price, 2); + if(count($merchantCartList) > 1 || count($merchantCart['list']) > 1){ + $orderDeliveryStatus = $orderDeliveryStatus && $deliveryStatus; + } + $merchantCart['order'] = [ + 'true_price' => $_pay_price, + 'platform_coupon_price' => 0, + 'valid_total_price' => $valid_total_price, + 'total_price' => $total_price, + 'final_price' => $final_price, + 'down_price' => $down_price, + 'coupon_price' => $coupon_price, + 'svip_coupon_merge' => $svip_coupon_merge, + 'postage_price' => $postage_price, + 'isTake' => $isTake, + 'total_num' => $total_num, + 'enabledCoupon' => $enabledCoupon, + 'useCouponIds' => $useCouponIds, + 'allow_take' => $merTake, + 'allow_delivery' => $merDelivery, + 'delivery_status' => $deliveryStatus, + 'svip_discount' => $total_svip_discount, + 'use_svip' => $use_svip, + ]; + $order_total_postage = bcadd($order_total_postage, $postage_price, 2); + $order_svip_discount = bcadd($total_svip_discount, $order_svip_discount, 2); + if (count($defaultSort)) { + $merchantCart['coupon'] = &$defaultSort; + } + } + unset($merchantCart); + + $usePlatformCouponId = $useCoupon[0] ?? 0; + $usePlatformCouponId = is_array($usePlatformCouponId) ? array_pop($usePlatformCouponId) : $usePlatformCouponId; + $usePlatformCouponFlag = isset($useCoupon[0]); + + foreach ($merchantCartList as &$merchantCart) { + if (!$merchantCart['order']['use_svip']) + continue; + $totalMergePrice = 0; + foreach ($merchantCart['list'] as &$cart) { + if (!$cart['svip_coupon_merge']) { + $totalMergePrice = bcadd($totalMergePrice, $cart['true_price'], 2); + $cart['allow_price'] = $cart['true_price']; + } + } + unset($cart); + if ($totalMergePrice > 0) { + $total_true_price = bcadd($total_true_price, $totalMergePrice, 2); + $merchantCart['order']['valid_total_price'] = bcadd($merchantCart['order']['valid_total_price'], $totalMergePrice, 2); + $merchantCart['order']['true_price'] = $merchantCart['order']['valid_total_price']; + } + } + unset($merchantCart); + + //计算平台券优惠金额 +// if ($total_true_price > 0) { + $StoreCouponUser = app()->make(StoreCouponUserRepository::class); + $platformCoupon = $StoreCouponUser->validUserPlatformCoupon($uid); + if ($enabledPlatformCoupon && count($platformCoupon)) { + + $catePriceLst = []; + $storePriceLst = []; + $_cartNum = 0; + + foreach ($merchantCartList as &$merchantCart) { + if ($merchantCart['order']['true_price'] <= 0) continue; + foreach ($merchantCart['list'] as &$cart) { + $_cartNum++; + if ($cart['product']['cate_id']) { + if (!isset($catePriceLst[$cart['product']['cate_id']])) { + $catePriceLst[$cart['product']['cate_id']] = ['price' => 0, 'cart' => []]; + } + $catePriceLst[$cart['product']['cate_id']]['price'] = bcadd($catePriceLst[$cart['product']['cate_id']]['price'], $cart['true_price']); + $catePriceLst[$cart['product']['cate_id']]['cart'][] = &$cart; + } + } + unset($cart); + $storePriceLst[$merchantCart['mer_id']] = [ + 'price' => $merchantCart['order']['true_price'], + 'num' => count($merchantCart['list']) + ]; + } + unset($merchantCart); + $flag = false; + $platformCouponRate = null; + + foreach ($platformCoupon as &$coupon) { + $coupon['checked'] = false; + //通用券 + if ($coupon['coupon']['type'] === StoreCouponRepository::TYPE_PLATFORM_ALL) { + $coupon['disabled'] = $total_true_price <= 0 || $coupon['use_min_price'] > $total_true_price; + if (!$platformCouponRate && !$coupon['disabled'] && !$flag && ((!$usePlatformCouponId && !$usePlatformCouponFlag) || $usePlatformCouponId == $coupon['coupon_user_id'])) { + $platformCouponRate = [ + 'id' => $coupon['coupon_user_id'], + 'type' => $coupon['coupon']['type'], + 'price' => $total_true_price, + 'coupon_price' => $coupon['coupon_price'], + 'use_count' => $_cartNum, + 'check' => function ($cart) { + return true; + } + ]; + $coupon['checked'] = true; + $flag = true; + } + //品类券 + } else if ($coupon['coupon']['type'] === StoreCouponRepository::TYPE_PLATFORM_CATE) { + $_price = 0; + $_use_count = 0; + $cateIds = $coupon['product']->column('product_id'); + $allCateIds = array_unique(array_merge(app()->make(StoreCategoryRepository::class)->allChildren($cateIds), $cateIds)); + $flag2 = true; + foreach ($allCateIds as $cateId) { + if (isset($catePriceLst[$cateId])) { + $_price = bcadd($catePriceLst[$cateId]['price'], $_price, 2); + $_use_count += count($catePriceLst[$cateId]['cart']); + $flag2 = false; + } + } + $coupon['disabled'] = $flag2 || $coupon['use_min_price'] > $_price; + //品类券可用 + if (!$platformCouponRate && !$coupon['disabled'] && !$flag && !$flag2 && ((!$usePlatformCouponId && !$usePlatformCouponFlag) || $usePlatformCouponId == $coupon['coupon_user_id'])) { + $platformCouponRate = [ + 'id' => $coupon['coupon_user_id'], + 'type' => $coupon['coupon']['type'], + 'price' => $_price, + 'use_cate' => $allCateIds, + 'coupon_price' => $coupon['coupon_price'], + 'use_count' => $_use_count, + 'check' => function ($cart) use ($allCateIds) { + return in_array($cart['product']['cate_id'], $allCateIds); + } + ]; + $coupon['checked'] = true; + $flag = true; + } + //跨店券 + } else if ($coupon['coupon']['type'] === StoreCouponRepository::TYPE_PLATFORM_STORE) { + $_price = 0; + $_use_count = 0; + $flag2 = true; + foreach ($coupon['product'] as $item) { + $merId = $item['product_id']; + if (isset($storePriceLst[$merId])) { + $_price = bcadd($storePriceLst[$merId]['price'], $_price, 2); + $_use_count += $storePriceLst[$merId]['num']; + $flag2 = false; + } + } + $coupon['disabled'] = $flag2 || $coupon['use_min_price'] > $_price; + //店铺券可用 + if (!$platformCouponRate && !$coupon['disabled'] && !$flag && !$flag2 && ((!$usePlatformCouponId && !$usePlatformCouponFlag) || $usePlatformCouponId == $coupon['coupon_user_id'])) { + $_merIds = $coupon['product']->column('product_id'); + $platformCouponRate = [ + 'id' => $coupon['coupon_user_id'], + 'type' => $coupon['coupon']['type'], + 'price' => $_price, + 'use_store' => $_merIds, + 'coupon_price' => $coupon['coupon_price'], + 'use_count' => $_use_count, + 'check' => function ($cart) use ($_merIds) { + return in_array($cart['mer_id'], $_merIds); + } + ]; + $coupon['checked'] = true; + $flag = true; + } + } + } + unset($coupon); + } +// } + + $usePlatformCouponId = 0; + $total_platform_coupon_price = 0; + //计算平台优惠券 + if (isset($platformCouponRate)) { + $_coupon_price = $platformCouponRate['coupon_price']; + foreach ($merchantCartList as &$merchantCart) { + $_price = 0; + foreach ($merchantCart['list'] as &$cart) { + if ($cart['true_price'] <= 0 || !$platformCouponRate['check']($cart)) continue; + + if ($platformCouponRate['use_count'] === 1) { + $couponPrice = min($platformCouponRate['coupon_price'], $cart['true_price']); + } else { + $couponPrice = min(bcmul($_coupon_price, bcdiv($cart['true_price'], $platformCouponRate['price'], 3), 2), $cart['true_price']); + } + $platformCouponRate['coupon_price'] = bcsub($platformCouponRate['coupon_price'], $couponPrice, 2); + $cart['true_price'] = bcsub($cart['true_price'], $couponPrice, 2); + $cart['platform_coupon_price'] = $couponPrice; + $platformCouponRate['use_count']--; + $_price = bcadd($couponPrice, $_price, 2); + } + unset($cart); + $merchantCart['order']['platform_coupon_price'] = $_price; + $merchantCart['order']['true_price'] = bcsub($merchantCart['order']['true_price'], $_price, 2); + $total_platform_coupon_price = bcadd($total_platform_coupon_price, $_price, 2); + } + $usePlatformCouponId = $platformCouponRate['id']; + unset($merchantCart); + } + + //积分配置 + $sysIntegralConfig = systemConfig(['integral_money', 'integral_status', 'integral_order_rate']); + $merIntegralFlag = false; + $order_total_integral = 0; + $order_total_integral_price = 0; + $order_total_give_integral = 0; + $allow_no_address = true; + + foreach ($merchantCartList as &$merchantCart) { + $merchantCart['take'] = [ + 'mer_integral_rate' => 0, + 'mer_integral_status' => 0, + ]; + $allow_no_address = $allow_no_address && $merchantCart['order']['isTake']; + foreach ($merchantCart['config'] as $config) { + $merchantCart['take'][$config['config_key']] = $config['value']; + } + $merIntegralConfig = $merchantCart['take']; + unset($merchantCart['config']); + $merIntegralConfig['mer_integral_rate'] = min(1, $merIntegralConfig['mer_integral_rate'] > 0 ? bcdiv($merIntegralConfig['mer_integral_rate'], 100, 4) : $merIntegralConfig['mer_integral_rate']); + $total_integral = 0; + $total_integral_price = 0; + $merIntegralFlag = $merIntegralFlag || ((bool)$merIntegralConfig['mer_integral_status']); + $integralFlag = $useIntegral && $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_money'] > 0 && $merIntegralConfig['mer_integral_status']; + + //计算积分抵扣 + foreach ($merchantCart['list'] as &$cart) { + //只有普通商品可以抵扣 + if ($cart['product_type'] == 0 && $integralFlag && $userIntegral > 0 && $merchantCart['order']['true_price'] > 0) { + $integralRate = $cart['product']['integral_rate']; + if ($integralRate < 0) { + $integralRate = $merIntegralConfig['mer_integral_rate']; + } else if($integralRate > 0){ + $integralRate = min(bcdiv($integralRate, 100, 4), 1); + } + if ($integralRate > 0) { + $productIntegralPrice = min(bcmul(bcmul($this->cartByPrice($cart), $cart['cart_num'], 2), $integralRate, 2), $cart['true_price']); + if ($productIntegralPrice > 0) { + $productIntegral = ceil(bcdiv($productIntegralPrice, $sysIntegralConfig['integral_money'], 3)); + if ($productIntegral <= $userIntegral) { + $userIntegral = bcsub($userIntegral, $productIntegral, 0); + //使用多少积分抵扣了多少金额 + $cart['integral'] = [ + 'use' => $productIntegral, + 'price' => $productIntegralPrice + ]; + } else { + $productIntegralPrice = bcmul($userIntegral, $sysIntegralConfig['integral_money'], 2); + //使用多少积分抵扣了多少金额 + $cart['integral'] = [ + 'use' => $userIntegral, + 'price' => $productIntegralPrice + ]; + $userIntegral = 0; + } + + $cart['true_price'] = bcsub($cart['true_price'], $cart['integral']['price'], 2); + $merchantCart['order']['true_price'] = bcsub($merchantCart['order']['true_price'], $cart['integral']['price'], 2); + + $total_integral_price = bcadd($total_integral_price, $cart['integral']['price'], 2); + $total_integral = bcadd($total_integral, $cart['integral']['use'], 0); + continue; + } + } + } + $cart['integral'] = null; + } + unset($cart); + $order_total_integral = bcadd($order_total_integral, $total_integral, 0); + $order_total_integral_price = bcadd($order_total_integral_price, $total_integral_price, 2); + + $_pay_price = $merchantCart['order']['true_price']; + $valid_total_price = $merchantCart['order']['valid_total_price']; + $total_price = $merchantCart['order']['total_price']; + $final_price = $merchantCart['order']['final_price']; + $down_price = $merchantCart['order']['down_price']; + $coupon_price = $merchantCart['order']['coupon_price']; + $postage_price = $merchantCart['order']['postage_price']; + + //计算订单商品金额 + $org_price = bcadd(bcsub($total_price, $valid_total_price, 2), max($_pay_price, 0), 2); + if ($presellType == 2) { + $org_price = max(bcsub($org_price, $final_price, 2), $down_price); + } + + //获取可优惠金额 + $coupon_price = min($coupon_price, bcsub($total_price, $down_price, 2)); + $order_coupon_price = bcadd($coupon_price, $order_coupon_price, 2); + + //计算订单金额 + if ($order_type != 2 || $presellType != 2) { + $pay_price = bcadd($postage_price, $org_price, 2); + } else { + $pay_price = $org_price; + } + + $giveIntegralFlag = $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_order_rate'] > 0; + $total_give_integral = 0; + //计算赠送积分, 只有普通商品赠送积分 + if ($giveIntegralFlag && !$order_type && $pay_price > 0) { + $total_give_integral = floor(bcmul($pay_price, $sysIntegralConfig['integral_order_rate'], 0)); + if ($total_give_integral > 0 && $svip_status && $svip_integral_rate > 0) { + $total_give_integral = bcmul($svip_integral_rate, $total_give_integral, 0); + } + } + $order_total_give_integral = bcadd($total_give_integral, $order_total_give_integral, 0); + + foreach ($fn as $callback) { + $callback(); + } + + $merchantCart['order']['order_type'] = $order_type; + $merchantCart['order']['total_give_integral'] = $total_give_integral; + $merchantCart['order']['total_integral_price'] = $total_integral_price; + $merchantCart['order']['total_integral'] = $total_integral; + $merchantCart['order']['org_price'] = $org_price; + $merchantCart['order']['pay_price'] = $pay_price; + $merchantCart['order']['coupon_price'] = $coupon_price; + + $order_price = bcadd($order_price, $pay_price, 2); + $order_total_price = bcadd($order_total_price, $total_price, 2); + } + unset($merchantCart); + + if ($order_model) { + $allow_no_address = false; + } + + foreach ($merchantCartList as &$merchantCart) { + foreach ($merchantCart['list'] as &$cart) { + $cart['total_price'] = bcadd($cart['total_price'], $cart['svip_discount'], 2); + } + unset($cart); + $merchantCart['order']['total_price'] = bcadd($merchantCart['order']['total_price'], $merchantCart['order']['svip_discount'], 2); + $order_total_price = bcadd($order_total_price, $merchantCart['order']['svip_discount'], 2); + } + unset($merchantCart); + + $status = ($address || $order_model || $allow_no_address) ? ($noDeliver ? 'noDeliver' : 'finish') : 'noAddress'; + $order = $merchantCartList; + $total_price = $order_total_price; + $openIntegral = $merIntegralFlag && !$order_type && $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_money'] > 0; + $total_coupon = bcadd($order_svip_discount, bcadd(bcadd($total_platform_coupon_price, $order_coupon_price, 2), $order_total_integral_price, 2), 2); + return compact( + 'order_type', + 'order_model', + 'order_extend', + 'order_total_postage', + 'order_price', + 'total_price', + 'platformCoupon', + 'enabledPlatformCoupon', + 'usePlatformCouponId', + 'order_total_integral', + 'order_total_integral_price', + 'order_total_give_integral', + 'order_svip_discount', + 'total_platform_coupon_price', + 'total_coupon', + 'order_coupon_price', + 'order', + 'status', + 'address', + 'openIntegral', + 'useIntegral', + 'key' + ) + ['allow_address' => !$allow_no_address, 'order_delivery_status' => $orderDeliveryStatus]; + } + + public function v2CreateOrder(int $pay_type, $user, array $cartId, array $extend, array $mark, array $receipt_data, array $takes = null, array $useCoupon = null, bool $useIntegral = false, int $addressId = null, array $post,int $product_type=0) + { + $uid = $user->uid; + $orderInfo = $this->v2CartIdByOrderInfo($user, $cartId, $takes, $useCoupon, $useIntegral, $addressId, true); + $order_model = $orderInfo['order_model']; + $order_extend = $orderInfo['order_extend']; + if (!$orderInfo['order_delivery_status']) { + throw new ValidateException('部分商品配送方式不一致,请单独下单'); + } + if ($orderInfo['order_price'] > 1000000) { + throw new ValidateException('支付金额超出最大限制'); + } + if ($orderInfo['status'] == 'noDeliver') throw new ValidateException('部分商品不支持该区域'); + if ($orderInfo['status'] == 'noAddress') throw new ValidateException('请选择地址'); + if (!$order_model && $orderInfo['allow_address']) { + if (!$orderInfo['address']) throw new ValidateException('请选择正确的收货地址'); + if (!$orderInfo['address']['province_id']) throw new ValidateException('请完善收货地址信息'); + $extend = []; + } else if (count($order_extend)) { + $extend = app()->make(OrderVirtualFieldValidate::class)->load($order_extend, $extend); + } else { + $extend = []; + } + $orderType = $orderInfo['order_type']; + if ($orderType && (count($orderInfo['order']) > 1 || ($orderType != 10 && count($orderInfo['order'][0]['list']) > 1))) { + throw new ValidateException('活动商品请单独购买'); + } + + $merchantCartList = $orderInfo['order']; + $cartSpread = 0; + $hasTake = false; + + foreach ($merchantCartList as $merchantCart) { + if ($merchantCart['order']['isTake']) { + $hasTake = true; + } + //检查发票状态 + if (isset($receipt_data[$merchantCart['mer_id']]) && !$merchantCart['openReceipt']) + throw new ValidateException('该店铺不支持开发票'); + + foreach ($merchantCart['list'] as $cart) { + if (!$cartSpread && $cart['spread_id']) { + $cartSpread = $cart['spread_id']; + } + } + } + if ($hasTake) { + app()->make(UserAddressValidate::class)->scene('take')->check($post); + } + + if ($cartSpread) { + app()->make(UserRepository::class)->bindSpread($user, $cartSpread); + } + + $isSelfBuy = $user->is_promoter && systemConfig('extension_self') ? 1 : 0; + if ($isSelfBuy) { + $spreadUser = $user; + $topUser = $user->valid_spread; + } else { + $spreadUser = $user->valid_spread; + $topUser = $user->valid_top; + } + $spreadUid = $spreadUser->uid ?? 0; + $topUid = $topUser->uid ?? 0; + + $merchantRepository = app()->make(MerchantRepository::class); + $giveCouponIds = []; + $ex = systemConfig('extension_status'); + $address = $orderInfo['address']; + $allUseCoupon = $orderInfo['usePlatformCouponId'] ? [$orderInfo['usePlatformCouponId']] : []; + $totalNum = 0; + $totalPostage = 0; + $totalCost = 0; + $cartIds = []; + $orderList = []; + + foreach ($merchantCartList as $k => $merchantCart) { + $cost = 0; + $total_extension_one = 0; + $total_extension_two = 0; + //计算佣金和赠送的优惠券 + foreach ($merchantCart['list'] as &$cart) { + $cartIds[] = $cart['cart_id']; + $giveCouponIds = array_merge($giveCouponIds, $cart['product']['give_coupon_ids'] ?: []); + $cart['cost'] = $cart['productAttr']['cost']; + $cost = bcadd(bcmul($cart['cost'], $cart['cart_num'], 2), $cost, 2); + $extension_one = 0; + $extension_two = 0; + if ($ex) { + //预售订单 + if ($orderType == 2) { + $_payPrice = $merchantCart['order']['pay_price']; + $rate = $cart['productPresell']['presell_type'] == 2 ? bcdiv($cart['productPresellAttr']['down_price'], $cart['productPresellAttr']['presell_price'], 3) : 1; + $one_price = $_payPrice > 0 ? bcdiv($_payPrice, $cart['cart_num'], 2) : 0; + if ($spreadUid && $cart['productPresellAttr']['bc_extension_one'] > 0) { + $org_extension = $cart['productPresellAttr']['bc_extension_one']; + if ($spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); + } + $_extension_one = bcmul($rate, $org_extension, 3); + $presell_extension_one = 0; + if ($cart['true_price'] > 0) { + $extension_one = bcmul(bcdiv($one_price, $cart['productPresellAttr']['down_price'], 3), $_extension_one, 2); + } + if ($rate < 1) { + $presell_extension_one = bcmul(1 - $rate, $org_extension, 2); + } + $cart['final_extension_one'] = bcmul($extension_one, $cart['cart_num'], 2); + $extension_one = bcadd($extension_one, $presell_extension_one, 2); + $cart['presell_extension_one'] = bcmul($presell_extension_one, $cart['cart_num'], 2); + } + if ($topUid && $cart['productPresellAttr']['bc_extension_two'] > 0) { + $org_extension = $cart['productPresellAttr']['bc_extension_two']; + if ($topUser->brokerage_level > 0 && $topUser->brokerage && $topUser->brokerage->extension_two_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $topUser->brokerage->extension_two_rate, 2); + } + $_extension_two = bcmul($rate, $org_extension, 2); + $presell_extension_two = 0; + if ($cart['true_price'] > 0) { + $extension_two = bcmul(bcdiv($one_price, $cart['productPresellAttr']['down_price'], 3), $_extension_two, 2); + } + if ($rate < 1) { + $presell_extension_two = bcmul(1 - $rate, $org_extension, 2); + } + $cart['final_extension_two'] = bcmul($extension_two, $cart['cart_num'], 2);; + $extension_two = bcadd($extension_two, $presell_extension_two, 2); + $cart['presell_extension_two'] = bcmul($presell_extension_two, $cart['cart_num'], 2); + } + } else if (!$orderType) { + if ($spreadUid && $cart['productAttr']['bc_extension_one'] > 0) { + $org_extension = $cart['productAttr']['bc_extension_one']; + if ($spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); + } + $extension_one = $cart['true_price'] > 0 ? bcmul(bcdiv($cart['true_price'], $cart['total_price'], 3), $org_extension, 2) : 0; + } + if ($topUid && $cart['productAttr']['bc_extension_two'] > 0) { + $org_extension = $cart['productAttr']['bc_extension_two']; + if ($topUser->brokerage_level > 0 && $topUser->brokerage && $topUser->brokerage->extension_two_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $topUser->brokerage->extension_two_rate, 2); + } + $extension_two = $cart['true_price'] > 0 ? bcmul(bcdiv($cart['true_price'], $cart['total_price'], 3), $org_extension, 2) : 0; + } + } + } + $cart['extension_one'] = $extension_one; + $cart['extension_two'] = $extension_two; + $total_extension_one = bcadd($total_extension_one, bcmul($extension_one, $cart['cart_num'], 2), 2); + $total_extension_two = bcadd($total_extension_two, bcmul($extension_two, $cart['cart_num'], 2), 2); + } + unset($cart); + + $rate = 0; + if ($merchantCart['commission_rate'] > 0) { + $rate = $merchantCart['commission_rate']; + } else if (isset($merchantCart['merchantCategory']['commission_rate']) && $merchantCart['merchantCategory']['commission_rate'] > 0) { + $rate = bcmul($merchantCart['merchantCategory']['commission_rate'], 100, 4); + } + $user_address = isset($address) ? ($address['province'] . $address['city'] . $address['district'] . $address['street'] . $address['detail']) : ''; + //整理订单数据 + $_order = [ + 'cartInfo' => $merchantCart, + 'activity_type' => $orderInfo['order_type'], + 'commission_rate' => (float)$rate, + 'order_type' => $merchantCart['order']['isTake'] ? 1 : 0, + 'is_virtual' => $order_model ? 1 : 0, + 'extension_one' => $total_extension_one, + 'extension_two' => $total_extension_two, + 'order_sn' => $this->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . ($k + 1), + 'uid' => $uid, + 'spread_uid' => $spreadUid, + 'top_uid' => $topUid, + 'is_selfbuy' => $isSelfBuy, + 'real_name' => $merchantCart['order']['isTake'] ? $post['real_name'] : ($address['real_name'] ?? ''), + 'user_phone' => $merchantCart['order']['isTake'] ? $post['phone'] : ($address['phone'] ?? ''), + 'user_address' => $user_address, + 'cart_id' => implode(',', array_column($merchantCart['list'], 'cart_id')), + 'total_num' => $merchantCart['order']['total_num'], + 'total_price' => $merchantCart['order']['total_price'], + 'total_postage' => $merchantCart['order']['postage_price'], + 'pay_postage' => $merchantCart['order']['postage_price'], + 'svip_discount' => $merchantCart['order']['svip_discount'], + 'pay_price' => $merchantCart['order']['pay_price'], + 'integral' => $merchantCart['order']['total_integral'], + 'integral_price' => $merchantCart['order']['total_integral_price'], + 'give_integral' => $merchantCart['order']['total_give_integral'], + 'mer_id' => $merchantCart['mer_id'], + 'cost' => $cost, + 'order_extend' => count($extend) ? json_encode($extend, JSON_UNESCAPED_UNICODE) : '', + 'coupon_id' => implode(',', $merchantCart['order']['useCouponIds']), + 'mark' => $mark[$merchantCart['mer_id']] ?? '', + 'coupon_price' => bcadd($merchantCart['order']['coupon_price'], $merchantCart['order']['platform_coupon_price'], 2), + 'platform_coupon_price' => $merchantCart['order']['platform_coupon_price'], + 'pay_type' => $pay_type + ]; + $allUseCoupon = array_merge($allUseCoupon, $merchantCart['order']['useCouponIds']); + $orderList[] = $_order; + $totalPostage = bcadd($totalPostage, $_order['total_postage'], 2); + $totalCost = bcadd($totalCost, $cost, 2); + $totalNum += $merchantCart['order']['total_num']; + } + $groupOrder = [ + 'uid' => $uid, + 'group_order_sn' => count($orderList) === 1 ? $orderList[0]['order_sn'] : ($this->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . '0'), + 'total_postage' => $totalPostage, + 'total_price' => $orderInfo['total_price'], + 'total_num' => $totalNum, + 'real_name' => $address['real_name'] ?? '', + 'user_phone' => $address['phone'] ?? '', + 'user_address' => $user_address, + 'pay_price' => $orderInfo['order_price'], + 'coupon_price' => bcadd($orderInfo['total_platform_coupon_price'], $orderInfo['order_coupon_price'], 2), + 'pay_postage' => $totalPostage, + 'cost' => $totalCost, + 'coupon_id' => $orderInfo['usePlatformCouponId'] > 0 ? $orderInfo['usePlatformCouponId'] : '', + 'pay_type' => $pay_type, + 'give_coupon_ids' => $giveCouponIds, + 'integral' => $orderInfo['order_total_integral'], + 'integral_price' => $orderInfo['order_total_integral_price'], + 'give_integral' => $orderInfo['order_total_give_integral'], + ]; + event('order.create.before', compact('groupOrder', 'orderList')); + $group = Db::transaction(function () use ($ex, $user, $topUid, $spreadUid, $uid, $receipt_data, $cartIds, $allUseCoupon, $groupOrder, $orderList, $orderInfo) { + $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class); + $storeCartRepository = app()->make(StoreCartRepository::class); + $attrValueRepository = app()->make(ProductAttrValueRepository::class); + $productRepository = app()->make(ProductRepository::class); + $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class); + $couponUserRepository = app()->make(StoreCouponUserRepository::class); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $userMerchantRepository = app()->make(UserMerchantRepository::class); + + //减库存 + foreach ($orderList as $order) { + foreach ($order['cartInfo']['list'] as $cart) { + if (!isset($uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']])) + $uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']] = true; + else + throw new ValidateException('购物车商品信息重复'); + + try { + if ($cart['product_type'] == '1') { + $attrValueRepository->descSkuStock($cart['product']['old_product_id'], $cart['productAttr']['sku'], $cart['cart_num']); + $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']); + } else if ($cart['product_type'] == '2') { + $productPresellSkuRepository = app()->make(ProductPresellSkuRepository::class); + $productPresellSkuRepository->descStock($cart['productPresellAttr']['product_presell_id'], $cart['productPresellAttr']['unique'], $cart['cart_num']); + $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']); + } else if ($cart['product_type'] == '3') { + app()->make(ProductAssistSkuRepository::class)->descStock($cart['productAssistAttr']['product_assist_id'], $cart['productAssistAttr']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']); + $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + } else if ($cart['product_type'] == '4') { + app()->make(ProductGroupSkuRepository::class)->descStock($cart['activeSku']['product_group_id'], $cart['activeSku']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']); + $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + } else { + $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']); + if ($cart['integral'] && $cart['integral']['use'] > 0) { + $productRepository->incIntegral($cart['product']['product_id'], $cart['integral']['use'], $cart['integral']['price']); + } + } + } catch (\Exception $e) { + throw new ValidateException('库存不足'); + } + } + } + + if ($orderInfo['order_type'] == 10 && !app()->make(StoreDiscountRepository::class)->decStock($orderList[0]['cartInfo']['list'][0]['source_id'])) { + throw new ValidateException('套餐库不足'); + } + + //修改购物车状态 + $storeCartRepository->updates($cartIds, [ + 'is_pay' => 1 + ]); + + //使用优惠券 + if (count($allUseCoupon)) { + $couponUserRepository->updates($allUseCoupon, [ + 'use_time' => date('Y-m-d H:i:s'), + 'status' => 1 + ]); + } + + //创建订单 + $groupOrder = $storeGroupOrderRepository->create($groupOrder); + $bills = []; + + if ($groupOrder['integral'] > 0) { + $user->integral = bcsub($user->integral, $groupOrder['integral'], 0); + app()->make(UserBillRepository::class)->decBill($user['uid'], 'integral', 'deduction', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 1, + 'title' => '购买商品', + 'number' => $groupOrder['integral'], + 'mark' => '购买商品使用积分抵扣' . floatval($groupOrder['integral_price']) . '元', + 'balance' => $user->integral + ]); + $user->save(); + } + + foreach ($orderList as $k => $order) { + $orderList[$k]['group_order_id'] = $groupOrder->group_order_id; + } + + $orderProduct = []; + $orderStatus = []; + foreach ($orderList as $order) { + $cartInfo = $order['cartInfo']; + unset($order['cartInfo']); + //创建子订单 + $_order = $this->dao->create($order); + + if ($order['integral'] > 0) { + $bills[] = [ + 'uid' => $uid, + 'link_id' => $_order->order_id, + 'pm' => 0, + 'title' => '积分抵扣', + 'category' => 'mer_integral', + 'type' => 'deduction', + 'number' => $order['integral'], + 'balance' => $user->integral, + 'mark' => '购买商品使用' . $order['integral'] . '积分抵扣' . floatval($order['integral_price']) . '元', + 'mer_id' => $order['mer_id'], + 'status' => 1 + ]; + } + + //创建发票信息 + if (isset($receipt_data[$_order['mer_id']])) { + app()->make(StoreOrderReceiptRepository::class)->add($receipt_data[$_order['mer_id']], $_order); + } + + $orderStatus[] = [ + 'order_id' => $_order->order_id, + 'order_sn' => $_order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单生成', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CREATE, + 'uid' => $user->uid, + 'nickname' => $user->nickname, + 'user_type' => $storeOrderStatusRepository::U_TYPE_USER, + ]; + + foreach ($cartInfo['list'] as $cart) { + + $productPrice = $cart['true_price']; + $extension_one = $cart['extension_one']; + $extension_two = $cart['extension_two']; + + //计算预售订单尾款 + if ($cartInfo['order']['order_type'] == 2) { + $finalPrice = max(bcsub($cartInfo['order']['final_price'], $cartInfo['order']['coupon_price'], 2), 0); + $allFinalPrice = $order['order_type'] ? $finalPrice : bcadd($finalPrice, $order['pay_postage'], 2); + if ($cart['productPresell']['presell_type'] == 1) { + $productPrice = bcsub($cartInfo['order']['pay_price'], $order['pay_postage'], 2); + } else { + $productPrice = bcadd($cartInfo['order']['pay_price'], $finalPrice, 2); + } + //生成尾款订单 + if ($cart['productPresell']['presell_type'] == 2) { + $presellOrderRepository = app()->make(PresellOrderRepository::class); + $presellOrderRepository->create([ + 'uid' => $uid, + 'order_id' => $_order->order_id, + 'mer_id' => $_order->mer_id, + 'final_start_time' => $cart['productPresell']['final_start_time'], + 'final_end_time' => $cart['productPresell']['final_end_time'], + 'pay_price' => $allFinalPrice, + 'presell_order_sn' => $this->getNewOrderId(StoreOrderRepository::TYPE_SN_PRESELL) + ]); + } + app()->make(ProductPresellSkuRepository::class)->incCount($cart['source_id'], $cart['productAttr']['unique'], 'one_take'); + } + + $order_cart = [ + 'product' => $cart['product'], + 'productAttr' => $cart['productAttr'], + 'product_type' => $cart['product_type'] + ]; + + if ($cart['product_type'] == '2') { + $order_cart['productPresell'] = $cart['productPresell']; + $order_cart['productPresellAttr'] = $cart['productPresellAttr']; + $order_cart['final_extension_one'] = $cart['final_extension_one'] ?? 0; + $order_cart['final_extension_two'] = $cart['final_extension_two'] ?? 0; + $order_cart['presell_extension_one'] = $cart['presell_extension_one'] ?? 0; + $order_cart['presell_extension_two'] = $cart['presell_extension_two'] ?? 0; + } else if ($cart['product_type'] == '3') { + $order_cart['productAssistAttr'] = $cart['productAssistAttr']; + $order_cart['productAssistSet'] = $cart['productAssistSet']; + } else if ($cart['product_type'] == '4') { + $order_cart['activeSku'] = $cart['activeSku']; + } else if ($cart['product_type'] == '10') { + $order_cart['active'] = $cart['productDiscount']; + $order_cart['activeSku'] = $cart['productDiscountAttr']; + } + + $orderProduct[] = [ + 'order_id' => $_order->order_id, + 'cart_id' => $cart['cart_id'], + 'uid' => $uid, + 'product_id' => $cart['product_id'], + 'activity_id' => $cart['source'] >= 2 ? $cart['source_id'] : $cart['product_id'], + 'total_price' => $cart['total_price'], + 'product_price' => $productPrice, + 'extension_one' => $extension_one, + 'extension_two' => $extension_two, + 'postage_price' => $cart['postage_price'], + 'svip_discount' => $cart['svip_discount'], + 'cost' => $cart['cost'], + 'coupon_price' => $cart['coupon_price'], + 'platform_coupon_price' => $cart['platform_coupon_price'], + 'product_sku' => $cart['productAttr']['unique'], + 'product_num' => $cart['cart_num'], + 'refund_num' => $cart['cart_num'], + 'integral_price' => $cart['integral']['price'] ?? 0, + 'integral' => $cart['integral'] ? bcdiv($cart['integral']['use'], $cart['cart_num'], 0) : 0, + 'integral_total' => $cart['integral'] ? $cart['integral']['use'] : 0, + 'product_type' => $cart['product_type'], + 'cart_info' => json_encode($order_cart) + ]; + } + + $userMerchantRepository->getInfo($uid, $order['mer_id']); + app()->make(MerchantRepository::class)->incSales($order['mer_id'], $order['total_num']); + } + + if (count($bills) > 0) { + app()->make(UserBillRepository::class)->insertAll($bills); + } + $storeOrderStatusRepository->batchCreateLog($orderStatus); + $storeOrderProductRepository->insertAll($orderProduct); + event('order.create', compact('groupOrder')); + return $groupOrder; + }); + foreach ($merchantCartList as $merchantCart) { + foreach ($merchantCart['list'] as $cart) { + if (($cart['productAttr']['stock'] - $cart['cart_num']) < (int)merchantConfig($merchantCart['mer_id'], 'mer_store_stock')) { + SwooleTaskService::merchant('notice', [ + 'type' => 'min_stock', + 'data' => [ + 'title' => '库存不足', + 'message' => $cart['product']['store_name'] . '(' . $cart['productAttr']['sku'] . ')库存不足', + 'id' => $cart['product']['product_id'] + ] + ], $merchantCart['mer_id']); + } + } + } + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_CREATE', 'id' => $group->group_order_id]); + return $group; + } +} diff --git a/app/common/repositories/store/order/StoreOrderCreateRepository.php.bak b/app/common/repositories/store/order/StoreOrderCreateRepository.php.bak new file mode 100644 index 00000000..d8ec8c4d --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderCreateRepository.php.bak @@ -0,0 +1,1360 @@ +uid; + $userIntegral = $user->integral; + $key = md5(json_encode(compact('cartId', 'takes', 'useCoupon', 'useIntegral', 'addressId'))) . $uid; + app()->make(StoreCouponUserRepository::class)->failCoupon(); + $address = null; + //验证地址 + if ($addressId) { + $addressRepository = app()->make(UserAddressRepository::class); + $address = $addressRepository->getWhere(['uid' => $uid, 'address_id' => $addressId]); + } + + $storeCartRepository = app()->make(StoreCartRepository::class); + $res = $storeCartRepository->checkCartList($storeCartRepository->cartIbByData($cartId, $uid, $address), 0, $user); + $merchantCartList = $res['list']; + $fail = $res['fail']; + + //检查购物车失效数据 + if (count($fail)) { + if ($fail[0]['is_fail']) + throw new ValidateException('[已失效]' . mb_substr($fail[0]['product']['store_name'],0,10).'...'); + if (in_array($fail[0]['product_type'], [1, 2, 3]) && !$fail[0]['userPayCount']) { + throw new ValidateException('[超出限购数]' . mb_substr($fail[0]['product']['store_name'],0,10).'...'); + } + throw new ValidateException('[已失效]' . mb_substr($fail[0]['product']['store_name'],0,10).'...'); + } + + $svip_status = $user->is_svip > 0 && systemConfig('svip_switch_status') == '1'; + $svip_integral_rate = $svip_status ? app()->make(MemberinterestsRepository::class)->getSvipInterestVal(MemberinterestsRepository::HAS_TYPE_PAY) : 0; + //订单活动类型 + $order_type = 0; + //虚拟订单 + $order_model = 0; + //虚拟订单自定义数据 + $order_extend = []; + //检查商品类型, 活动商品只能单独购买 + foreach ($merchantCartList as $merchantCart) { + foreach ($merchantCart['list'] as $cart) { + if ($cart['product_type']==0) { + if ($cart['product']['once_min_count'] > 0 && $cart['product']['once_min_count'] > $cart['cart_num']) + throw new ValidateException('[低于起购数:'.$cart['product']['once_min_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...'); + if ($cart['product']['pay_limit'] == 1 && $cart['product']['once_max_count'] < $cart['cart_num']) + throw new ValidateException('[超出单次限购数:'.$cart['product']['once_max_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...'); + if ($cart['product']['pay_limit'] == 2){ + //如果长期限购 + //已购买数量 + $count = app()->make(StoreOrderRepository::class)->getMaxCountNumber($cart['uid'],$cart['product_id']); + if (($cart['cart_num'] + $count) > $cart['product']['once_max_count']) + throw new ValidateException('[超出限购总数:'. $cart['product']['once_max_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...'); + } + } + + if ($cart['product_type'] > 0) $order_type = $cart['product_type']; + if ($cart['product_type'] > 0 && (($cart['product_type'] != 10 && count($merchantCart['list']) != 1) || count($merchantCartList) != 1)) { + throw new ValidateException('活动商品必须单独购买'); + } + if ($cart['product']['type'] && (count($merchantCart['list']) != 1 || count($merchantCartList) != 1)) { + throw new ValidateException('虚拟商品必须单独购买'); + } + $order_model = $cart['product']['type']; + if ($cart['product']['extend']) { + $order_extend = json_decode($cart['product']['extend'], true); + } + } + } + unset($merchantCart, $cart); + + $order_price = 0; + $total_true_price = 0; + $order_total_price = 0; + $order_coupon_price = 0; + $noDeliver = false; + $presellType = 0; + $fn = []; + $enabledPlatformCoupon = !$order_type; + $order_total_postage = 0; + + + //套餐订单 + if ($order_type == 10) { + app()->make(StoreDiscountRepository::class) + ->check($merchantCartList[0]['list'][0]['source_id'], $merchantCartList[0]['list'], $user); + } + + $orderDeliveryStatus = true; + $order_svip_discount = 0; + // 循环计算每个店铺的订单数据 + foreach ($merchantCartList as &$merchantCart) { + $postageRule = []; + $total_price = 0; + $total_num = 0; + $valid_total_price = 0; + $postage_price = 0; + $product_price = []; + $final_price = 0; + $down_price = 0; + $total_svip_discount = 0; + + //是否自提 + $isTake = in_array($merchantCart['mer_id'], $takes ?? []); + +// if (!$createOrder && !$isTake) { +// $isTake = count($merchantCart['delivery_way']) == 1 && $merchantCart['delivery_way'][0] == '1'; +// } + + $merTake = in_array('1', $merchantCart['delivery_way'], true); + $merDelivery = (!$merchantCart['delivery_way'] || !count($merchantCart['delivery_way']) || in_array('2', $merchantCart['delivery_way'], true)); + $_merTake = $merTake; + $_merDelivery = $merDelivery; + $deliveryStatus = true; + if ($createOrder && $isTake && !$merTake) { + $deliveryStatus = false; +// throw new ValidateException('[仅支持快递配送]' . $merchantCart['mer_name']); + } + $product_cart = []; + + foreach ($merchantCart['list'] as $k => $cart) { + //获取订单类型, 活动商品单次只能购买一个 + if ($cart['product']['delivery_way']) { + $delivery_way = explode(',', $cart['product']['delivery_way']); + $proTake = in_array('1', $delivery_way, true); + $merTake = $merTake && $proTake; + $proDelivery = (!count($delivery_way) || in_array('2', $delivery_way, true)); + $merDelivery = $merDelivery && $proDelivery; + $merchantCart['list'][$k]['allow_take'] = $proTake; + $merchantCart['list'][$k]['allow_delivery'] = $proDelivery; + } else { + $merchantCart['list'][$k]['allow_take'] = $_merTake; + $merchantCart['list'][$k]['allow_delivery'] = $_merDelivery; + } + if ($createOrder && $isTake && !$merTake) { + $deliveryStatus = false; +// throw new ValidateException('[仅支持快递配送]' . $cart['product']['store_name']); + } + } + if (!$merDelivery && !$merTake) { + $deliveryStatus = false; +// throw new ValidateException('部分商品配送方式不一致,请单独下单'); + } + if ($deliveryStatus && !$isTake && ($merDelivery || $merTake)) { + $isTake = $merDelivery ? 0 : 1; + } + //加载商品数据 + foreach ($merchantCart['list'] as $cart) { + //预售订单 + if ($cart['product_type'] == 2) { + $cart->append(['productPresell', 'productPresellAttr']); + //助力订单 + } else if ($cart['product_type'] == 3) { + $cart->append(['productAssistAttr']); + //拼团订单 + } else if ($cart['product_type'] == 4) { + $cart->append(['activeSku']); + //套餐订单 + } else if ($cart['product_type'] == 10) { + $cart->append(['productDiscount', 'productDiscountAttr']); + } + + //如果是预售订单 获取预售的订单的首款,尾款预售类型 + if ($order_type == 2) { + $final_price = bcadd($final_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['final_price'], 2), 2); + $presellType = $cart['productPresell']['presell_type']; + if ($presellType == 2) + $down_price = bcadd($down_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['down_price'], 2), 2); + } + } + unset($cart); + + $enabledCoupon = !($order_type && $order_type != 2); + + //只有预售和普通商品可以用优惠券 + if (!$enabledCoupon) { + $merchantCart['coupon'] = []; + } + $svip_coupon_merge = merchantConfig($merchantCart['mer_id'], 'svip_coupon_merge'); + $use_svip = 0; + //获取运费规则和统计商品数据 + foreach ($merchantCart['list'] as &$cart) { + + if ($cart['product_type'] == 10 && $cart['productDiscountAttr']) { + $cart['productAttr']['price'] = $cart['productDiscountAttr']['active_price']; + $cart['productAttr']['show_svip_price'] = false; + } + + if ($cart['cart_num'] <= 0) { + throw new ValidateException('购买商品数必须大于0'); + } + $svip_discount = 0; + + $price = bcmul($cart['cart_num'], $this->cartByPrice($cart), 2); + $cart['total_price'] = $price; + $cart['postage_price'] = 0; + $cart['svip_discount'] = 0; + $total_price = bcadd($total_price, $price, 2); + $total_num += $cart['cart_num']; + $_price = bcmul($cart['cart_num'], $this->cartByCouponPrice($cart), 2); + $cart['svip_coupon_merge'] = 1; + if ($cart['productAttr']['show_svip_price'] && !$cart['product_type']) { + $svip_discount = max(bcmul($cart['cart_num'], bcsub($cart['productAttr']['org_price'] ?? 0, $cart['productAttr']['price'], 2), 2), 0); + if ($svip_coupon_merge != '1') { + $_price = 0; + $cart['svip_coupon_merge'] = 0; + } + $use_svip = 1; + } + $valid_total_price = bcadd($valid_total_price, $_price, 2); + $cart['allow_price'] = $_price; + $temp1 = $cart['product']['temp']; + $cart['temp_number'] = 0; + $total_svip_discount = bcadd($total_svip_discount, $svip_discount, 2); + $cart['svip_discount'] = $svip_discount; + + if (!isset($product_cart[$cart['product_id']])) + $product_cart[$cart['product_id']] = [$cart['cart_id']]; + else + $product_cart[$cart['product_id']][] = $cart['cart_id']; + + if ($_price > 0) { + $product_price[$cart['product_id']] = bcadd($product_price[$cart['product_id']] ?? 0, $_price, 2); + } + + if (!$temp1) continue; + + $number = $this->productByTempNumber($cart); + if ($number <= 0) continue; + $cart['temp_number'] = $number; + + if ($order_model || !$temp1 || ($cart['product_type'] == 10 && $cart['productDiscount']['free_shipping'])) { + continue; + } + + $free = $temp1['free'][0] ?? null; + $region = $temp1['region'][0] ?? null; + + if (!$cart['product']['delivery_free'] && !$isTake && (!$address || !$cart['product']['temp'] || ($temp1['undelivery'] == 2 && !$free && (!$region || !$region['city_id'])))) { + $cart['undelivered'] = true; + $noDeliver = true; + continue; + } + $cart['undelivered'] = (!$isTake) && $temp1['undelivery'] == 1 && isset($temp1['undelives']); + $fn[] = function () use ($cart) { + unset($cart['product']['temp']); + }; + + if ($cart['undelivered']) { + $noDeliver = true; + continue; + } + if ($cart['product']['delivery_free']) { + continue; + } + $tempId = $cart['product']['temp_id']; + if (!isset($postageRule[$tempId])) { + $postageRule[$tempId] = [ + 'free' => null, + 'region' => null, + 'cart' => [], + 'price' => 0, + ]; + } + + $freeRule = $postageRule[$tempId]['free']; + $regionRule = $postageRule[$tempId]['region']; + $postageRule[$tempId]['cart'][] = $cart['cart_id']; + $postageRule[$tempId]['price'] = bcadd($postageRule[$tempId]['price'], $cart['price'], 2); + + if ($temp1['appoint'] && $free) { + if (!isset($freeRule)) { + $freeRule = $free; + $freeRule['cart_price'] = 0; + $freeRule['cart_number'] = 0; + } + $freeRule['cart_number'] = bcadd($freeRule['cart_number'], $number, 2); + $freeRule['cart_price'] = bcadd($freeRule['cart_price'], $price, 2); + } + + if ($region) { + if (!isset($regionRule)) { + $regionRule = $region; + $regionRule['cart_price'] = 0; + $regionRule['cart_number'] = 0; + } + $regionRule['cart_number'] = bcadd($regionRule['cart_number'], $number, 2); + $regionRule['cart_price'] = bcadd($regionRule['cart_price'], $price, 2); + } + $postageRule[$tempId]['free'] = $freeRule; + $postageRule[$tempId]['region'] = $regionRule; + } + unset($cart); + + if (!$isTake) { + //计算运费 + foreach ($postageRule as $item) { + $freeRule = $item['free']; + if ($freeRule && $freeRule['cart_number'] >= $freeRule['number'] && $freeRule['cart_price'] >= $freeRule['price']) + continue; + if (!$item['region']) continue; + $regionRule = $item['region']; + $postage = $regionRule['first_price']; + if ($regionRule['first'] > 0 && $regionRule['cart_number'] > $regionRule['first']) { + $num = ceil(bcdiv(bcsub($regionRule['cart_number'], $regionRule['first'], 2), $regionRule['continue'], 2)); + $postage = bcadd($postage, bcmul($num, $regionRule['continue_price'], 2), 2); + } + $postage_price = bcadd($postage_price, $postage, 2); + $cartNum = count($item['cart']); + //计算每个商品的运费比例 + foreach ($merchantCart['list'] as &$cart) { + if (in_array($cart['cart_id'], $item['cart'])) { + if (--$cartNum) { + $cart['postage_price'] = bcmul($postage, bcdiv($cart['temp_number'], $regionRule['cart_number'], 3), 2); + $postage = bcsub($postage, $cart['postage_price'], 2); + } else { + $cart['postage_price'] = $postage; + } + } + } + unset($cart); + } + unset($item); + } + + $coupon_price = 0; + $use_coupon_product = []; + $use_store_coupon = 0; + + $useCouponFlag = isset($useCoupon[$merchantCart['mer_id']]); + $merCouponIds = (array)($useCoupon[$merchantCart['mer_id']] ?? []); + $merCouponIds = array_reverse($merCouponIds); + $sortIds = $merCouponIds; +// $all_coupon_product = []; + unset($defaultSort); + $defaultSort = []; + if (count($merCouponIds)) { + foreach ($merchantCart['coupon'] as &$item) { + $defaultSort[] = &$item; + if (!in_array($item['coupon_user_id'], $sortIds, true)) { + $sortIds[] = $item['coupon_user_id']; + } + } + unset($item); + usort($merchantCart['coupon'], function ($a, $b) use ($sortIds) { + return array_search($a['coupon_user_id'], $sortIds) > array_search($b['coupon_user_id'], $sortIds) ? 1 : -1; + }); + } + + //过滤不可用店铺优惠券 + foreach ($merchantCart['coupon'] as &$coupon) { + if (!$coupon['coupon']['type']) continue; + + $coupon['disabled'] = false; + $coupon['checked'] = false; + + if (count(array_intersect(array_column($coupon['product'], 'product_id'), array_keys($product_price))) == 0) { + $coupon['disabled'] = true; + continue; + } + if($svip_coupon_merge != '1' && $use_svip){ + $coupon['disabled'] = true; + continue; + } + $flag = false; + foreach ($coupon['product'] as $_product) { + if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) { + $flag = true; + break; + } + } + if (!$flag) { + $coupon['disabled'] = true; + } +// if (!$coupon['disabled']) { +// $all_coupon_product[] = $coupon['coupon_user_id']; +// } + } + + unset($coupon); + + //if ($useCouponFlag && count(array_diff($all_coupon_product, $use_coupon_product))) { + // throw new ValidateException('请选择有效的商品券'); + //} + //计算商品券金额 + foreach ($merchantCart['coupon'] as &$coupon) { + if (!$coupon['coupon']['type']) continue; + if ($coupon['disabled']) continue; + + foreach ($coupon['product'] as $_product) { + if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) { + if ($useCouponFlag) { + if (!in_array($coupon['coupon_user_id'], $merCouponIds) || isset($use_coupon_product[$_product['product_id']])) { + continue; + } + } else if (isset($use_coupon_product[$_product['product_id']])) { + continue; + } + $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2); + $use_coupon_product[$_product['product_id']] = $coupon; + $coupon['checked'] = true; + break; + } + } + unset($_product); + } + unset($coupon); + $pay_price = max(bcsub($valid_total_price, $coupon_price, 2), 0); + $_pay_price = $pay_price; + //计算店铺券 + foreach ($merchantCart['coupon'] as &$coupon) { + if ($coupon['coupon']['type']) continue; + $coupon['checked'] = false; + $coupon['disabled'] = $pay_price <= 0; + if ($use_store_coupon || $pay_price <= 0) continue; + if($svip_coupon_merge != '1' && $use_svip){ + $coupon['disabled'] = true; + continue; + } + //店铺券 + if ($valid_total_price >= $coupon['use_min_price']) { + if ($useCouponFlag) { + if (!in_array($coupon['coupon_user_id'], $merCouponIds)) { + continue; + } + } + $use_store_coupon = $coupon; + $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2); + $_pay_price = bcsub($_pay_price, $coupon['coupon_price'], 2); + $coupon['checked'] = true; + } else { + $coupon['disabled'] = true; + } + } + unset($coupon); + + $productCouponRate = []; + $storeCouponRate = null; + $useCouponIds = []; + //计算优惠占比 + foreach ($use_coupon_product as $productId => $coupon) { + $productCouponRate[$productId] = [ + 'rate' => $product_price[$productId] > 0 ? bcdiv($coupon['coupon_price'], $product_price[$productId], 4) : 1, + 'coupon_price' => $coupon['coupon_price'], + 'price' => $product_price[$productId] + ]; + $useCouponIds[] = $coupon['coupon_user_id']; + } + + if ($use_store_coupon) { + $storeCouponRate = [ + 'rate' => $pay_price > 0 ? bcdiv($use_store_coupon['coupon_price'], $pay_price, 4) : 1, + 'coupon_price' => $use_store_coupon['coupon_price'], + 'price' => $coupon_price + ]; + $useCouponIds[] = $use_store_coupon['coupon_user_id']; + } + + //计算单个商品实际支付金额 + foreach ($merchantCart['list'] as $_k => &$cart) { + $cartTotalPrice = bcmul($this->cartByPrice($cart), $cart['cart_num'], 2); + $_cartTotalPrice = $cartTotalPrice; + if (!$cart['product_type'] && $cartTotalPrice > 0) { + if (isset($productCouponRate[$cart['product_id']])) { + //计算每个商品优惠金额(商品券) + if ($productCouponRate[$cart['product_id']]['rate'] >= 1) { + $cartTotalPrice = 0; + } else { + array_pop($product_cart); + if (!count($product_cart)) { + $cartTotalPrice = bcsub($cartTotalPrice, $productCouponRate[$cart['product_id']]['coupon_price'], 2); + $productCouponRate[$cart['product_id']]['coupon_price'] = 0; + } else { + $couponPrice = bcmul($cartTotalPrice, $productCouponRate[$cart['product_id']]['rate'], 2); + $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2); + $productCouponRate[$cart['product_id']]['coupon_price'] = bcsub($productCouponRate[$cart['product_id']]['coupon_price'], $couponPrice, 2); + } + } + } + + //(店铺券) + if ($storeCouponRate && $cartTotalPrice > 0) { + if ($storeCouponRate['rate'] >= 1) { + $cartTotalPrice = 0; + } else { + if (count($merchantCart['list']) == $_k + 1) { + $cartTotalPrice = bcsub($cartTotalPrice, $storeCouponRate['coupon_price'], 2); + } else { + $couponPrice = bcmul($cartTotalPrice, $storeCouponRate['rate'], 2); + $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2); + $storeCouponRate['coupon_price'] = bcsub($storeCouponRate['coupon_price'], $couponPrice, 2); + } + } + } + } + + //单个商品实际支付金额 + $cart['coupon_price'] = bcsub($_cartTotalPrice, $cartTotalPrice, 2); + $cart['true_price'] = $cartTotalPrice; + } + unset($cart, $_k); + $total_true_price = bcadd($_pay_price, $total_true_price, 2); + if(count($merchantCartList) > 1 || count($merchantCart['list']) > 1){ + $orderDeliveryStatus = $orderDeliveryStatus && $deliveryStatus; + } + $merchantCart['order'] = [ + 'true_price' => $_pay_price, + 'platform_coupon_price' => 0, + 'valid_total_price' => $valid_total_price, + 'total_price' => $total_price, + 'final_price' => $final_price, + 'down_price' => $down_price, + 'coupon_price' => $coupon_price, + 'svip_coupon_merge' => $svip_coupon_merge, + 'postage_price' => $postage_price, + 'isTake' => $isTake, + 'total_num' => $total_num, + 'enabledCoupon' => $enabledCoupon, + 'useCouponIds' => $useCouponIds, + 'allow_take' => $merTake, + 'allow_delivery' => $merDelivery, + 'delivery_status' => $deliveryStatus, + 'svip_discount' => $total_svip_discount, + 'use_svip' => $use_svip, + ]; + $order_total_postage = bcadd($order_total_postage, $postage_price, 2); + $order_svip_discount = bcadd($total_svip_discount, $order_svip_discount, 2); + if (count($defaultSort)) { + $merchantCart['coupon'] = &$defaultSort; + } + } + unset($merchantCart); + + $usePlatformCouponId = $useCoupon[0] ?? 0; + $usePlatformCouponId = is_array($usePlatformCouponId) ? array_pop($usePlatformCouponId) : $usePlatformCouponId; + $usePlatformCouponFlag = isset($useCoupon[0]); + + foreach ($merchantCartList as &$merchantCart) { + if (!$merchantCart['order']['use_svip']) + continue; + $totalMergePrice = 0; + foreach ($merchantCart['list'] as &$cart) { + if (!$cart['svip_coupon_merge']) { + $totalMergePrice = bcadd($totalMergePrice, $cart['true_price'], 2); + $cart['allow_price'] = $cart['true_price']; + } + } + unset($cart); + if ($totalMergePrice > 0) { + $total_true_price = bcadd($total_true_price, $totalMergePrice, 2); + $merchantCart['order']['valid_total_price'] = bcadd($merchantCart['order']['valid_total_price'], $totalMergePrice, 2); + $merchantCart['order']['true_price'] = $merchantCart['order']['valid_total_price']; + } + } + unset($merchantCart); + + //计算平台券优惠金额 +// if ($total_true_price > 0) { + $StoreCouponUser = app()->make(StoreCouponUserRepository::class); + $platformCoupon = $StoreCouponUser->validUserPlatformCoupon($uid); + if ($enabledPlatformCoupon && count($platformCoupon)) { + + $catePriceLst = []; + $storePriceLst = []; + $_cartNum = 0; + + foreach ($merchantCartList as &$merchantCart) { + if ($merchantCart['order']['true_price'] <= 0) continue; + foreach ($merchantCart['list'] as &$cart) { + $_cartNum++; + if ($cart['product']['cate_id']) { + if (!isset($catePriceLst[$cart['product']['cate_id']])) { + $catePriceLst[$cart['product']['cate_id']] = ['price' => 0, 'cart' => []]; + } + $catePriceLst[$cart['product']['cate_id']]['price'] = bcadd($catePriceLst[$cart['product']['cate_id']]['price'], $cart['true_price']); + $catePriceLst[$cart['product']['cate_id']]['cart'][] = &$cart; + } + } + unset($cart); + $storePriceLst[$merchantCart['mer_id']] = [ + 'price' => $merchantCart['order']['true_price'], + 'num' => count($merchantCart['list']) + ]; + } + unset($merchantCart); + $flag = false; + $platformCouponRate = null; + + foreach ($platformCoupon as &$coupon) { + $coupon['checked'] = false; + //通用券 + if ($coupon['coupon']['type'] === StoreCouponRepository::TYPE_PLATFORM_ALL) { + $coupon['disabled'] = $total_true_price <= 0 || $coupon['use_min_price'] > $total_true_price; + if (!$platformCouponRate && !$coupon['disabled'] && !$flag && ((!$usePlatformCouponId && !$usePlatformCouponFlag) || $usePlatformCouponId == $coupon['coupon_user_id'])) { + $platformCouponRate = [ + 'id' => $coupon['coupon_user_id'], + 'type' => $coupon['coupon']['type'], + 'price' => $total_true_price, + 'coupon_price' => $coupon['coupon_price'], + 'use_count' => $_cartNum, + 'check' => function ($cart) { + return true; + } + ]; + $coupon['checked'] = true; + $flag = true; + } + //品类券 + } else if ($coupon['coupon']['type'] === StoreCouponRepository::TYPE_PLATFORM_CATE) { + $_price = 0; + $_use_count = 0; + $cateIds = $coupon['product']->column('product_id'); + $allCateIds = array_unique(array_merge(app()->make(StoreCategoryRepository::class)->allChildren($cateIds), $cateIds)); + $flag2 = true; + foreach ($allCateIds as $cateId) { + if (isset($catePriceLst[$cateId])) { + $_price = bcadd($catePriceLst[$cateId]['price'], $_price, 2); + $_use_count += count($catePriceLst[$cateId]['cart']); + $flag2 = false; + } + } + $coupon['disabled'] = $flag2 || $coupon['use_min_price'] > $_price; + //品类券可用 + if (!$platformCouponRate && !$coupon['disabled'] && !$flag && !$flag2 && ((!$usePlatformCouponId && !$usePlatformCouponFlag) || $usePlatformCouponId == $coupon['coupon_user_id'])) { + $platformCouponRate = [ + 'id' => $coupon['coupon_user_id'], + 'type' => $coupon['coupon']['type'], + 'price' => $_price, + 'use_cate' => $allCateIds, + 'coupon_price' => $coupon['coupon_price'], + 'use_count' => $_use_count, + 'check' => function ($cart) use ($allCateIds) { + return in_array($cart['product']['cate_id'], $allCateIds); + } + ]; + $coupon['checked'] = true; + $flag = true; + } + //跨店券 + } else if ($coupon['coupon']['type'] === StoreCouponRepository::TYPE_PLATFORM_STORE) { + $_price = 0; + $_use_count = 0; + $flag2 = true; + foreach ($coupon['product'] as $item) { + $merId = $item['product_id']; + if (isset($storePriceLst[$merId])) { + $_price = bcadd($storePriceLst[$merId]['price'], $_price, 2); + $_use_count += $storePriceLst[$merId]['num']; + $flag2 = false; + } + } + $coupon['disabled'] = $flag2 || $coupon['use_min_price'] > $_price; + //店铺券可用 + if (!$platformCouponRate && !$coupon['disabled'] && !$flag && !$flag2 && ((!$usePlatformCouponId && !$usePlatformCouponFlag) || $usePlatformCouponId == $coupon['coupon_user_id'])) { + $_merIds = $coupon['product']->column('product_id'); + $platformCouponRate = [ + 'id' => $coupon['coupon_user_id'], + 'type' => $coupon['coupon']['type'], + 'price' => $_price, + 'use_store' => $_merIds, + 'coupon_price' => $coupon['coupon_price'], + 'use_count' => $_use_count, + 'check' => function ($cart) use ($_merIds) { + return in_array($cart['mer_id'], $_merIds); + } + ]; + $coupon['checked'] = true; + $flag = true; + } + } + } + unset($coupon); + } +// } + + $usePlatformCouponId = 0; + $total_platform_coupon_price = 0; + //计算平台优惠券 + if (isset($platformCouponRate)) { + $_coupon_price = $platformCouponRate['coupon_price']; + foreach ($merchantCartList as &$merchantCart) { + $_price = 0; + foreach ($merchantCart['list'] as &$cart) { + if ($cart['true_price'] <= 0 || !$platformCouponRate['check']($cart)) continue; + + if ($platformCouponRate['use_count'] === 1) { + $couponPrice = min($platformCouponRate['coupon_price'], $cart['true_price']); + } else { + $couponPrice = min(bcmul($_coupon_price, bcdiv($cart['true_price'], $platformCouponRate['price'], 3), 2), $cart['true_price']); + } + $platformCouponRate['coupon_price'] = bcsub($platformCouponRate['coupon_price'], $couponPrice, 2); + $cart['true_price'] = bcsub($cart['true_price'], $couponPrice, 2); + $cart['platform_coupon_price'] = $couponPrice; + $platformCouponRate['use_count']--; + $_price = bcadd($couponPrice, $_price, 2); + } + unset($cart); + $merchantCart['order']['platform_coupon_price'] = $_price; + $merchantCart['order']['true_price'] = bcsub($merchantCart['order']['true_price'], $_price, 2); + $total_platform_coupon_price = bcadd($total_platform_coupon_price, $_price, 2); + } + $usePlatformCouponId = $platformCouponRate['id']; + unset($merchantCart); + } + + //积分配置 + $sysIntegralConfig = systemConfig(['integral_money', 'integral_status', 'integral_order_rate']); + $merIntegralFlag = false; + $order_total_integral = 0; + $order_total_integral_price = 0; + $order_total_give_integral = 0; + $allow_no_address = true; + + foreach ($merchantCartList as &$merchantCart) { + $merchantCart['take'] = [ + 'mer_integral_rate' => 0, + 'mer_integral_status' => 0, + ]; + $allow_no_address = $allow_no_address && $merchantCart['order']['isTake']; + foreach ($merchantCart['config'] as $config) { + $merchantCart['take'][$config['config_key']] = $config['value']; + } + $merIntegralConfig = $merchantCart['take']; + unset($merchantCart['config']); + $merIntegralConfig['mer_integral_rate'] = min(1, $merIntegralConfig['mer_integral_rate'] > 0 ? bcdiv($merIntegralConfig['mer_integral_rate'], 100, 4) : $merIntegralConfig['mer_integral_rate']); + $total_integral = 0; + $total_integral_price = 0; + $merIntegralFlag = $merIntegralFlag || ((bool)$merIntegralConfig['mer_integral_status']); + $integralFlag = $useIntegral && $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_money'] > 0 && $merIntegralConfig['mer_integral_status']; + + //计算积分抵扣 + foreach ($merchantCart['list'] as &$cart) { + //只有普通商品可以抵扣 + if ($cart['product_type'] == 0 && $integralFlag && $userIntegral > 0 && $merchantCart['order']['true_price'] > 0) { + $integralRate = $cart['product']['integral_rate']; + if ($integralRate < 0) { + $integralRate = $merIntegralConfig['mer_integral_rate']; + } else if($integralRate > 0){ + $integralRate = min(bcdiv($integralRate, 100, 4), 1); + } + if ($integralRate > 0) { + $productIntegralPrice = min(bcmul(bcmul($this->cartByPrice($cart), $cart['cart_num'], 2), $integralRate, 2), $cart['true_price']); + if ($productIntegralPrice > 0) { + $productIntegral = ceil(bcdiv($productIntegralPrice, $sysIntegralConfig['integral_money'], 3)); + if ($productIntegral <= $userIntegral) { + $userIntegral = bcsub($userIntegral, $productIntegral, 0); + //使用多少积分抵扣了多少金额 + $cart['integral'] = [ + 'use' => $productIntegral, + 'price' => $productIntegralPrice + ]; + } else { + $productIntegralPrice = bcmul($userIntegral, $sysIntegralConfig['integral_money'], 2); + //使用多少积分抵扣了多少金额 + $cart['integral'] = [ + 'use' => $userIntegral, + 'price' => $productIntegralPrice + ]; + $userIntegral = 0; + } + + $cart['true_price'] = bcsub($cart['true_price'], $cart['integral']['price'], 2); + $merchantCart['order']['true_price'] = bcsub($merchantCart['order']['true_price'], $cart['integral']['price'], 2); + + $total_integral_price = bcadd($total_integral_price, $cart['integral']['price'], 2); + $total_integral = bcadd($total_integral, $cart['integral']['use'], 0); + continue; + } + } + } + $cart['integral'] = null; + } + unset($cart); + $order_total_integral = bcadd($order_total_integral, $total_integral, 0); + $order_total_integral_price = bcadd($order_total_integral_price, $total_integral_price, 2); + + $_pay_price = $merchantCart['order']['true_price']; + $valid_total_price = $merchantCart['order']['valid_total_price']; + $total_price = $merchantCart['order']['total_price']; + $final_price = $merchantCart['order']['final_price']; + $down_price = $merchantCart['order']['down_price']; + $coupon_price = $merchantCart['order']['coupon_price']; + $postage_price = $merchantCart['order']['postage_price']; + + //计算订单商品金额 + $org_price = bcadd(bcsub($total_price, $valid_total_price, 2), max($_pay_price, 0), 2); + if ($presellType == 2) { + $org_price = max(bcsub($org_price, $final_price, 2), $down_price); + } + + //获取可优惠金额 + $coupon_price = min($coupon_price, bcsub($total_price, $down_price, 2)); + $order_coupon_price = bcadd($coupon_price, $order_coupon_price, 2); + + //计算订单金额 + if ($order_type != 2 || $presellType != 2) { + $pay_price = bcadd($postage_price, $org_price, 2); + } else { + $pay_price = $org_price; + } + + $giveIntegralFlag = $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_order_rate'] > 0; + $total_give_integral = 0; + //计算赠送积分, 只有普通商品赠送积分 + if ($giveIntegralFlag && !$order_type && $pay_price > 0) { + $total_give_integral = floor(bcmul($pay_price, $sysIntegralConfig['integral_order_rate'], 0)); + if ($total_give_integral > 0 && $svip_status && $svip_integral_rate > 0) { + $total_give_integral = bcmul($svip_integral_rate, $total_give_integral, 0); + } + } + $order_total_give_integral = bcadd($total_give_integral, $order_total_give_integral, 0); + + foreach ($fn as $callback) { + $callback(); + } + + $merchantCart['order']['order_type'] = $order_type; + $merchantCart['order']['total_give_integral'] = $total_give_integral; + $merchantCart['order']['total_integral_price'] = $total_integral_price; + $merchantCart['order']['total_integral'] = $total_integral; + $merchantCart['order']['org_price'] = $org_price; + $merchantCart['order']['pay_price'] = $pay_price; + $merchantCart['order']['coupon_price'] = $coupon_price; + + $order_price = bcadd($order_price, $pay_price, 2); + $order_total_price = bcadd($order_total_price, $total_price, 2); + } + unset($merchantCart); + + if ($order_model) { + $allow_no_address = false; + } + + foreach ($merchantCartList as &$merchantCart) { + foreach ($merchantCart['list'] as &$cart) { + $cart['total_price'] = bcadd($cart['total_price'], $cart['svip_discount'], 2); + } + unset($cart); + $merchantCart['order']['total_price'] = bcadd($merchantCart['order']['total_price'], $merchantCart['order']['svip_discount'], 2); + $order_total_price = bcadd($order_total_price, $merchantCart['order']['svip_discount'], 2); + } + unset($merchantCart); + + $status = ($address || $order_model || $allow_no_address) ? ($noDeliver ? 'noDeliver' : 'finish') : 'noAddress'; + $order = $merchantCartList; + $total_price = $order_total_price; + $openIntegral = $merIntegralFlag && !$order_type && $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_money'] > 0; + $total_coupon = bcadd($order_svip_discount, bcadd(bcadd($total_platform_coupon_price, $order_coupon_price, 2), $order_total_integral_price, 2), 2); + return compact( + 'order_type', + 'order_model', + 'order_extend', + 'order_total_postage', + 'order_price', + 'total_price', + 'platformCoupon', + 'enabledPlatformCoupon', + 'usePlatformCouponId', + 'order_total_integral', + 'order_total_integral_price', + 'order_total_give_integral', + 'order_svip_discount', + 'total_platform_coupon_price', + 'total_coupon', + 'order_coupon_price', + 'order', + 'status', + 'address', + 'openIntegral', + 'useIntegral', + 'key' + ) + ['allow_address' => !$allow_no_address, 'order_delivery_status' => $orderDeliveryStatus]; + } + + public function v2CreateOrder(int $pay_type, $user, array $cartId, array $extend, array $mark, array $receipt_data, array $takes = null, array $useCoupon = null, bool $useIntegral = false, int $addressId = null, array $post) + { + $uid = $user->uid; + $orderInfo = $this->v2CartIdByOrderInfo($user, $cartId, $takes, $useCoupon, $useIntegral, $addressId, true); + $order_model = $orderInfo['order_model']; + $order_extend = $orderInfo['order_extend']; + if (!$orderInfo['order_delivery_status']) { + throw new ValidateException('部分商品配送方式不一致,请单独下单'); + } + if ($orderInfo['order_price'] > 1000000) { + throw new ValidateException('支付金额超出最大限制'); + } + if ($orderInfo['status'] == 'noDeliver') throw new ValidateException('部分商品不支持该区域'); + if ($orderInfo['status'] == 'noAddress') throw new ValidateException('请选择地址'); + if (!$order_model && $orderInfo['allow_address']) { + if (!$orderInfo['address']) throw new ValidateException('请选择正确的收货地址'); + if (!$orderInfo['address']['province_id']) throw new ValidateException('请完善收货地址信息'); + $extend = []; + } else if (count($order_extend)) { + $extend = app()->make(OrderVirtualFieldValidate::class)->load($order_extend, $extend); + } else { + $extend = []; + } + $orderType = $orderInfo['order_type']; + if ($orderType && (count($orderInfo['order']) > 1 || ($orderType != 10 && count($orderInfo['order'][0]['list']) > 1))) { + throw new ValidateException('活动商品请单独购买'); + } + + $merchantCartList = $orderInfo['order']; + $cartSpread = 0; + $hasTake = false; + + foreach ($merchantCartList as $merchantCart) { + if ($merchantCart['order']['isTake']) { + $hasTake = true; + } + //检查发票状态 + if (isset($receipt_data[$merchantCart['mer_id']]) && !$merchantCart['openReceipt']) + throw new ValidateException('该店铺不支持开发票'); + + foreach ($merchantCart['list'] as $cart) { + if (!$cartSpread && $cart['spread_id']) { + $cartSpread = $cart['spread_id']; + } + } + } + if ($hasTake) { + app()->make(UserAddressValidate::class)->scene('take')->check($post); + } + + if ($cartSpread) { + app()->make(UserRepository::class)->bindSpread($user, $cartSpread); + } + + $isSelfBuy = $user->is_promoter && systemConfig('extension_self') ? 1 : 0; + if ($isSelfBuy) { + $spreadUser = $user; + $topUser = $user->valid_spread; + } else { + $spreadUser = $user->valid_spread; + $topUser = $user->valid_top; + } + $spreadUid = $spreadUser->uid ?? 0; + $topUid = $topUser->uid ?? 0; + + $merchantRepository = app()->make(MerchantRepository::class); + $giveCouponIds = []; + $ex = systemConfig('extension_status'); + $address = $orderInfo['address']; + $allUseCoupon = $orderInfo['usePlatformCouponId'] ? [$orderInfo['usePlatformCouponId']] : []; + $totalNum = 0; + $totalPostage = 0; + $totalCost = 0; + $cartIds = []; + $orderList = []; + + foreach ($merchantCartList as $k => $merchantCart) { + $cost = 0; + $total_extension_one = 0; + $total_extension_two = 0; + //计算佣金和赠送的优惠券 + foreach ($merchantCart['list'] as &$cart) { + $cartIds[] = $cart['cart_id']; + $giveCouponIds = array_merge($giveCouponIds, $cart['product']['give_coupon_ids'] ?: []); + $cart['cost'] = $cart['productAttr']['cost']; + $cost = bcadd(bcmul($cart['cost'], $cart['cart_num'], 2), $cost, 2); + $extension_one = 0; + $extension_two = 0; + if ($ex) { + //预售订单 + if ($orderType == 2) { + $_payPrice = $merchantCart['order']['pay_price']; + $rate = $cart['productPresell']['presell_type'] == 2 ? bcdiv($cart['productPresellAttr']['down_price'], $cart['productPresellAttr']['presell_price'], 3) : 1; + $one_price = $_payPrice > 0 ? bcdiv($_payPrice, $cart['cart_num'], 2) : 0; + if ($spreadUid && $cart['productPresellAttr']['bc_extension_one'] > 0) { + $org_extension = $cart['productPresellAttr']['bc_extension_one']; + if ($spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); + } + $_extension_one = bcmul($rate, $org_extension, 3); + $presell_extension_one = 0; + if ($cart['true_price'] > 0) { + $extension_one = bcmul(bcdiv($one_price, $cart['productPresellAttr']['down_price'], 3), $_extension_one, 2); + } + if ($rate < 1) { + $presell_extension_one = bcmul(1 - $rate, $org_extension, 2); + } + $cart['final_extension_one'] = bcmul($extension_one, $cart['cart_num'], 2); + $extension_one = bcadd($extension_one, $presell_extension_one, 2); + $cart['presell_extension_one'] = bcmul($presell_extension_one, $cart['cart_num'], 2); + } + if ($topUid && $cart['productPresellAttr']['bc_extension_two'] > 0) { + $org_extension = $cart['productPresellAttr']['bc_extension_two']; + if ($topUser->brokerage_level > 0 && $topUser->brokerage && $topUser->brokerage->extension_two_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $topUser->brokerage->extension_two_rate, 2); + } + $_extension_two = bcmul($rate, $org_extension, 2); + $presell_extension_two = 0; + if ($cart['true_price'] > 0) { + $extension_two = bcmul(bcdiv($one_price, $cart['productPresellAttr']['down_price'], 3), $_extension_two, 2); + } + if ($rate < 1) { + $presell_extension_two = bcmul(1 - $rate, $org_extension, 2); + } + $cart['final_extension_two'] = bcmul($extension_two, $cart['cart_num'], 2);; + $extension_two = bcadd($extension_two, $presell_extension_two, 2); + $cart['presell_extension_two'] = bcmul($presell_extension_two, $cart['cart_num'], 2); + } + } else if (!$orderType) { + if ($spreadUid && $cart['productAttr']['bc_extension_one'] > 0) { + $org_extension = $cart['productAttr']['bc_extension_one']; + if ($spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2); + } + $extension_one = $cart['true_price'] > 0 ? bcmul(bcdiv($cart['true_price'], $cart['total_price'], 3), $org_extension, 2) : 0; + } + if ($topUid && $cart['productAttr']['bc_extension_two'] > 0) { + $org_extension = $cart['productAttr']['bc_extension_two']; + if ($topUser->brokerage_level > 0 && $topUser->brokerage && $topUser->brokerage->extension_two_rate > 0) { + $org_extension = bcmul($org_extension, 1 + $topUser->brokerage->extension_two_rate, 2); + } + $extension_two = $cart['true_price'] > 0 ? bcmul(bcdiv($cart['true_price'], $cart['total_price'], 3), $org_extension, 2) : 0; + } + } + } + $cart['extension_one'] = $extension_one; + $cart['extension_two'] = $extension_two; + $total_extension_one = bcadd($total_extension_one, bcmul($extension_one, $cart['cart_num'], 2), 2); + $total_extension_two = bcadd($total_extension_two, bcmul($extension_two, $cart['cart_num'], 2), 2); + } + unset($cart); + + $rate = 0; + if ($merchantCart['commission_rate'] > 0) { + $rate = $merchantCart['commission_rate']; + } else if (isset($merchantCart['merchantCategory']['commission_rate']) && $merchantCart['merchantCategory']['commission_rate'] > 0) { + $rate = bcmul($merchantCart['merchantCategory']['commission_rate'], 100, 4); + } + $user_address = isset($address) ? ($address['province'] . $address['city'] . $address['district'] . $address['street'] . $address['detail']) : ''; + //整理订单数据 + $_order = [ + 'cartInfo' => $merchantCart, + 'activity_type' => $orderInfo['order_type'], + 'commission_rate' => (float)$rate, + 'order_type' => $merchantCart['order']['isTake'] ? 1 : 0, + 'is_virtual' => $order_model ? 1 : 0, + 'extension_one' => $total_extension_one, + 'extension_two' => $total_extension_two, + 'order_sn' => $this->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . ($k + 1), + 'uid' => $uid, + 'spread_uid' => $spreadUid, + 'top_uid' => $topUid, + 'is_selfbuy' => $isSelfBuy, + 'real_name' => $merchantCart['order']['isTake'] ? $post['real_name'] : ($address['real_name'] ?? ''), + 'user_phone' => $merchantCart['order']['isTake'] ? $post['phone'] : ($address['phone'] ?? ''), + 'user_address' => $user_address, + 'cart_id' => implode(',', array_column($merchantCart['list'], 'cart_id')), + 'total_num' => $merchantCart['order']['total_num'], + 'total_price' => $merchantCart['order']['total_price'], + 'total_postage' => $merchantCart['order']['postage_price'], + 'pay_postage' => $merchantCart['order']['postage_price'], + 'svip_discount' => $merchantCart['order']['svip_discount'], + 'pay_price' => $merchantCart['order']['pay_price'], + 'integral' => $merchantCart['order']['total_integral'], + 'integral_price' => $merchantCart['order']['total_integral_price'], + 'give_integral' => $merchantCart['order']['total_give_integral'], + 'mer_id' => $merchantCart['mer_id'], + 'cost' => $cost, + 'order_extend' => count($extend) ? json_encode($extend, JSON_UNESCAPED_UNICODE) : '', + 'coupon_id' => implode(',', $merchantCart['order']['useCouponIds']), + 'mark' => $mark[$merchantCart['mer_id']] ?? '', + 'coupon_price' => bcadd($merchantCart['order']['coupon_price'], $merchantCart['order']['platform_coupon_price'], 2), + 'platform_coupon_price' => $merchantCart['order']['platform_coupon_price'], + 'pay_type' => $pay_type + ]; + $allUseCoupon = array_merge($allUseCoupon, $merchantCart['order']['useCouponIds']); + $orderList[] = $_order; + $totalPostage = bcadd($totalPostage, $_order['total_postage'], 2); + $totalCost = bcadd($totalCost, $cost, 2); + $totalNum += $merchantCart['order']['total_num']; + } + $groupOrder = [ + 'uid' => $uid, + 'group_order_sn' => count($orderList) === 1 ? $orderList[0]['order_sn'] : ($this->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . '0'), + 'total_postage' => $totalPostage, + 'total_price' => $orderInfo['total_price'], + 'total_num' => $totalNum, + 'real_name' => $address['real_name'] ?? '', + 'user_phone' => $address['phone'] ?? '', + 'user_address' => $user_address, + 'pay_price' => $orderInfo['order_price'], + 'coupon_price' => bcadd($orderInfo['total_platform_coupon_price'], $orderInfo['order_coupon_price'], 2), + 'pay_postage' => $totalPostage, + 'cost' => $totalCost, + 'coupon_id' => $orderInfo['usePlatformCouponId'] > 0 ? $orderInfo['usePlatformCouponId'] : '', + 'pay_type' => $pay_type, + 'give_coupon_ids' => $giveCouponIds, + 'integral' => $orderInfo['order_total_integral'], + 'integral_price' => $orderInfo['order_total_integral_price'], + 'give_integral' => $orderInfo['order_total_give_integral'], + ]; + event('order.create.before', compact('groupOrder', 'orderList')); + $group = Db::transaction(function () use ($ex, $user, $topUid, $spreadUid, $uid, $receipt_data, $cartIds, $allUseCoupon, $groupOrder, $orderList, $orderInfo) { + $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class); + $storeCartRepository = app()->make(StoreCartRepository::class); + $attrValueRepository = app()->make(ProductAttrValueRepository::class); + $productRepository = app()->make(ProductRepository::class); + $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class); + $couponUserRepository = app()->make(StoreCouponUserRepository::class); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $userMerchantRepository = app()->make(UserMerchantRepository::class); + + //减库存 + foreach ($orderList as $order) { + foreach ($order['cartInfo']['list'] as $cart) { + if (!isset($uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']])) + $uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']] = true; + else + throw new ValidateException('购物车商品信息重复'); + + try { + if ($cart['product_type'] == '1') { + $attrValueRepository->descSkuStock($cart['product']['old_product_id'], $cart['productAttr']['sku'], $cart['cart_num']); + $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']); + } else if ($cart['product_type'] == '2') { + $productPresellSkuRepository = app()->make(ProductPresellSkuRepository::class); + $productPresellSkuRepository->descStock($cart['productPresellAttr']['product_presell_id'], $cart['productPresellAttr']['unique'], $cart['cart_num']); + $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']); + } else if ($cart['product_type'] == '3') { + app()->make(ProductAssistSkuRepository::class)->descStock($cart['productAssistAttr']['product_assist_id'], $cart['productAssistAttr']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']); + $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + } else if ($cart['product_type'] == '4') { + app()->make(ProductGroupSkuRepository::class)->descStock($cart['activeSku']['product_group_id'], $cart['activeSku']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']); + $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + } else { + $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']); + $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']); + if ($cart['integral'] && $cart['integral']['use'] > 0) { + $productRepository->incIntegral($cart['product']['product_id'], $cart['integral']['use'], $cart['integral']['price']); + } + } + } catch (\Exception $e) { + throw new ValidateException('库存不足'); + } + } + } + + if ($orderInfo['order_type'] == 10 && !app()->make(StoreDiscountRepository::class)->decStock($orderList[0]['cartInfo']['list'][0]['source_id'])) { + throw new ValidateException('套餐库不足'); + } + + //修改购物车状态 + $storeCartRepository->updates($cartIds, [ + 'is_pay' => 1 + ]); + + //使用优惠券 + if (count($allUseCoupon)) { + $couponUserRepository->updates($allUseCoupon, [ + 'use_time' => date('Y-m-d H:i:s'), + 'status' => 1 + ]); + } + + //创建订单 + $groupOrder = $storeGroupOrderRepository->create($groupOrder); + $bills = []; + + if ($groupOrder['integral'] > 0) { + $user->integral = bcsub($user->integral, $groupOrder['integral'], 0); + app()->make(UserBillRepository::class)->decBill($user['uid'], 'integral', 'deduction', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 1, + 'title' => '购买商品', + 'number' => $groupOrder['integral'], + 'mark' => '购买商品使用积分抵扣' . floatval($groupOrder['integral_price']) . '元', + 'balance' => $user->integral + ]); + $user->save(); + } + + foreach ($orderList as $k => $order) { + $orderList[$k]['group_order_id'] = $groupOrder->group_order_id; + } + + $orderProduct = []; + $orderStatus = []; + foreach ($orderList as $order) { + $cartInfo = $order['cartInfo']; + unset($order['cartInfo']); + //创建子订单 + $_order = $this->dao->create($order); + + if ($order['integral'] > 0) { + $bills[] = [ + 'uid' => $uid, + 'link_id' => $_order->order_id, + 'pm' => 0, + 'title' => '积分抵扣', + 'category' => 'mer_integral', + 'type' => 'deduction', + 'number' => $order['integral'], + 'balance' => $user->integral, + 'mark' => '购买商品使用' . $order['integral'] . '积分抵扣' . floatval($order['integral_price']) . '元', + 'mer_id' => $order['mer_id'], + 'status' => 1 + ]; + } + + //创建发票信息 + if (isset($receipt_data[$_order['mer_id']])) { + app()->make(StoreOrderReceiptRepository::class)->add($receipt_data[$_order['mer_id']], $_order); + } + + $orderStatus[] = [ + 'order_id' => $_order->order_id, + 'order_sn' => $_order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单生成', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CREATE, + 'uid' => $user->uid, + 'nickname' => $user->nickname, + 'user_type' => $storeOrderStatusRepository::U_TYPE_USER, + ]; + + foreach ($cartInfo['list'] as $cart) { + + $productPrice = $cart['true_price']; + $extension_one = $cart['extension_one']; + $extension_two = $cart['extension_two']; + + //计算预售订单尾款 + if ($cartInfo['order']['order_type'] == 2) { + $finalPrice = max(bcsub($cartInfo['order']['final_price'], $cartInfo['order']['coupon_price'], 2), 0); + $allFinalPrice = $order['order_type'] ? $finalPrice : bcadd($finalPrice, $order['pay_postage'], 2); + if ($cart['productPresell']['presell_type'] == 1) { + $productPrice = bcsub($cartInfo['order']['pay_price'], $order['pay_postage'], 2); + } else { + $productPrice = bcadd($cartInfo['order']['pay_price'], $finalPrice, 2); + } + //生成尾款订单 + if ($cart['productPresell']['presell_type'] == 2) { + $presellOrderRepository = app()->make(PresellOrderRepository::class); + $presellOrderRepository->create([ + 'uid' => $uid, + 'order_id' => $_order->order_id, + 'mer_id' => $_order->mer_id, + 'final_start_time' => $cart['productPresell']['final_start_time'], + 'final_end_time' => $cart['productPresell']['final_end_time'], + 'pay_price' => $allFinalPrice, + 'presell_order_sn' => $this->getNewOrderId(StoreOrderRepository::TYPE_SN_PRESELL) + ]); + } + app()->make(ProductPresellSkuRepository::class)->incCount($cart['source_id'], $cart['productAttr']['unique'], 'one_take'); + } + + $order_cart = [ + 'product' => $cart['product'], + 'productAttr' => $cart['productAttr'], + 'product_type' => $cart['product_type'] + ]; + + if ($cart['product_type'] == '2') { + $order_cart['productPresell'] = $cart['productPresell']; + $order_cart['productPresellAttr'] = $cart['productPresellAttr']; + $order_cart['final_extension_one'] = $cart['final_extension_one'] ?? 0; + $order_cart['final_extension_two'] = $cart['final_extension_two'] ?? 0; + $order_cart['presell_extension_one'] = $cart['presell_extension_one'] ?? 0; + $order_cart['presell_extension_two'] = $cart['presell_extension_two'] ?? 0; + } else if ($cart['product_type'] == '3') { + $order_cart['productAssistAttr'] = $cart['productAssistAttr']; + $order_cart['productAssistSet'] = $cart['productAssistSet']; + } else if ($cart['product_type'] == '4') { + $order_cart['activeSku'] = $cart['activeSku']; + } else if ($cart['product_type'] == '10') { + $order_cart['active'] = $cart['productDiscount']; + $order_cart['activeSku'] = $cart['productDiscountAttr']; + } + + $orderProduct[] = [ + 'order_id' => $_order->order_id, + 'cart_id' => $cart['cart_id'], + 'uid' => $uid, + 'product_id' => $cart['product_id'], + 'activity_id' => $cart['source'] >= 2 ? $cart['source_id'] : $cart['product_id'], + 'total_price' => $cart['total_price'], + 'product_price' => $productPrice, + 'extension_one' => $extension_one, + 'extension_two' => $extension_two, + 'postage_price' => $cart['postage_price'], + 'svip_discount' => $cart['svip_discount'], + 'cost' => $cart['cost'], + 'coupon_price' => $cart['coupon_price'], + 'platform_coupon_price' => $cart['platform_coupon_price'], + 'product_sku' => $cart['productAttr']['unique'], + 'product_num' => $cart['cart_num'], + 'refund_num' => $cart['cart_num'], + 'integral_price' => $cart['integral']['price'] ?? 0, + 'integral' => $cart['integral'] ? bcdiv($cart['integral']['use'], $cart['cart_num'], 0) : 0, + 'integral_total' => $cart['integral'] ? $cart['integral']['use'] : 0, + 'product_type' => $cart['product_type'], + 'cart_info' => json_encode($order_cart) + ]; + } + + $userMerchantRepository->getInfo($uid, $order['mer_id']); + app()->make(MerchantRepository::class)->incSales($order['mer_id'], $order['total_num']); + } + + if (count($bills) > 0) { + app()->make(UserBillRepository::class)->insertAll($bills); + } + $storeOrderStatusRepository->batchCreateLog($orderStatus); + $storeOrderProductRepository->insertAll($orderProduct); + event('order.create', compact('groupOrder')); + return $groupOrder; + }); + foreach ($merchantCartList as $merchantCart) { + foreach ($merchantCart['list'] as $cart) { + if (($cart['productAttr']['stock'] - $cart['cart_num']) < (int)merchantConfig($merchantCart['mer_id'], 'mer_store_stock')) { + SwooleTaskService::merchant('notice', [ + 'type' => 'min_stock', + 'data' => [ + 'title' => '库存不足', + 'message' => $cart['product']['store_name'] . '(' . $cart['productAttr']['sku'] . ')库存不足', + 'id' => $cart['product']['product_id'] + ] + ], $merchantCart['mer_id']); + } + } + } + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_CREATE', 'id' => $group->group_order_id]); + return $group; + } +} diff --git a/app/common/repositories/store/order/StoreOrderProductRepository.php b/app/common/repositories/store/order/StoreOrderProductRepository.php new file mode 100644 index 00000000..14e80776 --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderProductRepository.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreOrderProductDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\SpuRepository; + +/** + * Class StoreOrderProductRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/8 + * @mixin StoreOrderProductDao + */ +class StoreOrderProductRepository extends BaseRepository +{ + /** + * StoreOrderProductRepository constructor. + * @param StoreOrderProductDao $dao + */ + public function __construct(StoreOrderProductDao $dao) + { + $this->dao = $dao; + } + + public function getUserPayProduct(?string $keyword, int $uid, int $page, int $limit) + { + $query = $this->dao->getUserPayProduct($keyword, $uid)->group('product_id'); + $count = $query->count(); + $list = $query->setOption('field',[])->field('StoreOrderProduct.uid,StoreOrderProduct.product_id,StoreOrderProduct.product_type,spu_id,image,store_name,price') + ->page($page, $limit)->select()->toArray(); + return compact('count', 'list'); + } + +} diff --git a/app/common/repositories/store/order/StoreOrderProfitsharingRepository.php b/app/common/repositories/store/order/StoreOrderProfitsharingRepository.php new file mode 100644 index 00000000..509efe2f --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderProfitsharingRepository.php @@ -0,0 +1,104 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreOrderProfitsharingDao; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreOrderProfitsharing; +use app\common\model\store\order\StoreRefundOrder; +use app\common\repositories\BaseRepository; +use crmeb\services\WechatService; +use think\exception\ValidateException; + +/** + * @mixin StoreOrderProfitsharingDao + */ +class StoreOrderProfitsharingRepository extends BaseRepository +{ + + const PROFITSHARING_TYPE_ORDER = 'order'; + const PROFITSHARING_TYPE_PRESELL = 'presell'; + /** + * @var StoreOrderProfitsharingDao + */ + protected $dao; + + public function __construct(StoreOrderProfitsharingDao $storeOrderProfitsharingDao) + { + $this->dao = $storeOrderProfitsharingDao; + } + + public function getList(array $where, $page, $limit, $merchant = false) + { + $query = $this->dao->search($where)->with(['order' => function ($query) { + $query->field('order_id,order_sn'); + }])->order('create_time DESC'); + $count = $query->count(); + $append = ['statusName', 'typeName']; + if (!$merchant) { + $append[] = 'merchant'; + } + $list = $query->page($page, $limit)->append($append)->select(); + return compact('list', 'count'); + } + + public function refundPrice(StoreRefundOrder $refundOrder, $price, $refundMerPrice) + { + $this->refundPresallPrice($refundOrder, $price, $refundMerPrice, true); + } + + public function refundPresallPrice(StoreRefundOrder $refundOrder, $price, $refundMerPrice, $order = false) + { + $model = $order ? $refundOrder->order->firstProfitsharing : $refundOrder->order->presellProfitsharing; + if (!$model) + throw new ValidateException('分账订单不存在'); + $model->profitsharing_refund = bcadd($model->profitsharing_refund, $price, 2); + $model->profitsharing_mer_price = bcsub($model->profitsharing_mer_price, $refundMerPrice, 2); + if ($model->profitsharing_refund >= $model->profitsharing_price) { + $model->status = -1; + } + $model->save(); + } + + public function profitsharingOrder(StoreOrder $storeOrder) + { + foreach ($storeOrder->profitsharing as $profitsharing) { + $this->profitsharing($profitsharing); + } + } + + public function profitsharing(StoreOrderProfitsharing $profitsharing) + { + $status = 1; + $error_msg = ''; + $flag = true; + try { + if (bcsub($profitsharing->profitsharing_price, $profitsharing->profitsharing_mer_price, 2) > 0) { + WechatService::create()->combinePay()->profitsharingOrder($profitsharing->getProfitsharingParmas(), true); + } else { + WechatService::create()->combinePay()->profitsharingFinishOrder($profitsharing->getProfitsharingFinishParmas()); + } + $profitsharing->profitsharing_time = date('Y-m-d H:i:s'); + } catch (\Exception $e) { + $status = -2; + $error_msg = $e->getMessage(); + $flag = false; + } + $profitsharing->status = $status; + $profitsharing->error_msg = $error_msg; + $profitsharing->save(); + return $flag; + } + +} diff --git a/app/common/repositories/store/order/StoreOrderReceiptRepository.php b/app/common/repositories/store/order/StoreOrderReceiptRepository.php new file mode 100644 index 00000000..c04a14ca --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderReceiptRepository.php @@ -0,0 +1,223 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\order; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\order\StoreOrderReceiptDao; +use app\common\model\store\order\StoreOrder; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\exception\ValidateException; +use think\facade\Route; + +/** + * @mixin StoreOrderReceiptDao + */ +class StoreOrderReceiptRepository extends BaseRepository +{ + public function __construct(StoreOrderReceiptDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 生成信息 + * @param array $receiptData + * @param StoreOrder $orderData + * @param null $orderPrice + * @author Qinii + * @day 2020-10-16 + */ + public function add(array $receiptData,StoreOrder $orderData, $orderPrice = null) + { + if($this->dao->getWhereCount(['order_id' => $orderData->order_id])) + throw new ValidateException('该订单已存在发票信息'); + + if (!$receiptData['receipt_type'] || + !$receiptData['receipt_title_type'] || + !$receiptData['receipt_title'] + ) throw new ValidateException('发票信息不全'); + + if($receiptData['receipt_type'] == 1){ + $receipt_info = [ + 'receipt_type' => $receiptData['receipt_type'], + 'receipt_title_type' => $receiptData['receipt_title_type'], + 'receipt_title' => $receiptData['receipt_title'], + 'duty_paragraph' => $receiptData['duty_paragraph'] + ]; + $delivery_info = [ + 'email' => $receiptData['email'] + ]; + } + if($receiptData['receipt_type'] == 2){ + if ( + !$receiptData['duty_paragraph'] || + !$receiptData['bank_name'] || + !$receiptData['bank_code'] || + !$receiptData['address'] || + !$receiptData['tel'] + ) throw new ValidateException('发票信息不全'); + $receipt_info = [ + 'receipt_type' => $receiptData['receipt_type'], + 'receipt_title_type' => $receiptData['receipt_title_type'], + 'receipt_title' => $receiptData['receipt_title'], + 'duty_paragraph' => $receiptData['duty_paragraph'], + 'bank_name' => $receiptData['bank_name'], + 'bank_code' => $receiptData['bank_code'], + 'address' => $receiptData['address'], + 'tel' => $receiptData['tel'], + ]; + $delivery_info = [ + 'user_name' => $orderData['real_name'], + 'user_phone' => $orderData['user_phone'], + 'user_address' => $orderData['user_address'], + ]; + } + $data = [ + 'order_id' => $orderData->order_id, + 'uid' => $orderData->uid, + 'mark' => $receiptData['mark'] ?? '', + 'order_price' => $orderPrice ?? $orderData['pay_price'], + 'receipt_info' => json_encode($receipt_info), + 'delivery_info'=> json_encode($delivery_info), + 'status_time' => date('Y-m-d H:i:s',time()), + 'mer_id' => $orderData->mer_id + ]; + $this->dao->create($data); + } + + /** + * TODO 列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-17 + */ + public function getList(array $where,int $page,int $limit) + { + $query = $this->dao->search($where)->with([ + 'storeOrder' => function ($query) { + $query->field('order_id,order_sn,real_name,user_phone,user_address,status,paid,is_del,pay_price,paid,group_order_id,mark'); + }, + 'user' => function ($query) { + $query->field('uid,nickname,phone'); + }, + 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + },]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + /** + * TODO 开票 + * @param string $ids + * @author Qinii + * @day 2020-10-17 + */ + public function setRecipt(string $ids,int $merId) + { + $data = $this->dao->getSearch(['order_receipt_ids' => $ids,'mer_id' => $merId])->order('create_time Desc')->select(); + $arr = $this->check($ids); + $receipt_price = 0; + foreach ($data as $item){ + if($item['status'] == 1) throw new ValidateException('存在已开票订单ID:'.$item['order_receipt_id']); + $receipt_price = bcadd($receipt_price,$item['order_price'],2); + $delivery_info = $item['delivery_info']; + } + $receipt_info = json_decode($arr[0]); + if($receipt_info->receipt_type == 1 ){ + $title = $receipt_info->receipt_title_type == 1 ? '个人电子普通发票' : '企业电子普通发票'; + }else{ + $title = '企业专用纸质发票'; + } + return $res = [ + "title" => $title, + "receipt_sn" => $this->receiptSn(), + "receipt_price" => $receipt_price, + 'receipt_info' => $receipt_info, + 'delivery_info' => $delivery_info, + 'status' => 0, + ]; + } + + public function merExists(string $ids,int $merId) + { + $ids = explode(',',$ids); + foreach ($ids as $id) { + if(!$this->dao->getSearch(['order_receipt_id' => $id,'mer_id' => $merId])->count()) + throw new ValidateException('数据有误,存在不属于您的发票ID'); + } + return true; + } + + /** + * TODO 保存合并的发票信息 + * @param array $data + * @author Qinii + * @day 2020-12-02 + */ + public function save(array $data) + { + $this->check($data['ids']); + $res = [ + "receipt_sn" => $data['receipt_sn'], + "receipt_price" => $data['receipt_price'], + 'status' => $data['receipt_no'] ? 1 : 2, + 'status_time' => date('Y-m-d H:i:s',time()), + 'receipt_no' => $data['receipt_no'], + 'mer_mark' => $data['mer_mark'] + ]; + $this->dao->updates(explode(',',$data['ids']),$res); + } + public function check(string $ids) + { + $query = $this->dao->getSearch(['order_receipt_ids' => $ids])->with(['storeOrder' => function($query){$query->field('order_id,paid');}]); + $result = $query->select(); + foreach ($result as $item){ + if(!$item->storeOrder['paid']) throw new ValidateException('订单未支付不可开发票'); + } + $data = $query->column('receipt_info'); + $arr = array_unique($data); + if(count($arr) > 1) throw new ValidateException('开票信息不相同,无法合并'); + return $arr; + } + + /** + * TODO 生成发票号 + * @return string + * @author Qinii + * @day 2020-10-17 + */ + public function receiptSn() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = 'PT' . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('merchantOrderReceiptMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('mer_mark', '备注', $data['mer_mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } +} diff --git a/app/common/repositories/store/order/StoreOrderRepository.php b/app/common/repositories/store/order/StoreOrderRepository.php new file mode 100644 index 00000000..517de878 --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderRepository.php @@ -0,0 +1,2407 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\order; + +use app\common\dao\store\order\StoreOrderDao; +use app\common\model\store\order\StoreGroupOrder; +use app\common\model\store\order\StoreOrder; +use app\common\model\user\User; +use app\common\repositories\BaseRepository; +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductPresellSkuRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\StoreDiscountRepository; +use app\common\repositories\store\shipping\ExpressRepository; +use app\common\repositories\store\StorePrinterRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\serve\ServeDumpRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserMerchantRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\PayGiveCouponJob; +use crmeb\jobs\SendSmsJob; +use crmeb\jobs\UserBrokerageLevelJob; +use crmeb\services\CombinePayService; +use crmeb\services\CrmebServeServices; +use crmeb\services\ExpressService; +use crmeb\services\PayService; +use crmeb\services\printer\Printer; +use crmeb\services\QrcodeService; +use crmeb\services\SpreadsheetExcelService; +use crmeb\services\SwooleTaskService; +use Exception; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use http\Exception\InvalidArgumentException; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Log; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class StoreOrderRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/9 + * @mixin StoreOrderDao + */ +class StoreOrderRepository extends BaseRepository +{ + /** + * 支付类型 + */ + const PAY_TYPE = ['balance', 'weixin', 'routine', 'h5', 'alipay', 'alipayQr', 'weixinQr']; + + const TYPE_SN_ORDER = 'wxo'; + const TYPE_SN_PRESELL = 'wxp'; + const TYPE_SN_USER_ORDER = 'wxs'; + const TYPE_SN_USER_RECHARGE = 'wxu'; + + const TYPE_SN_REFUND = 'rwx'; + /** + * StoreOrderRepository constructor. + * @param StoreOrderDao $dao + */ + public function __construct(StoreOrderDao $dao) + { + $this->dao = $dao; + } + + /** + * @param string $type + * @param User $user + * @param StoreGroupOrder $groupOrder + * @param string $return_url + * @return mixed + * @author xaboy + * @day 2020/10/22 + */ + public function pay(string $type, User $user, StoreGroupOrder $groupOrder, $return_url = '', $isApp = false) + { + + if ($type === 'balance') { + return $this->payBalance($user, $groupOrder); + } + + if (in_array($type, ['weixin', 'alipay'], true) && $isApp) { + $type .= 'App'; + } + event('order.pay.before', compact('groupOrder', 'type', 'isApp')); + if (in_array($type, ['weixin', 'weixinApp', 'routine', 'h5', 'weixinQr'], true) && systemConfig('open_wx_combine')) { + $service = new CombinePayService($type, $groupOrder->getCombinePayParams()); + } else { + $service = new PayService($type, $groupOrder->getPayParams($type === 'alipay' ? $return_url : '')); + } + $config = $service->pay($user); + return app('json')->status($type, $config + ['order_id' => $groupOrder['group_order_id']]); + } + + /** + * @param User $user + * @param StoreGroupOrder $groupOrder + * @return mixed + * @author xaboy + * @day 2020/6/9 + */ + public function payBalance(User $user, StoreGroupOrder $groupOrder) + { + if (!systemConfig('yue_pay_status')) + throw new ValidateException('未开启余额支付'); + if ($user['now_money'] < $groupOrder['pay_price']) + throw new ValidateException('余额不足,请更换支付方式'); + Db::transaction(function () use ($user, $groupOrder) { + $user->now_money = bcsub($user->now_money, $groupOrder['pay_price'], 2); + $user->save(); + $userBillRepository = app()->make(UserBillRepository::class); + $userBillRepository->decBill($user['uid'], 'now_money', 'pay_product', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 1, + 'title' => '购买商品', + 'number' => $groupOrder['pay_price'], + 'mark' => '余额支付支付' . floatval($groupOrder['pay_price']) . '元购买商品', + 'balance' => $user->now_money + ]); + $this->paySuccess($groupOrder); + }); + return app('json')->status('success', '余额支付成功', ['order_id' => $groupOrder['group_order_id']]); + } + + public function changePayType(StoreGroupOrder $groupOrder, int $pay_type) + { + Db::transaction(function () use ($groupOrder, $pay_type) { + $groupOrder->pay_type = $pay_type; + foreach ($groupOrder->orderList as $order) { + $order->pay_type = $pay_type; + $order->save(); + } + $groupOrder->save(); + }); + } + + /** + * @return string + * @author xaboy + * @day 2020/8/3 + */ + public function verifyCode() + { + $code = substr(uniqid('', true), 15) . substr(microtime(), 2, 8); + if ($this->dao->existsWhere(['verify_code' => $code])) + return $this->verifyCode(); + else + return $code; + } + + /** + * //TODO 支付成功后 + * + * @param StoreGroupOrder $groupOrder + * @author xaboy + * @day 2020/6/9 + */ + public function paySuccess(StoreGroupOrder $groupOrder, $is_combine = 0, $subOrders = []) + { + $groupOrder->append(['user']); + //修改订单状态 + Db::transaction(function () use ($subOrders, $is_combine, $groupOrder) { + $time = date('Y-m-d H:i:s'); + $groupOrder->paid = 1; + $groupOrder->pay_time = $time; + $groupOrder->is_combine = $is_combine; + $orderStatus = []; + $groupOrder->append(['orderList.orderProduct']); + $flag = true; + $finance = []; + $profitsharing = []; + $financialRecordRepository = app()->make(FinancialRecordRepository::class); + $financeSn = $financialRecordRepository->getSn(); + $userMerchantRepository = app()->make(UserMerchantRepository::class); + $storeOrderProfitsharingRepository = app()->make(StoreOrderProfitsharingRepository::class); + $uid = $groupOrder->uid; + $i = 1; + $isVipCoupon = app()->make(StoreGroupOrderRepository::class)->isVipCoupon($groupOrder); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $svipDiscount = 0; + foreach ($groupOrder->orderList as $_k => $order) { + $order->paid = 1; + $order->pay_time = $time; + $svipDiscount = bcadd($order->svip_discount, $svipDiscount, 2); + if (isset($subOrders[$order->order_sn])) { + $order->transaction_id = $subOrders[$order->order_sn]['transaction_id']; + } + $presell = false; + //todo 等待付尾款 + if ($order->activity_type == 2) { + $_make = app()->make(ProductPresellSkuRepository::class); + if ($order->orderProduct[0]['cart_info']['productPresell']['presell_type'] == 2) { + $order->status = 10; + $presell = true; + } else { + $_make->incCount($order->orderProduct[0]['activity_id'], $order->orderProduct[0]['product_sku'], 'two_pay'); + } + $_make->incCount($order->orderProduct[0]['activity_id'], $order->orderProduct[0]['product_sku'], 'one_pay'); + } else if ($order->activity_type == 4) { + $order->status = 9; + $order->save(); + $group_buying_id = app()->make(ProductGroupBuyingRepository::class)->create( + $groupOrder->user, + $order->orderProduct[0]['cart_info']['activeSku']['product_group_id'], + $order->orderProduct[0]['activity_id'], + $order->order_id + ); + $order->orderProduct[0]->activity_id = $group_buying_id; + $order->orderProduct[0]->save(); + } else if ($order->activity_type == 3) { + //更新助力状态 + app()->make(ProductAssistSetRepository::class)->changStatus($order->orderProduct[0]['activity_id']); + } + // 订单的类型 0 发货 1 自提 + if ($order->order_type == 1 && $order->status != 10) + { + $order->verify_code = $this->verifyCode(); + } + $order->save(); + $orderStatus[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单支付成功', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_PAY_SUCCCESS, + 'uid' => $order->uid, + 'nickname' => $order->user->nickname, + 'user_type' => $storeOrderStatusRepository::U_TYPE_USER, + ]; + + //TODO 成为推广员 + foreach ($order->orderProduct as $product) { + if ($flag && $product['cart_info']['product']['is_gift_bag']) { + app()->make(UserRepository::class)->promoter($order->uid); + $flag = false; + } + } + + // 商户流水账单数据 + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => $presell ? 'order_presell' : 'order', + 'financial_pm' => 1, + 'type' => $presell ? 2 : 1, + 'number' => $order->pay_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + + $_payPrice = bcsub($order->pay_price, bcadd($order['extension_one'], $order['extension_two'], 3), 2); + if ($presell) { + if (isset($order->orderProduct[0]['cart_info']['presell_extension_one']) && $order->orderProduct[0]['cart_info']['presell_extension_one'] > 0) { + $_payPrice = bcadd($_payPrice, $order->orderProduct[0]['cart_info']['presell_extension_one'], 2); + } + if (isset($order->orderProduct[0]['cart_info']['presell_extension_two']) && $order->orderProduct[0]['cart_info']['presell_extension_two'] > 0) { + $_payPrice = bcadd($_payPrice, $order->orderProduct[0]['cart_info']['presell_extension_two'], 2); + } + } + + $_order_rate = 0; + + if ($order['commission_rate'] > 0) { + + $commission_rate = ($order['commission_rate'] / 100); + + $_order_rate = bcmul($_payPrice, $commission_rate, 2); + + $_payPrice = bcsub($_payPrice, $_order_rate, 2); + } + + if (!$presell) { + if ($order['extension_one'] > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'brokerage_one', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order['extension_one'], + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + } + + if ($order['extension_two'] > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'brokerage_two', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order['extension_two'], + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + } + + if ($order['commission_rate'] > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'order_charge', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $_order_rate, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + } + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'order_true', + 'financial_pm' => 0, + 'type' => 2, + 'number' => $_payPrice, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + + if ($order->platform_coupon_price > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => $isVipCoupon ? 'order_svip_coupon' : 'order_platform_coupon', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order->platform_coupon_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + $_payPrice = bcadd($_payPrice, $order->platform_coupon_price, 2); + } + + if (!$is_combine) { + app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'order', $order->order_id, $_payPrice); + } + } + if ($is_combine) { + $profitsharing[] = [ + 'profitsharing_sn' => $storeOrderProfitsharingRepository->getOrderSn(), + 'order_id' => $order->order_id, + 'transaction_id' => $order->transaction_id ?? '', + 'mer_id' => $order->mer_id, + 'profitsharing_price' => $order->pay_price, + 'profitsharing_mer_price' => $_payPrice, + 'type' => $storeOrderProfitsharingRepository::PROFITSHARING_TYPE_ORDER, + ]; + } + $userMerchantRepository->updatePayTime($uid, $order->mer_id, $order->pay_price); + SwooleTaskService::merchant('notice', [ + 'type' => 'new_order', + 'data' => [ + 'title' => '新订单', + 'message' => '您有一个新的订单', + 'id' => $order->order_id + ] + ], $order->mer_id); + //自动打印订单 + $this->autoPrinter($order->order_id, $order->mer_id); + } + if ($groupOrder->user->spread_uid) { + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->user->spread_uid, 'type' => 'spread_pay_num', 'inc' => 1]); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->user->spread_uid, 'type' => 'spread_money', 'inc' => $groupOrder->pay_price]); + } + app()->make(UserRepository::class)->update($groupOrder->uid, [ + 'pay_count' => Db::raw('pay_count+' . count($groupOrder->orderList)), + 'pay_price' => Db::raw('pay_price+' . $groupOrder->pay_price), + 'svip_save_money' => Db::raw('svip_save_money+' . $svipDiscount), + ]); + $this->giveIntegral($groupOrder); + if (count($profitsharing)) { + $storeOrderProfitsharingRepository->insertAll($profitsharing); + } + $financialRecordRepository->insertAll($finance); + $storeOrderStatusRepository->batchCreateLog($orderStatus); + if (count($groupOrder['give_coupon_ids']) > 0) + $groupOrder['give_coupon_ids'] = app()->make(StoreCouponRepository::class)->getGiveCoupon($groupOrder['give_coupon_ids'])->column('coupon_id'); + $groupOrder->save(); + }); + + if (count($groupOrder['give_coupon_ids']) > 0) { + try { + Queue::push(PayGiveCouponJob::class, ['ids' => $groupOrder['give_coupon_ids'], 'uid' => $groupOrder['uid']]); + } catch (Exception $e) { + } + } + + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_PAY_SUCCESS', 'id' => $groupOrder->group_order_id]); + Queue::push(SendSmsJob::class, ['tempId' => 'ADMIN_PAY_SUCCESS_CODE', 'id' => $groupOrder->group_order_id]); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->uid, 'type' => 'pay_money', 'inc' => $groupOrder->pay_price]); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->uid, 'type' => 'pay_num', 'inc' => 1]); + app()->make(UserBrokerageRepository::class)->incMemberValue($groupOrder->uid, 'member_pay_num', $groupOrder->group_order_id); + event('order.paySuccess', compact('groupOrder')); + //店内扫码支付 + if (isset($groupOrder['micro_pay']) && $groupOrder['micro_pay'] == 1) { + $order = $this->dao->search(['uid' => $groupOrder->uid])->where('group_order_id', $groupOrder->group_order_id)->find(); + $order->status = 2; + $order->verify_time = date('Y-m-d H:i:s'); + $user=$order->user; + event('order.take.before', compact('order')); + Db::transaction(function () use ($order, $user) { + $this->takeAfter($order, $user); + $order->save(); + }); + event('order.take', compact('order')); + } + + } + + /** + * 自动打印 + * @Author:Qinii + * @Date: 2020/10/13 + * @param int $orderId + * @param int $merId + */ + public function autoPrinter(int $orderId, int $merId) + { + if (merchantConfig($merId, 'printing_auto_status')) { + try { + $this->batchPrinter($orderId, $merId); + } catch (Exception $exception) { + Log::info('自动打印小票报错:' . $exception); + } + } else { + Log::info('自动打印小票验证:商户ID【' . $merId . '】,自动打印状态未开启'); + } + } + + /** + * @return string + * @author xaboy + * @day 2020/6/9 + */ + public function getNewOrderId($type) + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = $type . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + /** + * @param $cart + * @return string + * @author xaboy + * @day 2020/6/9 + */ + public function productByTempNumber($cart) + { + $type = $cart['product']['temp']['type']; + $cartNum = $cart['cart_num']; + if (!$type) + return $cartNum; + else if ($type == 2) { + return bcmul($cartNum, $cart['productAttr']['volume'], 2); + } else { + return bcmul($cartNum, $cart['productAttr']['weight'], 2); + } + } + + public function cartByPrice($cart) + { + if ($cart['product_type'] == '2') { + return $cart['productPresellAttr']['presell_price']; + } else if ($cart['product_type'] == '3') { + return $cart['productAssistAttr']['assist_price']; + } else if ($cart['product_type'] == '4') { + return $cart['activeSku']['active_price']; + } else { + return $cart['productAttr']['price']; + } + } + + public function cartByCouponPrice($cart) + { + if ($cart['product_type'] == '2') { + return $cart['productPresellAttr']['final_price']; + } else if ($cart['product_type'] == '1') { + return 0; + } else if ($cart['product_type'] == '3') { + return 0; + } else if ($cart['product_type'] == '4') { + return 0; + } else { + return $cart['productAttr']['price']; + } + } + + public function cartByDownPrice($cart) + { + if ($cart['product_type'] == '2') { + return $cart['productPresellAttr']['down_price']; + } else { + return 0; + } + } + + + /** + * @param int $uid + * @return array + * @author xaboy + * @day 2020/6/10 + */ + public function userOrderNumber(int $uid, $product_type=0) + { + $noPay = app()->make(StoreGroupOrderRepository::class)->orderNumber($uid,$product_type); + $noPostage = $this->dao->search(['uid' => $uid, 'status' => 0, 'paid' => 1,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $all = $this->dao->search(['uid' => $uid, 'status' => -2,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $noDeliver = $this->dao->search(['uid' => $uid, 'status' => 1, 'paid' => 1])->where('StoreOrder.is_del', 0)->count(); + $noComment = $this->dao->search(['uid' => $uid, 'status' => 2, 'paid' => 1,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $done = $this->dao->search(['uid' => $uid, 'status' => 3, 'paid' => 1,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $refund = app()->make(StoreRefundOrderRepository::class)->getWhereCount(['uid' => $uid, 'status' => [0, 1, 2]]); + //$orderPrice = $this->dao->search(['uid' => $uid, 'paid' => 1])->sum('pay_price'); + $orderCount = $this->dao->search(['uid' => $uid, 'paid' => 1,'is_user' => 1])->count(); + return compact('noComment', 'done', 'refund', 'noDeliver', 'noPay', 'noPostage', 'orderCount', 'all'); + } + + /** + * @param $id + * @param null $uid + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function getDetail($id, $uid = null) + { + $where = []; + $with = [ + 'orderProduct', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name,service_phone')->append(['services_type']); + }, + 'receipt' => function ($query) { + return $query->field('order_id,order_receipt_id'); + }, + 'takeOrderList.orderProduct' + ]; + if ($uid) { + $where['uid'] = $uid; + } else if (!$uid) { + $with['user'] = function ($query) { + return $query->field('uid,nickname'); + }; + } + $order = $this->dao->search($where)->where('order_id', $id)->where('StoreOrder.is_del', 0)->with($with)->append(['refund_status'])->find(); + if (!$order) { + return null; + } + if ($order->activity_type == 2) { + if ($order->presellOrder) { + $order->presellOrder->append(['activeStatus']); + $order->presell_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2); + } else { + $order->presell_price = $order->pay_price; + } + } + return $order; + } + + public function codeByDetail($code, $uid = null) + { + $where = []; + if ($uid) $where['uid'] = $uid; + $data = $this->dao->search($where)->where('verify_code', $code) + ->where('StoreOrder.is_del', 0) + ->with([ + 'orderProduct', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name'); + } + ]) + ->find(); + if (!$data) + throw new ValidateException('数据不存在'); + if ($data['status']) + throw new ValidateException('该订单已全部核销'); + return $data; + } + + public function giveIntegral($groupOrder) + { + if ($groupOrder->give_integral > 0) { + app()->make(UserBillRepository::class)->incBill($groupOrder->uid, 'integral', 'lock', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 0, + 'title' => '下单赠送积分', + 'number' => $groupOrder->give_integral, + 'mark' => '成功消费' . floatval($groupOrder['pay_price']) . '元,赠送积分' . floatval($groupOrder->give_integral), + 'balance' => $groupOrder->user->integral + ]); + } + } + + /** + * @param StoreOrder $order + * @param User $user + * @author xaboy + * @day 2020/8/3 + */ + public function computed(StoreOrder $order, User $user) + { + $userBillRepository = app()->make(UserBillRepository::class); + if ($order->spread_uid) { + $spreadUid = $order->spread_uid; + $topUid = $order->top_uid; + } else if ($order->is_selfbuy) { + $spreadUid = $user->uid; + $topUid = $user->spread_uid; + } else { + $spreadUid = $user->spread_uid; + $topUid = $user->top_uid; + } + //TODO 添加冻结佣金 + if ($order->extension_one > 0 && $spreadUid) { + $userBillRepository->incBill($spreadUid, 'brokerage', 'order_one', [ + 'link_id' => $order['order_id'], + 'status' => 0, + 'title' => '获得推广佣金', + 'number' => $order->extension_one, + 'mark' => $user['nickname'] . '成功消费' . floatval($order['pay_price']) . '元,奖励推广佣金' . floatval($order->extension_one), + 'balance' => 0 + ]); + $userRepository = app()->make(UserRepository::class); + $userRepository->incBrokerage($spreadUid, $order->extension_one); + // app()->make(FinancialRecordRepository::class)->dec([ + // 'order_id' => $order->order_id, + // 'order_sn' => $order->order_sn, + // 'user_info' => $userRepository->getUsername($spreadUid), + // 'user_id' => $spreadUid, + // 'financial_type' => 'brokerage_one', + // 'number' => $order->extension_one, + // ], $order->mer_id); + } + if ($order->extension_two > 0 && $topUid) { + $userBillRepository->incBill($topUid, 'brokerage', 'order_two', [ + 'link_id' => $order['order_id'], + 'status' => 0, + 'title' => '获得推广佣金', + 'number' => $order->extension_two, + 'mark' => $user['nickname'] . '成功消费' . floatval($order['pay_price']) . '元,奖励推广佣金' . floatval($order->extension_two), + 'balance' => 0 + ]); + $userRepository = app()->make(UserRepository::class); + $userRepository->incBrokerage($topUid, $order->extension_two); + // app()->make(FinancialRecordRepository::class)->dec([ + // 'order_id' => $order->order_id, + // 'order_sn' => $order->order_sn, + // 'user_info' => $userRepository->getUsername($topUid), + // 'user_id' => $topUid, + // 'financial_type' => 'brokerage_two', + // 'number' => $order->extension_two, + // ], $order->mer_id); + } + } + + /** + * @param StoreOrder $order + * @param User $user + * @param string $type + * @author xaboy + * @day 2020/8/3 + */ + public function takeAfter(StoreOrder $order, ?User $user) + { + Db::transaction(function () use ($user, $order) { + if ($user) $this->computed($order, $user); + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_TAKE_SUCCESS', 'id' => $order->order_id]); + Queue::push(SendSmsJob::class, ['tempId' => 'ADMIN_TAKE_DELIVERY_CODE', 'id' => $order->order_id]); + app()->make(MerchantRepository::class)->computedLockMoney($order); + $order->save(); + }); + } + + /** + * @param $id + * @param User $user + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/17 + */ + public function takeOrder($id, ?User $user = null) + { + $order = $this->dao->search(!$user ? [] : ['uid' => $user->uid], null)->where('order_id', $id)->where('StoreOrder.is_del', 0)->find(); + if (!$order) + throw new ValidateException('订单不存在'); + if ($order['status'] != 1 || $order['order_type']) + throw new ValidateException('订单状态有误'); + $func = 'createUserLog'; + if (!$user){ + $func = 'createSysLog'; + $user = $order->user; + } +// if (!$user) { +// +// throw new ValidateException('用户不存在'); +// } + $order->status = 2; + $order->verify_time = date('Y-m-d H:i:s'); + event('order.take.before', compact('order')); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '已收货', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_TAKE, + ]; + Db::transaction(function () use ($order, $user,$storeOrderStatusRepository,$orderStatus,$func) { + $this->takeAfter($order, $user); + $order->save(); + $storeOrderStatusRepository->{$func}($orderStatus); + }); + event('order.take', compact('order')); + } + + + /** + * 获取订单列表头部统计数据 + * @Author:Qinii + * @Date: 2020/9/12 + * @param int|null $merId + * @param int|null $orderType + * @return array + */ + public function OrderTitleNumber(?int $merId, ?int $orderType, ?int $product_type=0) + { + $where = []; + $sysDel = $merId ? 0 : null; //商户删除 + if ($merId) $where['mer_id'] = $merId; //商户订单 + if ($orderType === 0) $where['order_type'] = 0; //普通订单 + if ($orderType === 1) $where['take_order'] = 1; //已核销订单 + if ($product_type!=0) $where['product_type'] = $product_type; //商品属性 + //1: 未支付 2: 未发货 3: 待收货 4: 待评价 5: 交易完成 6: 已退款 7: 已删除 + $all = $this->dao->search($where, $sysDel)->where($this->getOrderType(0))->count(); + $statusAll = $all; + $unpaid = $this->dao->search($where, $sysDel)->where($this->getOrderType(1))->count(); + $unshipped = $this->dao->search($where, $sysDel)->where($this->getOrderType(2))->count(); + $untake = $this->dao->search($where, $sysDel)->where($this->getOrderType(3))->count(); + $unevaluate = $this->dao->search($where, $sysDel)->where($this->getOrderType(4))->count(); + $complete = $this->dao->search($where, $sysDel)->where($this->getOrderType(5))->count(); + $refund = $this->dao->search($where, $sysDel)->where($this->getOrderType(6))->count(); + $del = $this->dao->search($where, $sysDel)->where($this->getOrderType(7))->count(); + + return compact('all', 'statusAll', 'unpaid', 'unshipped', 'untake', 'unevaluate', 'complete', 'refund', 'del'); + } + + public function orderType(array $where) + { + return [ + [ + 'count' => $this->dao->search($where)->count(), + 'title' => '全部', + 'order_type' => -1, + ], + [ + 'count' => $this->dao->search($where)->where('order_type', 0)->where('is_virtual', 0)->count(), + 'title' => '普通订单', + 'order_type' => 0, + ], + [ + 'count' => $this->dao->search($where)->where('order_type', 1)->count(), + 'title' => '核销订单', + 'order_type' => 1, + ], + [ + 'count' => $this->dao->search($where)->where('is_virtual', 1)->count(), + 'title' => '虚拟商品订单', + 'order_type' => 2, + ], + ]; + } + + /** + * @param $status + * @return mixed + * @author Qinii + */ + public function getOrderType($status) + { + $param['StoreOrder.is_del'] = 0; + switch ($status) { + case 1: + $param['paid'] = 0; + break; // 未支付 + case 2: + $param['paid'] = 1; + $param['StoreOrder.status'] = 0; + break; // 待发货 + case 3: + $param['StoreOrder.status'] = 1; + break; // 待收货 + case 4: + $param['StoreOrder.status'] = 2; + break; // 待评价 + case 5: + $param['StoreOrder.status'] = 3; + break; // 交易完成 + case 6: + $param['StoreOrder.status'] = -1; + break; // 已退款 + case 7: + $param['StoreOrder.is_del'] = 1; + break; // 待核销 + break; // 已删除 + default: + unset($param['StoreOrder.is_del']); + break; //全部 + } + return $param; + } + + /** + * @param int $id + * @param int|null $merId + * @return array|Model|null + * @author Qinii + */ + public function merDeliveryExists(int $id, ?int $merId, ?int $re = 0) + { + $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 1]; + if ($re) $where['status'] = 0; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + /** + * TODO + * @param int $id + * @param int|null $merId + * @return bool + * @author Qinii + * @day 2020-06-11 + */ + public function merGetDeliveryExists(int $id, ?int $merId) + { + $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 1, 'status' => 1]; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + /** + * @param int $id + * @param int|null $merId + * @return array|Model|null + * @author Qinii + */ + public function merStatusExists(int $id, ?int $merId) + { + $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 0, 'status' => 0]; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + public function userDelExists(int $id, ?int $merId) + { + $where = ['order_id' => $id, 'is_del' => 1]; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + /** + * @param $id + * @return Form + * @author Qinii + */ + public function form($id) + { + $data = $this->dao->getWhere([$this->dao->getPk() => $id], 'total_price,pay_price,total_postage,pay_postage'); + $form = Elm::createForm(Route::buildUrl('merchantStoreOrderUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::number('total_price', '订单总价', $data['total_price'])->required(), + Elm::number('total_postage', '订单邮费', $data['total_postage'])->required(), + Elm::number('pay_price', '实际支付金额', $data['pay_price'])->required(), + ]); + return $form->setTitle('修改订单'); + } + + /** + * TODO 修改订单价格 + * @param int $id + * @param array $data + * @author Qinii + * @day 12/15/20 + */ + public function eidt(int $id, array $data, $service_id = 0) + { + + /** + * 1 计算出新的实际支付价格 + * 1.1 计算邮费 + * 1.2 计算商品总价 + * 2 修改订单信息 + * 3 计算总单数据 + * 4 修改总单数据 + * 5 修改订单商品单价 + * + * pay_price = total_price - coupon_price + pay_postage + */ + $order = $this->dao->get($id); + if ($order->activity_type == 2) { + throw new ValidateException('预售订单不支持改价'); + } + $extension_total = (float)bcadd($order->extension_one, $order->extension_two, 2); + $data['pay_price'] = $this->bcmathPrice($data['total_price'], $order['coupon_price'], $data['pay_postage']); + if ($data['pay_price'] < 0) { + throw new ValidateException('实际支付金额不能小于0'); + } else if ($data['pay_price'] < $extension_total) { + throw new ValidateException('实际支付金额不能小于佣金' . $extension_total); + } + $make = app()->make(StoreGroupOrderRepository::class); + $orderGroup = $make->dao->getWhere(['group_order_id' => $order['group_order_id']]); + + //总单总价格 + $_group['total_price'] = $this->bcmathPrice($orderGroup['total_price'], $order['total_price'], $data['total_price']); + //总单实际支付价格 + $_group['pay_price'] = $this->bcmathPrice($orderGroup['pay_price'], $order['pay_price'], $data['pay_price']); + //总单实际支付邮费 + $_group['pay_postage'] = $this->bcmathPrice($orderGroup['pay_postage'], $order['pay_postage'], $data['pay_postage']); + event('order.changePrice.before', compact('order', 'data')); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单价格修改', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CHANGE, + ]; + + Db::transaction(function () use ($id, $data, $orderGroup, $order, $_group,$storeOrderStatusRepository,$orderStatus,$service_id) { + $orderGroup->total_price = $_group['total_price']; + $orderGroup->pay_price = $_group['pay_price']; + $orderGroup->pay_postage = $_group['pay_postage']; + $orderGroup->group_order_sn = $this->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . '0'; + $orderGroup->save(); + + $this->dao->update($id, $data); + $this->changOrderProduct($id, $data); + + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + if ($data['pay_price'] != $order['pay_price']) Queue::push(SendSmsJob::class, ['tempId' => 'PRICE_REVISION_CODE', 'id' => $id]); + }); + event('order.changePrice', compact('order', 'data')); + } + + /** + * TODO 改价后重新计算每个商品的单价 + * @param int $orderId + * @param array $data + * @author Qinii + * @day 12/15/20 + */ + public function changOrderProduct(int $orderId, array $data) + { + $make = app()->make(StoreOrderProductRepository::class); + $ret = $make->getSearch(['order_id' => $orderId])->field('order_product_id,product_num,product_price')->select(); + $count = $make->getSearch(['order_id' => $orderId])->sum('product_price'); + $_count = (count($ret->toArray()) - 1); + $pay_price = $data['total_price']; + foreach ($ret as $k => $item) { + $_price = 0; + /** + * 比例 = 单个商品总价 / 订单原总价; + * + * 新的商品总价 = 比例 * 订单修改总价 + * + * 更新数据库 + */ + if ($k == $_count) { + $_price = $pay_price; + } else { + $_reta = bcdiv($item->product_price, $count, 3); + $_price = bcmul($_reta, $data['total_price'], 2); + } + + $item->product_price = $_price; + $item->save(); + + $pay_price = $this->bcmathPrice($pay_price, $_price, 0); + } + } + + /** + * TODO 计算的重复利用 + * @param $total + * @param $old + * @param $new + * @return int|string + * @author Qinii + * @day 12/15/20 + */ + public function bcmathPrice($total, $old, $new) + { + $_bcsub = bcsub($total, $old, 2); + $_count = (bccomp($_bcsub, 0, 2) == -1) ? 0 : $_bcsub; + $count = bcadd($_count, $new, 2); + return (bccomp($count, 0, 2) == -1) ? 0 : $count; + } + + /** + * @param $id + * @param $uid + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function refundProduct($id, $uid) + { + $order = $this->dao->userOrder($id, $uid); + if (!$order) + throw new ValidateException('订单不存在'); + if (!count($order->refundProduct)) + throw new ValidateException('没有可退款商品'); + return $order->refundProduct->toArray(); + } + + /** + * TODO + * @param $id + * @param $data + * @return mixed + * @author Qinii + * @day 7/26/21 + */ + public function orderDumpInfo($id, $data, $merId) + { + $where = [ + 'order_id' => $id, + ]; + $ret = $this->dao->getWhere($where); + if ($ret['is_virtual']) throw new ValidateException('虚拟商品只能虚拟发货'); + $cargo = ''; + $count = 0; + foreach ($ret->orderProduct as $item) { + // $cargo .= $item['cart_info']['product']['store_name']. ' ' .$item['cart_info']['productAttr']['sku'] .' * ' .$item['product_num'].$item['cart_info']['product']['unit_name'].PHP_EOL; + $count += $item['product_num']; + } + + $data['to_name'] = $ret['real_name']; + $data['to_tel'] = $ret['user_phone']; + $data['to_addr'] = $ret['user_address']; + $data['cargo'] = $cargo; + $data['count'] = $count; + $data['order_sn'] = $ret['order_sn']; + return $data; + } + + /** + * TODO 批量发货 + * @param int $merId + * @param array $params + * @author Qinii + * @day 7/26/21 + */ + public function batchDelivery(int $merId, array $params) + { + $count = count($params['order_id']); + $import = app()->make(StoreImportRepository::class)->create($merId, 'delivery', $params['delivery_type']); + $make = app()->make(StoreImportDeliveryRepository::class); + $data = []; + $num = 0; + foreach ($params['order_id'] as $item) { + $ret = $this->dao->getWhere(['order_id' => $params['order_id']]); + $imp = [ + 'order_sn' => $ret['order_sn'] ?? $item, + 'delivery_id' => $params['delivery_id'], + 'delivery_type' => $params['delivery_type'], + 'delivery_name' => $params['delivery_name'], + 'import_id' => $import['import_id'], + 'mer_id' => $merId + ]; + + if (!$ret || $ret['status'] != 1 || $ret['mer_id'] != $merId || $ret['is_del'] != 0 || $ret['paid'] != 1 || $ret['delivery_type'] != 0 ) { + $imp['status'] = 0; + $imp['mark'] = '订单信息不存在或状态错误'; + } else { + try { + if ($params['delivery_type'] == 4) { + $dump = [ + 'temp_id' => $params['temp_id'], + 'from_tel' => $params['from_tel'], + 'from_addr' => $params['from_addr'], + 'from_name' => $params['from_name'], + 'delivery_name' => $params['delivery_name'], + ]; + $dump = $this->orderDumpInfo($item, $dump, $merId); + $ret = $this->dump($item, $merId, $dump); + $imp['delivery_id'] = $ret['delivery_id']; + $imp['delivery_name'] = $ret['delivery_name']; + } else { + $this->delivery($item, $merId,[ + 'delivery_id' => $params['delivery_id'], + 'delivery_type' => $params['delivery_type'], + 'delivery_name' => $params['delivery_name'], + ]); + } + $num++; + $imp['status'] = 1; + } catch (Exception $exception) { + $imp['status'] = 0; + $imp['mark'] = $exception->getMessage(); + } + } + $data[] = $imp; + } + + $_status = ($num == 0) ? -1 : (($count == $num) ? 1 : 10); + $make->insertAll($data); + $arr = ['count' => $count, 'success' => $num, 'status' => $_status]; + app()->make(StoreImportRepository::class)->update($import['import_id'], $arr); + } + + + /** + * TODO 打印电子面单,组合参数 + * @param int $id + * @param int $merId + * @param array $data + * @return mixed + * @author Qinii + * @day 7/26/21 + */ + public function dump(int $id, int $merId, array $data, $service_id = 0) + { + $make = app()->make(MerchantRepository::class); + $make->checkCrmebNum($merId, 'dump'); + + $data = $this->orderDumpInfo($id, $data, $merId); + + $data['com'] = $data['delivery_name']; + $result = app()->make(CrmebServeServices::class)->express()->dump($merId, $data); + if (!isset($result['kuaidinum'])) throw new ValidateException('打印失败'); + + $delivery = [ + 'delivery_type' => 4, + 'delivery_name' => $data['delivery_name'], + 'delivery_id' => $result['kuaidinum'], + 'remark' => $data['remark'] ?? '', + ]; + + $dump = [ + 'delivery_name' => $delivery['delivery_name'], + 'delivery_id' => $delivery['delivery_id'], + 'from_name' => $data['from_name'], + 'order_sn' => $data['order_sn'], + 'to_name' => $data['to_name'], + ]; + Db::transaction(function () use ($merId, $id, $delivery, $make, $dump, $service_id) { + $this->delivery($id, $merId, $delivery,$service_id); + $arr = [ + 'type' => 'mer_dump', + 'num' => -1, + 'message' => '电子面单', + 'info' => $dump + ]; + app()->make(ProductCopyRepository::class)->add($arr, $merId); + }); + return $delivery; + } + + public function runDelivery($id, $merId, $data, $split, $method,$service_id = 0) + { + return Db::transaction(function () use ($id, $merId, $data, $split, $method,$service_id) { + if ($split['is_split'] && !empty($split['split'])) { + foreach ($split['split'] as $v) { + $splitData[$v['id']] = $v['num']; + } + $order = $this->dao->get($id); + $newOrder = app()->make(StoreOrderSplitRepository::class)->splitOrder($order, $splitData,$service_id); + if ($newOrder){ + $id = $newOrder->order_id; + } else { + throw new ValidateException('商品不能全部拆单'); + } + } + return $this->{$method}($id, $merId, $data,$service_id); + }); + } + + /** + * TODO 发货订单操作 + * @param $id + * @param $data + * @return mixed + * @author Qinii + * @day 7/26/21 + */ + public function delivery($id, $merId, $data, $service_id = 0) + { + $data['status'] = 1; + $order = $this->dao->get($id); + if ($order['is_virtual'] && $data['delivery_type'] != 3) + throw new ValidateException('虚拟商品只能虚拟发货'); + //订单记录 + $statusRepository = app()->make(StoreOrderStatusRepository::class); + switch ($data['delivery_type']) { + case 1: + $exprss = app()->make(ExpressRepository::class)->getWhere(['code' => $data['delivery_name']]); + if (!$exprss) throw new ValidateException('快递公司不存在'); + $data['delivery_name'] = $exprss['name']; + $change_type = $statusRepository::ORDER_DELIVERY_COURIER; + $change_message = '订单已配送【快递名称】:' . $exprss['name'] . '; 【快递单号】:' . $data['delivery_id']; + $temp_code = 'DELIVER_GOODS_CODE'; + break; + case 2: + if (!preg_match("/^1[3456789]{1}\d{9}$/", $data['delivery_id'])) throw new ValidateException('手机号格式错误'); + $change_type = 'delivery_1'; + $change_message = '订单已配送【送货人姓名】:' . $data['delivery_name'] . '; 【手机号】:' . $data['delivery_id']; + $temp_code = 'ORDER_DELIVER_SUCCESS'; + break; + case 3: + $change_type = $statusRepository::ORDER_DELIVERY_NOTHING; + $change_message = '订单已配送【虚拟发货】'; + $data['status'] = 2; + break; + case 4: + $exprss = app()->make(ExpressRepository::class)->getWhere(['code' => $data['delivery_name']]); + if (!$exprss) throw new ValidateException('快递公司不存在'); + $data['delivery_name'] = $exprss['name']; + $change_type = $statusRepository::ORDER_DELIVERY_COURIER; + $change_message = '订单已配送【快递名称】:' . $exprss['name'] . '; 【快递单号】:' . $data['delivery_id']; + $temp_code = 'DELIVER_GOODS_CODE'; + break; + } + + event('order.delivery.before', compact('order', 'data')); + $this->dao->update($id, $data); + + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => $change_message, + 'change_type' => $change_type, + ]; + if ($service_id) { + $statusRepository->createServiceLog($service_id,$orderStatus); + } else { + $statusRepository->createAdminLog($orderStatus); + } + + + //虚拟发货后用户直接确认收获 + if($data['status'] == 2){ + $user = app()->make(UserRepository::class)->get($order['uid']); + //订单记录 + $this->takeAfter($order,$user); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '虚拟发货后', + 'change_type' => $statusRepository::ORDER_STATUS_TAKE, + ]; + $statusRepository->createSysLog($orderStatus); + + } + if (isset($temp_code)) Queue::push(SendSmsJob::class, ['tempId' => $temp_code, 'id' => $order->order_id]); + + event('order.delivery', compact('order', 'data')); + return $data; + } + + /** + * TODO 同城配送 + * @param int $id + * @param int $merId + * @param array $data + * @author Qinii + * @day 2/16/22 + */ + public function cityDelivery(int $id, int $merId, array $data, $service_id) + { + $make = app()->make(DeliveryOrderRepository::class); + $order = $this->dao->get($id); + if ($order['is_virtual']) + throw new ValidateException('虚拟商品只能虚拟发货'); + $make->create($id, $merId, $data, $order); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $this->dao->update($id, ['delivery_type' => 5, 'status' => 1,'remark' => $data['remark']]); + + $orderStatus = [ + 'order_id' => $id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单配送【同城配送】', + 'change_type' => $storeOrderStatusRepository::ORDER_DELIVERY_SELF, + ]; + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_DELIVER_SUCCESS', 'id' => $id]); + } + + + public function getOne($id, ?int $merId) + { + $where = [$this->getPk() => $id]; + if ($merId) { + $whre['mer_id'] = $merId; + $whre['is_system_del'] = 0; + } + $res = $this->dao->getWhere($where, '*', [ + 'orderProduct', + 'user' => function ($query) { + $query->field('uid,real_name,nickname,is_svip,svip_endtime,phone'); + }, + 'refundOrder' => function ($query) { + $query->field('order_id,extension_one,extension_two,refund_price,integral')->where('status', 3); + }, + 'finalOrder', + 'TopSpread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ] + ); + if (!$res) throw new ValidateException('数据不存在'); + $res['integral'] = (int)$res['integral']; + return $res->append(['refund_extension_one', 'refund_extension_two']); + } + + public function getOrderStatus($where, $page, $limit) + { + $where['type'] = StoreOrderStatusRepository::TYPE_ORDER; + return app()->make(StoreOrderStatusRepository::class)->search($where, $page, $limit); + } + + public function remarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('merchantStoreOrderRemark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('remark', '备注', $data['remark'])->required(), + ]); + return $form->setTitle('订单备注'); + } + + public function adminMarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantOrderMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('admin_mark', '备注', $data['admin_mark'])->required(), + ]); + return $form->setTitle('订单备注'); + } + + /** + * TODO 平台每个商户的订单列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-15 + */ + public function adminMerGetList($where, $page, $limit) + { + $where['paid'] = 1; + $query = $this->dao->search($where, null); + $count = $query->count(); + $list = $query->with([ + 'orderProduct', + 'merchant' => function ($query) { + $query->field('mer_id,mer_name,is_trader'); + }, + 'groupOrder' => function ($query) { + $query->field('group_order_id,group_order_sn'); + }, + 'finalOrder', + 'user' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ])->page($page, $limit)->select()->append(['refund_extension_one', 'refund_extension_two']); + + return compact('count', 'list'); + } + + public function reconList($where, $page, $limit) + { + $ids = app()->make(MerchantReconciliationOrderRepository::class)->getIds($where); + $query = $this->dao->search([], null)->whereIn('order_id', $ids); + $count = $query->count(); + $list = $query->with(['orderProduct'])->page($page, $limit)->select()->each(function ($item) { + //(实付金额 - 一级佣金 - 二级佣金) * 抽成 + $commission_rate = ($item['commission_rate'] / 100); + //佣金 + $_order_extension = bcadd($item['extension_one'], $item['extension_two'], 3); + //手续费 = (实付金额 - 一级佣金 - 二级佣金) * 比例 + $_order_rate = bcmul(bcsub($item['pay_price'], $_order_extension, 3), $commission_rate, 3); + $item['order_extension'] = round($_order_extension, 2); + $item['order_rate'] = round($_order_rate, 2); + return $item; + }); + + return compact('count', 'list'); + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @author Qinii + */ + public function merchantGetList(array $where, $page, $limit) + { + $status = $where['status']; + unset($where['status']); + $query = $this->dao->search($where)->where($this->getOrderType($status)) + ->with([ + 'orderProduct', + 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }, + 'verifyService' => function ($query) { + $query->field('service_id,nickname'); + }, + 'finalOrder', + 'groupUser.groupBuying', + 'TopSpread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['refund_extension_one', 'refund_extension_two']) + ->each(function($item){ + // 1:退款中 2:部分退款 3 = 全退 + $refunding = 0; + if ($item['orderProduct']) { + $is_refund = array_column($item['orderProduct']->toArray(),'is_refund'); + $is_refund = array_unique($is_refund); + if (in_array(1,$is_refund)) { + $refunding = 1; + } else if (in_array(2,$is_refund)) { + $refunding = 2; + } else if (in_array(3,$is_refund)) { + $refunding = 3; + } + } + $item['refunding'] = $refunding; + }); + + + return compact('count', 'list'); + } + + /** + * TODO 平台总的订单列表 + * @param array $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-15 + */ + public function adminGetList(array $where, $page, $limit) + { + $status = $where['status']; + unset($where['status']); + $query = $this->dao->search($where, null)->where($this->getOrderType($status)) + ->with([ + 'orderProduct', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name,is_trader'); + }, + 'verifyService' => function ($query) { + return $query->field('service_id,nickname'); + }, + 'groupOrder' => function ($query) { + $query->field('group_order_id,group_order_sn'); + }, + 'finalOrder', + 'groupUser.groupBuying', + 'TopSpread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'user' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['refund_extension_one', 'refund_extension_two']); + + return compact('count', 'list'); + } + + public function getStat(array $where, $status) + { + unset($where['status']); + $make = app()->make(StoreRefundOrderRepository::class); + $presellOrderRepository = app()->make(PresellOrderRepository::class); + + //退款订单id + $orderId = $this->dao->search($where)->where($this->getOrderType($status))->column('order_id'); + //退款金额 + $orderRefund = $make->refundPirceByOrder($orderId); + //实际支付订单数量 + $all = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->count(); + //实际支付订单金额 + $countQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1); + $countOrderId = $countQuery->column('order_id'); + $countPay1 = $countQuery->sum('StoreOrder.pay_price'); + $countPay2 = $presellOrderRepository->search(['paid' => 1, 'order_ids' => $countOrderId])->sum('pay_price'); + $countPay = bcadd($countPay1, $countPay2, 2); + + //余额支付 + $banclQuery = $this->dao->search(array_merge($where, ['paid' => 1, 'pay_type' => 0]))->where($this->getOrderType($status)); + $banclOrderId = $banclQuery->column('order_id'); + $banclPay1 = $banclQuery->sum('StoreOrder.pay_price'); + $banclPay2 = $presellOrderRepository->search(['pay_type' => [0], 'paid' => 1, 'order_ids' => $banclOrderId])->sum('pay_price'); + $banclPay = bcadd($banclPay1, $banclPay2, 2); + + //微信金额 + $wechatQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->where('pay_type', 'in', [1, 2, 3, 6]); + $wechatOrderId = $wechatQuery->column('order_id'); + $wechatPay1 = $wechatQuery->sum('StoreOrder.pay_price'); + $wechatPay2 = $presellOrderRepository->search(['pay_type' => [1, 2, 3, 6], 'paid' => 1, 'order_ids' => $wechatOrderId])->sum('pay_price'); + $wechatPay = bcadd($wechatPay1, $wechatPay2, 2); + + //支付宝金额 + $aliQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->where('pay_type', 'in', [4, 5]); + $aliOrderId = $aliQuery->column('order_id'); + $aliPay1 = $aliQuery->sum('StoreOrder.pay_price'); + $aliPay2 = $presellOrderRepository->search(['pay_type' => [4, 5], 'paid' => 1, 'order_ids' => $aliOrderId])->sum('pay_price'); + $aliPay = bcadd($aliPay1, $aliPay2, 2); + + + $stat = [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $all, + 'field' => '件', + 'name' => '已支付订单数量' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => (float)$countPay, + 'field' => '元', + 'name' => '实际支付金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)$orderRefund, + 'field' => '元', + 'name' => '已退款金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)$wechatPay, + 'field' => '元', + 'name' => '微信支付金额' + ], + [ + 'className' => 'el-icon-s-finance', + 'count' => (float)$banclPay, + 'field' => '元', + 'name' => '余额支付金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)$aliPay, + 'field' => '元', + 'name' => '支付宝支付金额' + ], + ]; + return $stat; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->where('StoreOrder.is_del', 0); + $count = $query->count(); + $list = $query->with([ + 'orderProduct', + 'presellOrder', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name'); + }, + 'community', + 'receipt' => function ($query) { + return $query->field('order_id,order_receipt_id'); + }, + ])->page($page, $limit)->order('pay_time DESC')->append(['refund_status'])->select(); + + foreach ($list as $order) { + if ($order->activity_type == 2) { + if ($order->presellOrder) { + $order->presellOrder->append(['activeStatus']); + $order->presell_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2); + } else { + $order->presell_price = $order->pay_price; + } + } + $order->takeOrderCount = count($order['takeOrderList']); + unset($order['takeOrderList']); + } + + return compact( 'count','list'); + } + + public function userList($uid, $page, $limit) + { + $query = $this->dao->search([ + 'uid' => $uid, + 'paid' => 1 + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + + public function userMerList($uid, $merId, $page, $limit) + { + $query = $this->dao->search([ + 'uid' => $uid, + 'mer_id' => $merId, + 'paid' => 1 + ]); + $count = $query->count(); + $list = $query->with(['presellOrder'])->page($page, $limit)->select(); + foreach ($list as $order) { + if ($order->activity_type == 2 && $order->status >= 0 && $order->status < 10 && $order->presellOrder) { + $order->pay_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2); + } + } + return compact('count', 'list'); + } + + public function express(int $orderId, ?int $merId) + { + $order = $this->dao->get($orderId); + if ($merId && $order['mer_id'] != $merId) throw new ValidateException('订单信息不存在'); + if (!in_array($order['delivery_type'], [1, 4])) throw new ValidateException('订单状态错误'); + return ExpressService::express($order->delivery_id, $order->delivery_name, $order->user_phone); + } + + public function checkPrinterConfig(int $merId) + { + if (!merchantConfig($merId, 'printing_status')) + throw new ValidateException('打印功能未开启'); + $config = [ + 'clientId' => merchantConfig($merId, 'printing_client_id'), + 'apiKey' => merchantConfig($merId, 'printing_api_key'), + 'partner' => merchantConfig($merId, 'develop_id'), + 'terminal' => merchantConfig($merId, 'terminal_number') + ]; + if (!$config['clientId'] || !$config['apiKey'] || !$config['partner'] || !$config['terminal']) + throw new ValidateException('打印机配置错误'); + return $config; + } + + /** + * TODO 打印机 -- 暂无使用 + * @param int $id + * @param int $merId + * @return bool|mixed|string + * @author Qinii + * @day 2020-07-30 + */ + public function printer(int $id, int $merId) + { + $order = $this->dao->getWhere(['order_id' => $id], '*', ['orderProduct', 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }]); + foreach ($order['orderProduct'] as $item) { + $product[] = [ + 'store_name' => $item['cart_info']['product']['store_name'] . '【' . $item['cart_info']['productAttr']['sku'] . '】', + 'product_num' => $item['product_num'], + 'price' => bcdiv($item['product_price'], $item['product_num'], 2), + 'product_price' => $item['product_price'], + ]; + } + $data = [ + 'order_sn' => $order['order_sn'], + 'pay_time' => $order['pay_time'], + 'real_name' => $order['real_name'], + 'user_phone' => $order['user_phone'], + 'user_address' => $order['user_address'], + 'total_price' => $order['total_price'], + 'coupon_price' => $order['coupon_price'], + 'pay_price' => $order['pay_price'], + 'total_postage' => $order['total_postage'], + 'pay_postage' => $order['pay_postage'], + 'mark' => $order['mark'], + ]; + $config = $this->checkPrinterConfig($merId); + $printer = new Printer('yi_lian_yun', $config); + event('order.print.before', compact('order')); + + $res = $printer->setPrinterContent([ + 'name' => $order['merchant']['mer_name'], + 'orderInfo' => $data, + 'product' => $product + ])->startPrinter(); + + event('order.print', compact('order', 'res')); + + return $res; + } + + public function batchPrinter(int $id, int $merId) + { + $order = $this->dao->getWhere(['order_id' => $id], '*', ['orderProduct', 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }]); + + foreach ($order['orderProduct'] as $item) { + $product[] = [ + 'store_name' => $item['cart_info']['product']['store_name'] . '【' . $item['cart_info']['productAttr']['sku'] . '】', + 'product_num' => $item['product_num'], + 'price' => bcdiv($item['product_price'], $item['product_num'], 2), + 'product_price' => $item['product_price'], + ]; + } + + $data = [ + 'order_sn' => $order['order_sn'], + 'order_type' => $order['order_type'], + 'pay_time' => $order['pay_time'], + 'real_name' => $order['real_name'], + 'user_phone' => $order['user_phone'], + 'user_address' => $order['user_address'], + 'total_price' => $order['total_price'], + 'coupon_price' => $order['coupon_price'], + 'pay_price' => $order['pay_price'], + 'total_postage' => $order['total_postage'], + 'pay_postage' => $order['pay_postage'], + 'mark' => $order['mark'], + ]; + + $printer = app()->make(StorePrinterRepository::class)->getPrinter($merId); + event('order.print.before', compact('order')); + foreach ($printer as $config) { + $printer = new Printer('yi_lian_yun', $config); + $res = $printer->setPrinterContent([ + 'name' => $order['merchant']['mer_name'], + 'orderInfo' => $data, + 'product' => $product + ])->startPrinter(); + } + + event('order.print', compact('order', 'res')); + } + + + public function verifyOrder(int $id, int $merId, array $data, $serviceId = 0) + { + $order = $this->dao->getWhere(['order_id' => $id, 'mer_id' => $merId,'verify_code' => $data['verify_code'],'order_type' => 1],'*',['orderProduct']); + if (!$order) throw new ValidateException('订单不存在'); + if (!$order->paid) throw new ValidateException('订单未支付'); + if ($order['status']) throw new ValidateException('订单已全部核销,请勿重复操作'); + foreach ($data['data'] as $v) { + $splitData[$v['id']] = $v['num']; + } + $spl = app()->make(StoreOrderSplitRepository::class)->splitOrder($order, $splitData, $serviceId, 1); + if ($spl) $order = $spl; + $order->status = 2; + $order->verify_time = date('Y-m-d H:i:s'); + $order->verify_service_id = $serviceId; + event('order.verify.before', compact('order')); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + Db::transaction(function () use ($order,$storeOrderStatusRepository,$serviceId) { + $this->takeAfter($order, $order->user); + $order->save(); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单已核销', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_TAKE, + ]; + if ($serviceId){ + $storeOrderStatusRepository->createServiceLog($serviceId,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + + }); + event('order.verify', compact('order')); + } + + public function wxQrcode($orderId, $verify_code) + { + $siteUrl = systemConfig('site_url'); + $name = md5('owx' . $orderId . date('Ymd')) . '.jpg'; + $attachmentRepository = app()->make(AttachmentRepository::class); + $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]); + + if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) { + $imageInfo->delete(); + $imageInfo = null; + } + if (!$imageInfo) { + // $codeUrl = set_http_type(rtrim($siteUrl, '/') . '/pages/admin/order_cancellation/index?verify_code=' . $verify_code, request()->isSsl() ? 0 : 1);//二维码链接 + $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($verify_code, $name); + if (is_string($imageInfo)) throw new ValidateException('二维码生成失败'); + + $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl); + + $attachmentRepository->create(systemConfig('upload_type') ?: 1, -2, $orderId, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $urlCode = $imageInfo['dir']; + } else $urlCode = $imageInfo['attachment_src']; + return $urlCode; + } + + /** + * TODO 根据商品ID获取订单数 + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-05 + */ + public function seckillOrderCounut(int $productId) + { + $where = [ + 'activity_id' => $productId, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + $count = $this->dao->getTattendCount($where, null)->count(); + $count_ = $this->dao->getSeckillRefundCount($where, 2); + $count__ = $this->dao->getSeckillRefundCount($where, 1); + return $count - $count_ - $count__; + } + + /** + * TODO 根据商品sku获取订单数 + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-05 + */ + public function seckillSkuOrderCounut(string $sku) + { + $where = [ + 'product_sku' => $sku, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + $count = $this->dao->getTattendCount($where, null)->count(); + $count_ = $this->dao->getSeckillRefundCount($where, 2); + $count__ = $this->dao->getSeckillRefundCount($where, 1); + return $count - $count_ - $count__; + } + + /** + * TODO 获取sku的总销量 + * @param string $sku + * @return int|mixed + * @author Qinii + * @day 3/4/21 + */ + public function skuSalesCount(string $sku) + { + $where = [ + 'product_sku' => $sku, + 'product_type' => 1, + ]; + $count = $this->dao->getTattendSuccessCount($where, null)->count(); + $count_ = $this->dao->getSeckillRefundCount($where, 2); + $count__ = $this->dao->getSeckillRefundCount($where, 1); + return $count - $count_ - $count__; + } + + /** + * TODO 秒杀获取个人当天限购 + * @param int $uid + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-15 + */ + public function getDayPayCount(int $uid, int $productId) + { + $make = app()->make(StoreSeckillActiveRepository::class); + $active = $make->getWhere(['product_id' => $productId]); + if ($active['once_pay_count'] == 0) return true; + + $where = [ + 'activity_id' => $productId, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + + $count = $this->dao->getTattendCount($where, $uid)->count(); + return ($active['once_pay_count'] > $count); + } + + /** + * TODO 秒杀获取个人总限购 + * @param int $uid + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-15 + */ + public function getPayCount(int $uid, int $productId) + { + $make = app()->make(StoreSeckillActiveRepository::class); + $active = $make->getWhere(['product_id' => $productId]); + if ($active['all_pay_count'] == 0) return true; + $where = [ + 'activity_id' => $productId, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + $count = $this->dao->getTattendCount($where, $uid)->count(); + return ($active['all_pay_count'] > $count); + } + + /** + * 根据订单id查看是否全部退款 + * @Author:Qinii + * @Date: 2020/9/11 + * @param int $orderId + * @return bool + */ + public function checkRefundStatusById(int $orderId, int $refundId) + { + return Db::transaction(function () use ($orderId, $refundId) { + $res = $this->dao->search(['order_id' => $orderId])->with(['orderProduct'])->find(); + $refund = app()->make(StoreRefundOrderRepository::class)->getRefundCount($orderId, $refundId); + if ($refund) return false; + foreach ($res['orderProduct'] as $item) { + if ($item['refund_num'] !== 0) return false; + $item->is_refund = 3; + $item->save(); + } + $res->status = -1; + $res->save(); + $this->orderRefundAllAfter($res); + return true; + }); + } + + public function orderRefundAllAfter($order) + { + + if ($order->activity_type == 10) { + app()->make(StoreDiscountRepository::class)->incStock($order->orderProduct[0]['activity_id']); + } + $mainId = $order->main_id ?: $order->order_id; + $count = $this->query([])->where('status', '<>', -1)->where(function ($query) use ($mainId) { + $query->where('order_id', $mainId)->whereOr('main_id', $mainId); + })->count(); + //拆单后完全退完 + if (!$count) { + if ($order->main_id) { + $order = $this->query(['order_id' => $mainId])->find(); + } + $couponId = []; + if ($order->coupon_id) { + $couponId = explode(',', $order->coupon_id); + } + app()->make(MerchantRepository::class)->computedLockMoney($order); + //总单所有订单全部退完 + if (!$this->query([])->where('status', '<>', -1)->where('group_order_id', $order->group_order_id)->count()) { + if ($order->groupOrder->coupon_id) { + $couponId[] = $order->groupOrder->coupon_id; + } + } + if (count($couponId)) { + app()->make(StoreCouponUserRepository::class)->updates($couponId, ['status' => 0]); + } + + } + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单已全部退款', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_REFUND_ALL, + ]; + $storeOrderStatusRepository->createSysLog($orderStatus); + + event('order.refundAll', compact('order')); + } + + /** + * @param $id + * @param $uid + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/9/17 + */ + public function userDel($id, $uid) + { + $order = $this->dao->getWhere([['status', 'in', [0, 3, -1, 11]], ['order_id', '=', $id], ['uid', '=', $uid], ['is_del', '=', 0]]); + if (!$order || ($order->status == 0 && $order->paid == 1)) + throw new ValidateException('订单状态有误'); + event('order.userDel.before', compact('order')); + $this->delOrder($order, '订单删除'); + event('order.userDel', compact('order')); + } + + public function delOrder($order, $info = '订单删除') + { + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => $info, + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_DELETE, + ]; + $productRepository = app()->make(ProductRepository::class); + Db::transaction(function () use ($info, $order, $orderStatus, $storeOrderStatusRepository,$productRepository) { + $order->is_del = 1; + $order->save(); + $storeOrderStatusRepository->createUserLog($orderStatus); + foreach ($order->orderProduct as $cart) { + $productRepository->orderProductIncStock($order, $cart); + } + }); + } + + public function merDelete($id) + { + Db::transaction(function () use ($id) { + $data['is_system_del'] = 1; + $this->dao->update($id, $data); + app()->make(StoreOrderReceiptRepository::class)->deleteByOrderId($id); + }); + } + + /** + * @param $id + * @return \FormBuilder\Form + * @author Qinii + */ + public function sendProductForm($id, $data) + { + $express = app()->make(ExpressRepository::class)->options(); + $form = Elm::createForm(Route::buildUrl('merchantStoreOrderDelivery', ['id' => $id])->build()); + + if (in_array($data['delivery_type'], [1, 2])) { + if ($data['delivery_type'] == 1) { + $form->setRule([ + Elm::hidden('delivery_type', 1), + [ + 'type' => 'span', + 'title' => '原快递名称', + 'children' => [(string)$data['delivery_name']] + ], + [ + 'type' => 'span', + 'title' => '原快递单号', + 'children' => [(string)$data['delivery_id']] + ], + Elm::select('delivery_name', '快递名称')->options(function () use ($express) { + return $express; + }), + Elm::input('delivery_id', '快递单号')->required(), + ]); + } else { + $form->setRule([ + Elm::hidden('delivery_type', 2), + [ + 'type' => 'span', + 'title' => '原送货人姓名', + 'children' => [(string)$data['delivery_name']] + ], + [ + 'type' => 'span', + 'title' => '原手机号', + 'children' => [(string)$data['delivery_id']] + ], + Elm::input('delivery_name', '送货人姓名')->required(), + Elm::input('delivery_id', '手机号')->required(), + ]); + } + } + if ($data['delivery_type'] == 3) { + $form->setRule([ + Elm::hidden('delivery_type', 3), + [ + 'type' => 'span', + 'title' => '发货类型', + 'children' => ['无需配送'] + ] + ]); + } + if (!$data['delivery_type']) { + $form->setRule([ + Elm::radio('delivery_type', '发货类型', 1) + ->setOptions([ + ['value' => 1, 'label' => '发货'], + ['value' => 2, 'label' => '送货'], + ['value' => 3, 'label' => '无需配送'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::select('delivery_name', '快递名称')->options(function () use ($express) { + return $express; + }), + Elm::input('delivery_id', '快递单号')->required(), + ] + ], + [ + 'value' => 2, + 'rule' => [ + Elm::input('delivery_name', '送货人姓名')->required(), + Elm::input('delivery_id', '手机号')->required(), + ] + ], + [ + 'value' => 3, + 'rule' => [] + ], + + ]), + ]); + } + + return $form->setTitle('发货信息'); + } + + /** + * TODO 导入发货信息 + * @param array $data + * @param $merId + * @author Qinii + * @day 3/16/21 + */ + public function setWhereDeliveryStatus(array $arrary, $merId) + { + //读取excel + $data = SpreadsheetExcelService::instance()->_import($arrary['path'], $arrary['sql'], $arrary['where'], 4); + if (!$data) return; + $import_id = $arrary['import_id']; + Db::transaction(function () use ($data, $merId, $import_id) { + $result = []; + $num = 0; + $count = 0; + $status = 0; + foreach ($data as $datum) { + $value = []; + $ret = []; + if ($datum['where']) { + $count = $count + 1; + if (empty($datum['value']['delivery_id'])) { + $mark = '发货单号为空'; + } else { + $ret = $this->getSearch([]) + ->where('status', 0) + ->where('paid', 1) + ->where('order_type', 0) + ->where('mer_id', $merId) + ->where($datum['where']) + ->find(); + $mark = '数据有误或已发货'; + } + if ($ret) { + try { + $value = array_merge($datum['value'], ['status' => 1]); + $value['delivery_type'] = 1; + $this->delivery($ret['order_id'], $merId, $value); + + $status = 1; + $mark = ''; + + $num = $num + 1; + } catch (\Exception $exception) { + $mark = $exception->getMessage(); + } + } + $datum['where']['mark'] = $mark; + $datum['where']['mer_id'] = $merId; + $datum['where']['status'] = $status; + $datum['where']['import_id'] = $import_id; + $result[] = array_merge($datum['where'], $datum['value']); + } + } + // 记录入库操作 + if (!empty($result)) app()->make(StoreImportDeliveryRepository::class)->insertAll($result); + $_status = ($count == $num) ? 1 : (($num < 1) ? -1 : 10); + app()->make(StoreImportRepository::class)->update($import_id, ['count' => $count, 'success' => $num, 'status' => $_status]); + }); + if (file_exists($arrary['path'])) unlink($arrary['path']); + } + + /** + * TODO 根据订单查询相关联的自订单 + * @param $id + * @param $merId + * @return \think\Collection + * @author Qinii + * @day 2023/2/22 + */ + public function childrenList($id,$merId) + { + $data = $this->dao->get($id); + $query = $this->dao->getSearch([])->with(['orderProduct'])->where('order_id','<>',$id); + if ($merId) $query->where('mer_id',$merId); + if ($data['main_id']) { + $query->where(function($query) use($data,$id){ + $query->where('main_id',$data['main_id'])->whereOr('order_id',$data['main_id']); + }); + } else { + $query->where('main_id',$id); + } + return $query->select(); + } + + /**导入库存 + * @param array $arrary + * @param $merId + * @return void + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function setProduct(array $arrary, $merId) + { + //读取excel + $data = SpreadsheetExcelService::instance()->_import($arrary['path'], $arrary['sql'], $arrary['where'], 1); + if (!$data) return false; + unset($data[0]); + $mer_cate_id=Db::name('store_category')->where('mer_id',$merId)->where('cate_name','默认分类')->value('store_category_id'); + if (!$mer_cate_id ||$mer_cate_id==0){ + $mer_cate=['pid'=>0,'cate_name'=>'默认分类','path'=>'/','mer_id'=>$merId,'sort'=>0,'is_show'=>1,'create_time'=>date('Y-m-d H:i:s')]; + $mer_cate_id=Db::name('store_category')->insertGetId($mer_cate); + $mer_cate['pid']=$mer_cate_id; + $mer_cate['path']='/'.$mer_cate_id.'/'; + $mer_cate['level']=1; + $mer_cate_id=Db::name('store_category')->insertGetId($mer_cate); + } + $type=Db::name('merchant')->where('mer_id',$merId)->value('type_id'); + $product_type=0; + if ($type==12){ + $product_type=98;//供应链 + } + foreach ($data as $datum) { +// $find=Db::name('store_product')->where('mer_id', $merId)->where('bar_code', $datum['where']['bar_code'])->find(); +// if ($find){ +// Db::name('store_product')->where('product_id', $find['product_id'])->update($datum['value']); +// }else{ + $store_category_id=Db::name('store_category')->where('mer_id',0)->where('cate_name',$datum['value']['cate_id'])->value('store_category_id'); + if ($store_category_id==null){ + $store_category_id=438; + } + $datas = [ + "image" => "https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/luzhou/static4/oa_app/23565656.png", + "slider_image" => [ + 0 => "https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/luzhou/static4/oa_app/23565656.png", + ], + "store_name" => $datum['value']['store_name'].' '.$datum['value']['specifications'], + "store_info" => $datum['value']['store_name'], + "keyword" => $datum['value']['keyword'], + "bar_code" => $datum['value']['bar_code'], + "guarantee_template_id" => "", + "cate_id" => $store_category_id,//要修改 + "mer_cate_id" => [ + 0 => $mer_cate_id//要修改 + ], + 'product_type'=>$product_type, + "unit_name" => $datum['value']['unit_name'], + "sort" => 0, + "is_show" => "", + "is_good" => 0, + "is_gift_bag" => 0, + "integral_rate" => -1, + "video_link" => "", + "temp_id" => "", + "content" => "", + "spec_type" => 0, + "extension_type" => 0, + "attr" => [], + "mer_labels" => [], + "delivery_way" => [ + 0 => "2" + ], + "delivery_free" => 1, + "param_temp_id" => [], + "extend" => [], + "brand_id" => "", + "once_max_count" => 0, + "once_min_count" => 0, + "pay_limit" => 0, + "attrValue" => [ + [ + "image" => "https://lihai001.oss-cn-chengdu.aliyuncs.com/public/kk/luzhou/static4/oa_app/23565656.png", + "price" => $datum['value']['price'], + "cost" => $datum['value']['price'], + "ot_price" => $datum['value']['price'], + "svip_price" => null, + "stock" => $datum['value']['stock'], + "bar_code" => $datum['value']['bar_code'], + "weight" => 0, + "volume" => 0, + ], + ], + "give_coupon_ids" => [], + "type" => 0, + "svip_price" => 0, + "svip_price_type" => 0, + "params" => [], + "mer_id" => $merId, + "status" => 1, + "mer_status" => 1, + "rate" => 3, + ]; + $data_list=[ + 'data'=>$datas, + 'product_type'=>$product_type, + ]; + Queue::push(ProductImportJob::class,$data_list); + } + return true; + } + +} diff --git a/app/common/repositories/store/order/StoreOrderRepository.php.bak b/app/common/repositories/store/order/StoreOrderRepository.php.bak new file mode 100644 index 00000000..5304c504 --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderRepository.php.bak @@ -0,0 +1,2280 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\order; + +use app\common\dao\store\order\StoreOrderDao; +use app\common\model\store\order\StoreGroupOrder; +use app\common\model\store\order\StoreOrder; +use app\common\model\user\User; +use app\common\repositories\BaseRepository; +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductPresellSkuRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\StoreDiscountRepository; +use app\common\repositories\store\shipping\ExpressRepository; +use app\common\repositories\store\StorePrinterRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\serve\ServeDumpRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserMerchantRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\PayGiveCouponJob; +use crmeb\jobs\SendSmsJob; +use crmeb\jobs\UserBrokerageLevelJob; +use crmeb\services\CombinePayService; +use crmeb\services\CrmebServeServices; +use crmeb\services\ExpressService; +use crmeb\services\PayService; +use crmeb\services\printer\Printer; +use crmeb\services\QrcodeService; +use crmeb\services\SpreadsheetExcelService; +use crmeb\services\SwooleTaskService; +use Exception; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use http\Exception\InvalidArgumentException; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Log; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class StoreOrderRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/9 + * @mixin StoreOrderDao + */ +class StoreOrderRepository extends BaseRepository +{ + /** + * 支付类型 + */ + const PAY_TYPE = ['balance', 'weixin', 'routine', 'h5', 'alipay', 'alipayQr', 'weixinQr']; + + const TYPE_SN_ORDER = 'wxo'; + const TYPE_SN_PRESELL = 'wxp'; + const TYPE_SN_USER_ORDER = 'wxs'; + const TYPE_SN_USER_RECHARGE = 'wxu'; + + const TYPE_SN_REFUND = 'rwx'; + /** + * StoreOrderRepository constructor. + * @param StoreOrderDao $dao + */ + public function __construct(StoreOrderDao $dao) + { + $this->dao = $dao; + } + + /** + * @param string $type + * @param User $user + * @param StoreGroupOrder $groupOrder + * @param string $return_url + * @return mixed + * @author xaboy + * @day 2020/10/22 + */ + public function pay(string $type, User $user, StoreGroupOrder $groupOrder, $return_url = '', $isApp = false) + { + + if ($type === 'balance') { + return $this->payBalance($user, $groupOrder); + } + + if (in_array($type, ['weixin', 'alipay'], true) && $isApp) { + $type .= 'App'; + } + event('order.pay.before', compact('groupOrder', 'type', 'isApp')); + if (in_array($type, ['weixin', 'weixinApp', 'routine', 'h5', 'weixinQr'], true) && systemConfig('open_wx_combine')) { + $service = new CombinePayService($type, $groupOrder->getCombinePayParams()); + } else { + $service = new PayService($type, $groupOrder->getPayParams($type === 'alipay' ? $return_url : '')); + } + $config = $service->pay($user); + return app('json')->status($type, $config + ['order_id' => $groupOrder['group_order_id']]); + } + + /** + * @param User $user + * @param StoreGroupOrder $groupOrder + * @return mixed + * @author xaboy + * @day 2020/6/9 + */ + public function payBalance(User $user, StoreGroupOrder $groupOrder) + { + if (!systemConfig('yue_pay_status')) + throw new ValidateException('未开启余额支付'); + if ($user['now_money'] < $groupOrder['pay_price']) + throw new ValidateException('余额不足,请更换支付方式'); + Db::transaction(function () use ($user, $groupOrder) { + $user->now_money = bcsub($user->now_money, $groupOrder['pay_price'], 2); + $user->save(); + $userBillRepository = app()->make(UserBillRepository::class); + $userBillRepository->decBill($user['uid'], 'now_money', 'pay_product', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 1, + 'title' => '购买商品', + 'number' => $groupOrder['pay_price'], + 'mark' => '余额支付支付' . floatval($groupOrder['pay_price']) . '元购买商品', + 'balance' => $user->now_money + ]); + $this->paySuccess($groupOrder); + }); + return app('json')->status('success', '余额支付成功', ['order_id' => $groupOrder['group_order_id']]); + } + + public function changePayType(StoreGroupOrder $groupOrder, int $pay_type) + { + Db::transaction(function () use ($groupOrder, $pay_type) { + $groupOrder->pay_type = $pay_type; + foreach ($groupOrder->orderList as $order) { + $order->pay_type = $pay_type; + $order->save(); + } + $groupOrder->save(); + }); + } + + /** + * @return string + * @author xaboy + * @day 2020/8/3 + */ + public function verifyCode() + { + $code = substr(uniqid('', true), 15) . substr(microtime(), 2, 8); + if ($this->dao->existsWhere(['verify_code' => $code])) + return $this->verifyCode(); + else + return $code; + } + + /** + * //TODO 支付成功后 + * + * @param StoreGroupOrder $groupOrder + * @author xaboy + * @day 2020/6/9 + */ + public function paySuccess(StoreGroupOrder $groupOrder, $is_combine = 0, $subOrders = []) + { + $groupOrder->append(['user']); + //修改订单状态 + Db::transaction(function () use ($subOrders, $is_combine, $groupOrder) { + $time = date('Y-m-d H:i:s'); + $groupOrder->paid = 1; + $groupOrder->pay_time = $time; + $groupOrder->is_combine = $is_combine; + $orderStatus = []; + $groupOrder->append(['orderList.orderProduct']); + $flag = true; + $finance = []; + $profitsharing = []; + $financialRecordRepository = app()->make(FinancialRecordRepository::class); + $financeSn = $financialRecordRepository->getSn(); + $userMerchantRepository = app()->make(UserMerchantRepository::class); + $storeOrderProfitsharingRepository = app()->make(StoreOrderProfitsharingRepository::class); + $uid = $groupOrder->uid; + $i = 1; + $isVipCoupon = app()->make(StoreGroupOrderRepository::class)->isVipCoupon($groupOrder); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $svipDiscount = 0; + foreach ($groupOrder->orderList as $_k => $order) { + $order->paid = 1; + $order->pay_time = $time; + $svipDiscount = bcadd($order->svip_discount, $svipDiscount, 2); + if (isset($subOrders[$order->order_sn])) { + $order->transaction_id = $subOrders[$order->order_sn]['transaction_id']; + } + $presell = false; + //todo 等待付尾款 + if ($order->activity_type == 2) { + $_make = app()->make(ProductPresellSkuRepository::class); + if ($order->orderProduct[0]['cart_info']['productPresell']['presell_type'] == 2) { + $order->status = 10; + $presell = true; + } else { + $_make->incCount($order->orderProduct[0]['activity_id'], $order->orderProduct[0]['product_sku'], 'two_pay'); + } + $_make->incCount($order->orderProduct[0]['activity_id'], $order->orderProduct[0]['product_sku'], 'one_pay'); + } else if ($order->activity_type == 4) { + $order->status = 9; + $order->save(); + $group_buying_id = app()->make(ProductGroupBuyingRepository::class)->create( + $groupOrder->user, + $order->orderProduct[0]['cart_info']['activeSku']['product_group_id'], + $order->orderProduct[0]['activity_id'], + $order->order_id + ); + $order->orderProduct[0]->activity_id = $group_buying_id; + $order->orderProduct[0]->save(); + } else if ($order->activity_type == 3) { + //更新助力状态 + app()->make(ProductAssistSetRepository::class)->changStatus($order->orderProduct[0]['activity_id']); + } + if ($order->order_type == 1 && $order->status != 10) + $order->verify_code = $this->verifyCode(); + $order->save(); + $orderStatus[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单支付成功', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_PAY_SUCCCESS, + 'uid' => $order->uid, + 'nickname' => $order->user->nickname, + 'user_type' => $storeOrderStatusRepository::U_TYPE_USER, + ]; + + //TODO 成为推广员 + foreach ($order->orderProduct as $product) { + if ($flag && $product['cart_info']['product']['is_gift_bag']) { + app()->make(UserRepository::class)->promoter($order->uid); + $flag = false; + } + } + + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => $presell ? 'order_presell' : 'order', + 'financial_pm' => 1, + 'type' => $presell ? 2 : 1, + 'number' => $order->pay_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + + $_payPrice = bcsub($order->pay_price, bcadd($order['extension_one'], $order['extension_two'], 3), 2); + if ($presell) { + if (isset($order->orderProduct[0]['cart_info']['presell_extension_one']) && $order->orderProduct[0]['cart_info']['presell_extension_one'] > 0) { + $_payPrice = bcadd($_payPrice, $order->orderProduct[0]['cart_info']['presell_extension_one'], 2); + } + if (isset($order->orderProduct[0]['cart_info']['presell_extension_two']) && $order->orderProduct[0]['cart_info']['presell_extension_two'] > 0) { + $_payPrice = bcadd($_payPrice, $order->orderProduct[0]['cart_info']['presell_extension_two'], 2); + } + } + + $_order_rate = 0; + + if ($order['commission_rate'] > 0) { + + $commission_rate = ($order['commission_rate'] / 100); + + $_order_rate = bcmul($_payPrice, $commission_rate, 2); + + $_payPrice = bcsub($_payPrice, $_order_rate, 2); + } + + if (!$presell) { + if ($order['extension_one'] > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'brokerage_one', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order['extension_one'], + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + } + + if ($order['extension_two'] > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'brokerage_two', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order['extension_two'], + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + } + + if ($order['commission_rate'] > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'order_charge', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $_order_rate, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + } + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => 'order_true', + 'financial_pm' => 0, + 'type' => 2, + 'number' => $_payPrice, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + + if ($order->platform_coupon_price > 0) { + $finance[] = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'user_info' => $groupOrder->user->nickname, + 'user_id' => $uid, + 'financial_type' => $isVipCoupon ? 'order_svip_coupon' : 'order_platform_coupon', + 'financial_pm' => 0, + 'type' => 1, + 'number' => $order->platform_coupon_price, + 'mer_id' => $order->mer_id, + 'financial_record_sn' => $financeSn . ($i++) + ]; + $_payPrice = bcadd($_payPrice, $order->platform_coupon_price, 2); + } + + if (!$is_combine) { + app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'order', $order->order_id, $_payPrice); + } + } + if ($is_combine) { + $profitsharing[] = [ + 'profitsharing_sn' => $storeOrderProfitsharingRepository->getOrderSn(), + 'order_id' => $order->order_id, + 'transaction_id' => $order->transaction_id ?? '', + 'mer_id' => $order->mer_id, + 'profitsharing_price' => $order->pay_price, + 'profitsharing_mer_price' => $_payPrice, + 'type' => $storeOrderProfitsharingRepository::PROFITSHARING_TYPE_ORDER, + ]; + } + $userMerchantRepository->updatePayTime($uid, $order->mer_id, $order->pay_price); + SwooleTaskService::merchant('notice', [ + 'type' => 'new_order', + 'data' => [ + 'title' => '新订单', + 'message' => '您有一个新的订单', + 'id' => $order->order_id + ] + ], $order->mer_id); + //自动打印订单 + $this->autoPrinter($order->order_id, $order->mer_id); + } + if ($groupOrder->user->spread_uid) { + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->user->spread_uid, 'type' => 'spread_pay_num', 'inc' => 1]); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->user->spread_uid, 'type' => 'spread_money', 'inc' => $groupOrder->pay_price]); + } + app()->make(UserRepository::class)->update($groupOrder->uid, [ + 'pay_count' => Db::raw('pay_count+' . count($groupOrder->orderList)), + 'pay_price' => Db::raw('pay_price+' . $groupOrder->pay_price), + 'svip_save_money' => Db::raw('svip_save_money+' . $svipDiscount), + ]); + $this->giveIntegral($groupOrder); + if (count($profitsharing)) { + $storeOrderProfitsharingRepository->insertAll($profitsharing); + } + $financialRecordRepository->insertAll($finance); + $storeOrderStatusRepository->batchCreateLog($orderStatus); + if (count($groupOrder['give_coupon_ids']) > 0) + $groupOrder['give_coupon_ids'] = app()->make(StoreCouponRepository::class)->getGiveCoupon($groupOrder['give_coupon_ids'])->column('coupon_id'); + $groupOrder->save(); + }); + + if (count($groupOrder['give_coupon_ids']) > 0) { + try { + Queue::push(PayGiveCouponJob::class, ['ids' => $groupOrder['give_coupon_ids'], 'uid' => $groupOrder['uid']]); + } catch (Exception $e) { + } + } + + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_PAY_SUCCESS', 'id' => $groupOrder->group_order_id]); + Queue::push(SendSmsJob::class, ['tempId' => 'ADMIN_PAY_SUCCESS_CODE', 'id' => $groupOrder->group_order_id]); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->uid, 'type' => 'pay_money', 'inc' => $groupOrder->pay_price]); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->uid, 'type' => 'pay_num', 'inc' => 1]); + app()->make(UserBrokerageRepository::class)->incMemberValue($groupOrder->uid, 'member_pay_num', $groupOrder->group_order_id); + event('order.paySuccess', compact('groupOrder')); + } + + /** + * 自动打印 + * @Author:Qinii + * @Date: 2020/10/13 + * @param int $orderId + * @param int $merId + */ + public function autoPrinter(int $orderId, int $merId) + { + if (merchantConfig($merId, 'printing_auto_status')) { + try { + $this->batchPrinter($orderId, $merId); + } catch (Exception $exception) { + Log::info('自动打印小票报错:' . $exception); + } + } else { + Log::info('自动打印小票验证:商户ID【' . $merId . '】,自动打印状态未开启'); + } + } + + /** + * @return string + * @author xaboy + * @day 2020/6/9 + */ + public function getNewOrderId($type) + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $orderId = $type . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369)); + return $orderId; + } + + /** + * @param $cart + * @return string + * @author xaboy + * @day 2020/6/9 + */ + public function productByTempNumber($cart) + { + $type = $cart['product']['temp']['type']; + $cartNum = $cart['cart_num']; + if (!$type) + return $cartNum; + else if ($type == 2) { + return bcmul($cartNum, $cart['productAttr']['volume'], 2); + } else { + return bcmul($cartNum, $cart['productAttr']['weight'], 2); + } + } + + public function cartByPrice($cart) + { + if ($cart['product_type'] == '2') { + return $cart['productPresellAttr']['presell_price']; + } else if ($cart['product_type'] == '3') { + return $cart['productAssistAttr']['assist_price']; + } else if ($cart['product_type'] == '4') { + return $cart['activeSku']['active_price']; + } else { + return $cart['productAttr']['price']; + } + } + + public function cartByCouponPrice($cart) + { + if ($cart['product_type'] == '2') { + return $cart['productPresellAttr']['final_price']; + } else if ($cart['product_type'] == '1') { + return 0; + } else if ($cart['product_type'] == '3') { + return 0; + } else if ($cart['product_type'] == '4') { + return 0; + } else { + return $cart['productAttr']['price']; + } + } + + public function cartByDownPrice($cart) + { + if ($cart['product_type'] == '2') { + return $cart['productPresellAttr']['down_price']; + } else { + return 0; + } + } + + + /** + * @param int $uid + * @return array + * @author xaboy + * @day 2020/6/10 + */ + public function userOrderNumber(int $uid) + { + $noPay = app()->make(StoreGroupOrderRepository::class)->orderNumber($uid); + $noPostage = $this->dao->search(['uid' => $uid, 'status' => 0, 'paid' => 1,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $all = $this->dao->search(['uid' => $uid, 'status' => -2,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $noDeliver = $this->dao->search(['uid' => $uid, 'status' => 1, 'paid' => 1])->where('StoreOrder.is_del', 0)->count(); + $noComment = $this->dao->search(['uid' => $uid, 'status' => 2, 'paid' => 1,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $done = $this->dao->search(['uid' => $uid, 'status' => 3, 'paid' => 1,'is_user' => 1])->where('StoreOrder.is_del', 0)->count(); + $refund = app()->make(StoreRefundOrderRepository::class)->getWhereCount(['uid' => $uid, 'status' => [0, 1, 2]]); + //$orderPrice = $this->dao->search(['uid' => $uid, 'paid' => 1])->sum('pay_price'); + $orderCount = $this->dao->search(['uid' => $uid, 'paid' => 1,'is_user' => 1])->count(); + return compact('noComment', 'done', 'refund', 'noDeliver', 'noPay', 'noPostage', 'orderCount', 'all'); + } + + /** + * @param $id + * @param null $uid + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function getDetail($id, $uid = null) + { + $where = []; + $with = [ + 'orderProduct', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name,service_phone')->append(['services_type']); + }, + 'receipt' => function ($query) { + return $query->field('order_id,order_receipt_id'); + }, + 'takeOrderList.orderProduct' + ]; + if ($uid) { + $where['uid'] = $uid; + } else if (!$uid) { + $with['user'] = function ($query) { + return $query->field('uid,nickname'); + }; + } + $order = $this->dao->search($where)->where('order_id', $id)->where('StoreOrder.is_del', 0)->with($with)->append(['refund_status'])->find(); + if (!$order) { + return null; + } + if ($order->activity_type == 2) { + if ($order->presellOrder) { + $order->presellOrder->append(['activeStatus']); + $order->presell_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2); + } else { + $order->presell_price = $order->pay_price; + } + } + return $order; + } + + public function codeByDetail($code, $uid = null) + { + $where = []; + if ($uid) $where['uid'] = $uid; + $data = $this->dao->search($where)->where('verify_code', $code) + ->where('StoreOrder.is_del', 0) + ->with([ + 'orderProduct', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name'); + } + ]) + ->find(); + if (!$data) + throw new ValidateException('数据不存在'); + if ($data['status']) + throw new ValidateException('该订单已全部核销'); + return $data; + } + + public function giveIntegral($groupOrder) + { + if ($groupOrder->give_integral > 0) { + app()->make(UserBillRepository::class)->incBill($groupOrder->uid, 'integral', 'lock', [ + 'link_id' => $groupOrder['group_order_id'], + 'status' => 0, + 'title' => '下单赠送积分', + 'number' => $groupOrder->give_integral, + 'mark' => '成功消费' . floatval($groupOrder['pay_price']) . '元,赠送积分' . floatval($groupOrder->give_integral), + 'balance' => $groupOrder->user->integral + ]); + } + } + + /** + * @param StoreOrder $order + * @param User $user + * @author xaboy + * @day 2020/8/3 + */ + public function computed(StoreOrder $order, User $user) + { + $userBillRepository = app()->make(UserBillRepository::class); + if ($order->spread_uid) { + $spreadUid = $order->spread_uid; + $topUid = $order->top_uid; + } else if ($order->is_selfbuy) { + $spreadUid = $user->uid; + $topUid = $user->spread_uid; + } else { + $spreadUid = $user->spread_uid; + $topUid = $user->top_uid; + } + //TODO 添加冻结佣金 + if ($order->extension_one > 0 && $spreadUid) { + $userBillRepository->incBill($spreadUid, 'brokerage', 'order_one', [ + 'link_id' => $order['order_id'], + 'status' => 0, + 'title' => '获得推广佣金', + 'number' => $order->extension_one, + 'mark' => $user['nickname'] . '成功消费' . floatval($order['pay_price']) . '元,奖励推广佣金' . floatval($order->extension_one), + 'balance' => 0 + ]); + $userRepository = app()->make(UserRepository::class); + $userRepository->incBrokerage($spreadUid, $order->extension_one); + // app()->make(FinancialRecordRepository::class)->dec([ + // 'order_id' => $order->order_id, + // 'order_sn' => $order->order_sn, + // 'user_info' => $userRepository->getUsername($spreadUid), + // 'user_id' => $spreadUid, + // 'financial_type' => 'brokerage_one', + // 'number' => $order->extension_one, + // ], $order->mer_id); + } + if ($order->extension_two > 0 && $topUid) { + $userBillRepository->incBill($topUid, 'brokerage', 'order_two', [ + 'link_id' => $order['order_id'], + 'status' => 0, + 'title' => '获得推广佣金', + 'number' => $order->extension_two, + 'mark' => $user['nickname'] . '成功消费' . floatval($order['pay_price']) . '元,奖励推广佣金' . floatval($order->extension_two), + 'balance' => 0 + ]); + $userRepository = app()->make(UserRepository::class); + $userRepository->incBrokerage($topUid, $order->extension_two); + // app()->make(FinancialRecordRepository::class)->dec([ + // 'order_id' => $order->order_id, + // 'order_sn' => $order->order_sn, + // 'user_info' => $userRepository->getUsername($topUid), + // 'user_id' => $topUid, + // 'financial_type' => 'brokerage_two', + // 'number' => $order->extension_two, + // ], $order->mer_id); + } + } + + /** + * @param StoreOrder $order + * @param User $user + * @param string $type + * @author xaboy + * @day 2020/8/3 + */ + public function takeAfter(StoreOrder $order, ?User $user) + { + Db::transaction(function () use ($user, $order) { + if ($user) $this->computed($order, $user); + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_TAKE_SUCCESS', 'id' => $order->order_id]); + Queue::push(SendSmsJob::class, ['tempId' => 'ADMIN_TAKE_DELIVERY_CODE', 'id' => $order->order_id]); + app()->make(MerchantRepository::class)->computedLockMoney($order); + $order->save(); + }); + } + + /** + * @param $id + * @param User $user + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/17 + */ + public function takeOrder($id, ?User $user = null) + { + $order = $this->dao->search(!$user ? [] : ['uid' => $user->uid], null)->where('order_id', $id)->where('StoreOrder.is_del', 0)->find(); + if (!$order) + throw new ValidateException('订单不存在'); + if ($order['status'] != 1 || $order['order_type']) + throw new ValidateException('订单状态有误'); + $func = 'createUserLog'; + if (!$user){ + $func = 'createSysLog'; + $user = $order->user; + } +// if (!$user) { +// +// throw new ValidateException('用户不存在'); +// } + $order->status = 2; + $order->verify_time = date('Y-m-d H:i:s'); + event('order.take.before', compact('order')); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '已收货', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_TAKE, + ]; + Db::transaction(function () use ($order, $user,$storeOrderStatusRepository,$orderStatus,$func) { + $this->takeAfter($order, $user); + $order->save(); + $storeOrderStatusRepository->{$func}($orderStatus); + }); + event('order.take', compact('order')); + } + + + /** + * 获取订单列表头部统计数据 + * @Author:Qinii + * @Date: 2020/9/12 + * @param int|null $merId + * @param int|null $orderType + * @return array + */ + public function OrderTitleNumber(?int $merId, ?int $orderType) + { + $where = []; + $sysDel = $merId ? 0 : null; //商户删除 + if ($merId) $where['mer_id'] = $merId; //商户订单 + if ($orderType === 0) $where['order_type'] = 0; //普通订单 + if ($orderType === 1) $where['take_order'] = 1; //已核销订单 + //1: 未支付 2: 未发货 3: 待收货 4: 待评价 5: 交易完成 6: 已退款 7: 已删除 + $all = $this->dao->search($where, $sysDel)->where($this->getOrderType(0))->count(); + $statusAll = $all; + $unpaid = $this->dao->search($where, $sysDel)->where($this->getOrderType(1))->count(); + $unshipped = $this->dao->search($where, $sysDel)->where($this->getOrderType(2))->count(); + $untake = $this->dao->search($where, $sysDel)->where($this->getOrderType(3))->count(); + $unevaluate = $this->dao->search($where, $sysDel)->where($this->getOrderType(4))->count(); + $complete = $this->dao->search($where, $sysDel)->where($this->getOrderType(5))->count(); + $refund = $this->dao->search($where, $sysDel)->where($this->getOrderType(6))->count(); + $del = $this->dao->search($where, $sysDel)->where($this->getOrderType(7))->count(); + + return compact('all', 'statusAll', 'unpaid', 'unshipped', 'untake', 'unevaluate', 'complete', 'refund', 'del'); + } + + public function orderType(array $where) + { + return [ + [ + 'count' => $this->dao->search($where)->count(), + 'title' => '全部', + 'order_type' => -1, + ], + [ + 'count' => $this->dao->search($where)->where('order_type', 0)->where('is_virtual', 0)->count(), + 'title' => '普通订单', + 'order_type' => 0, + ], + [ + 'count' => $this->dao->search($where)->where('order_type', 1)->count(), + 'title' => '核销订单', + 'order_type' => 1, + ], + [ + 'count' => $this->dao->search($where)->where('is_virtual', 1)->count(), + 'title' => '虚拟商品订单', + 'order_type' => 2, + ], + ]; + } + + /** + * @param $status + * @return mixed + * @author Qinii + */ + public function getOrderType($status) + { + $param['StoreOrder.is_del'] = 0; + switch ($status) { + case 1: + $param['paid'] = 0; + break; // 未支付 + case 2: + $param['paid'] = 1; + $param['StoreOrder.status'] = 0; + break; // 待发货 + case 3: + $param['StoreOrder.status'] = 1; + break; // 待收货 + case 4: + $param['StoreOrder.status'] = 2; + break; // 待评价 + case 5: + $param['StoreOrder.status'] = 3; + break; // 交易完成 + case 6: + $param['StoreOrder.status'] = -1; + break; // 已退款 + case 7: + $param['StoreOrder.is_del'] = 1; + break; // 待核销 + break; // 已删除 + default: + unset($param['StoreOrder.is_del']); + break; //全部 + } + return $param; + } + + /** + * @param int $id + * @param int|null $merId + * @return array|Model|null + * @author Qinii + */ + public function merDeliveryExists(int $id, ?int $merId, ?int $re = 0) + { + $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 1]; + if ($re) $where['status'] = 0; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + /** + * TODO + * @param int $id + * @param int|null $merId + * @return bool + * @author Qinii + * @day 2020-06-11 + */ + public function merGetDeliveryExists(int $id, ?int $merId) + { + $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 1, 'status' => 1]; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + /** + * @param int $id + * @param int|null $merId + * @return array|Model|null + * @author Qinii + */ + public function merStatusExists(int $id, ?int $merId) + { + $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 0, 'status' => 0]; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + public function userDelExists(int $id, ?int $merId) + { + $where = ['order_id' => $id, 'is_del' => 1]; + if ($merId) $where['mer_id'] = $merId; + return $this->dao->merFieldExists($where); + } + + /** + * @param $id + * @return Form + * @author Qinii + */ + public function form($id) + { + $data = $this->dao->getWhere([$this->dao->getPk() => $id], 'total_price,pay_price,total_postage,pay_postage'); + $form = Elm::createForm(Route::buildUrl('merchantStoreOrderUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::number('total_price', '订单总价', $data['total_price'])->required(), + Elm::number('total_postage', '订单邮费', $data['total_postage'])->required(), + Elm::number('pay_price', '实际支付金额', $data['pay_price'])->required(), + ]); + return $form->setTitle('修改订单'); + } + + /** + * TODO 修改订单价格 + * @param int $id + * @param array $data + * @author Qinii + * @day 12/15/20 + */ + public function eidt(int $id, array $data, $service_id = 0) + { + + /** + * 1 计算出新的实际支付价格 + * 1.1 计算邮费 + * 1.2 计算商品总价 + * 2 修改订单信息 + * 3 计算总单数据 + * 4 修改总单数据 + * 5 修改订单商品单价 + * + * pay_price = total_price - coupon_price + pay_postage + */ + $order = $this->dao->get($id); + if ($order->activity_type == 2) { + throw new ValidateException('预售订单不支持改价'); + } + $extension_total = (float)bcadd($order->extension_one, $order->extension_two, 2); + $data['pay_price'] = $this->bcmathPrice($data['total_price'], $order['coupon_price'], $data['pay_postage']); + if ($data['pay_price'] < 0) { + throw new ValidateException('实际支付金额不能小于0'); + } else if ($data['pay_price'] < $extension_total) { + throw new ValidateException('实际支付金额不能小于佣金' . $extension_total); + } + $make = app()->make(StoreGroupOrderRepository::class); + $orderGroup = $make->dao->getWhere(['group_order_id' => $order['group_order_id']]); + + //总单总价格 + $_group['total_price'] = $this->bcmathPrice($orderGroup['total_price'], $order['total_price'], $data['total_price']); + //总单实际支付价格 + $_group['pay_price'] = $this->bcmathPrice($orderGroup['pay_price'], $order['pay_price'], $data['pay_price']); + //总单实际支付邮费 + $_group['pay_postage'] = $this->bcmathPrice($orderGroup['pay_postage'], $order['pay_postage'], $data['pay_postage']); + event('order.changePrice.before', compact('order', 'data')); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单价格修改', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CHANGE, + ]; + + Db::transaction(function () use ($id, $data, $orderGroup, $order, $_group,$storeOrderStatusRepository,$orderStatus,$service_id) { + $orderGroup->total_price = $_group['total_price']; + $orderGroup->pay_price = $_group['pay_price']; + $orderGroup->pay_postage = $_group['pay_postage']; + $orderGroup->group_order_sn = $this->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . '0'; + $orderGroup->save(); + + $this->dao->update($id, $data); + $this->changOrderProduct($id, $data); + + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + if ($data['pay_price'] != $order['pay_price']) Queue::push(SendSmsJob::class, ['tempId' => 'PRICE_REVISION_CODE', 'id' => $id]); + }); + event('order.changePrice', compact('order', 'data')); + } + + /** + * TODO 改价后重新计算每个商品的单价 + * @param int $orderId + * @param array $data + * @author Qinii + * @day 12/15/20 + */ + public function changOrderProduct(int $orderId, array $data) + { + $make = app()->make(StoreOrderProductRepository::class); + $ret = $make->getSearch(['order_id' => $orderId])->field('order_product_id,product_num,product_price')->select(); + $count = $make->getSearch(['order_id' => $orderId])->sum('product_price'); + $_count = (count($ret->toArray()) - 1); + $pay_price = $data['total_price']; + foreach ($ret as $k => $item) { + $_price = 0; + /** + * 比例 = 单个商品总价 / 订单原总价; + * + * 新的商品总价 = 比例 * 订单修改总价 + * + * 更新数据库 + */ + if ($k == $_count) { + $_price = $pay_price; + } else { + $_reta = bcdiv($item->product_price, $count, 3); + $_price = bcmul($_reta, $data['total_price'], 2); + } + + $item->product_price = $_price; + $item->save(); + + $pay_price = $this->bcmathPrice($pay_price, $_price, 0); + } + } + + /** + * TODO 计算的重复利用 + * @param $total + * @param $old + * @param $new + * @return int|string + * @author Qinii + * @day 12/15/20 + */ + public function bcmathPrice($total, $old, $new) + { + $_bcsub = bcsub($total, $old, 2); + $_count = (bccomp($_bcsub, 0, 2) == -1) ? 0 : $_bcsub; + $count = bcadd($_count, $new, 2); + return (bccomp($count, 0, 2) == -1) ? 0 : $count; + } + + /** + * @param $id + * @param $uid + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function refundProduct($id, $uid) + { + $order = $this->dao->userOrder($id, $uid); + if (!$order) + throw new ValidateException('订单不存在'); + if (!count($order->refundProduct)) + throw new ValidateException('没有可退款商品'); + return $order->refundProduct->toArray(); + } + + /** + * TODO + * @param $id + * @param $data + * @return mixed + * @author Qinii + * @day 7/26/21 + */ + public function orderDumpInfo($id, $data, $merId) + { + $where = [ + 'order_id' => $id, + ]; + $ret = $this->dao->getWhere($where); + if ($ret['is_virtual']) throw new ValidateException('虚拟商品只能虚拟发货'); + $cargo = ''; + $count = 0; + foreach ($ret->orderProduct as $item) { + // $cargo .= $item['cart_info']['product']['store_name']. ' ' .$item['cart_info']['productAttr']['sku'] .' * ' .$item['product_num'].$item['cart_info']['product']['unit_name'].PHP_EOL; + $count += $item['product_num']; + } + + $data['to_name'] = $ret['real_name']; + $data['to_tel'] = $ret['user_phone']; + $data['to_addr'] = $ret['user_address']; + $data['cargo'] = $cargo; + $data['count'] = $count; + $data['order_sn'] = $ret['order_sn']; + return $data; + } + + /** + * TODO 批量发货 + * @param int $merId + * @param array $params + * @author Qinii + * @day 7/26/21 + */ + public function batchDelivery(int $merId, array $params) + { + $count = count($params['order_id']); + $import = app()->make(StoreImportRepository::class)->create($merId, 'delivery', $params['delivery_type']); + $make = app()->make(StoreImportDeliveryRepository::class); + $data = []; + $num = 0; + foreach ($params['order_id'] as $item) { + $ret = $this->dao->getWhere(['order_id' => $params['order_id']]); + $imp = [ + 'order_sn' => $ret['order_sn'] ?? $item, + 'delivery_id' => $params['delivery_id'], + 'delivery_type' => $params['delivery_type'], + 'delivery_name' => $params['delivery_name'], + 'import_id' => $import['import_id'], + 'mer_id' => $merId + ]; + + if (!$ret || $ret['status'] != 1 || $ret['mer_id'] != $merId || $ret['is_del'] != 0 || $ret['paid'] != 1 || $ret['delivery_type'] != 0 ) { + $imp['status'] = 0; + $imp['mark'] = '订单信息不存在或状态错误'; + } else { + try { + if ($params['delivery_type'] == 4) { + $dump = [ + 'temp_id' => $params['temp_id'], + 'from_tel' => $params['from_tel'], + 'from_addr' => $params['from_addr'], + 'from_name' => $params['from_name'], + 'delivery_name' => $params['delivery_name'], + ]; + $dump = $this->orderDumpInfo($item, $dump, $merId); + $ret = $this->dump($item, $merId, $dump); + $imp['delivery_id'] = $ret['delivery_id']; + $imp['delivery_name'] = $ret['delivery_name']; + } else { + $this->delivery($item, $merId,[ + 'delivery_id' => $params['delivery_id'], + 'delivery_type' => $params['delivery_type'], + 'delivery_name' => $params['delivery_name'], + ]); + } + $num++; + $imp['status'] = 1; + } catch (Exception $exception) { + $imp['status'] = 0; + $imp['mark'] = $exception->getMessage(); + } + } + $data[] = $imp; + } + + $_status = ($num == 0) ? -1 : (($count == $num) ? 1 : 10); + $make->insertAll($data); + $arr = ['count' => $count, 'success' => $num, 'status' => $_status]; + app()->make(StoreImportRepository::class)->update($import['import_id'], $arr); + } + + + /** + * TODO 打印电子面单,组合参数 + * @param int $id + * @param int $merId + * @param array $data + * @return mixed + * @author Qinii + * @day 7/26/21 + */ + public function dump(int $id, int $merId, array $data, $service_id = 0) + { + $make = app()->make(MerchantRepository::class); + $make->checkCrmebNum($merId, 'dump'); + + $data = $this->orderDumpInfo($id, $data, $merId); + + $data['com'] = $data['delivery_name']; + $result = app()->make(CrmebServeServices::class)->express()->dump($merId, $data); + if (!isset($result['kuaidinum'])) throw new ValidateException('打印失败'); + + $delivery = [ + 'delivery_type' => 4, + 'delivery_name' => $data['delivery_name'], + 'delivery_id' => $result['kuaidinum'], + 'remark' => $data['remark'] ?? '', + ]; + + $dump = [ + 'delivery_name' => $delivery['delivery_name'], + 'delivery_id' => $delivery['delivery_id'], + 'from_name' => $data['from_name'], + 'order_sn' => $data['order_sn'], + 'to_name' => $data['to_name'], + ]; + Db::transaction(function () use ($merId, $id, $delivery, $make, $dump, $service_id) { + $this->delivery($id, $merId, $delivery,$service_id); + $arr = [ + 'type' => 'mer_dump', + 'num' => -1, + 'message' => '电子面单', + 'info' => $dump + ]; + app()->make(ProductCopyRepository::class)->add($arr, $merId); + }); + return $delivery; + } + + public function runDelivery($id, $merId, $data, $split, $method,$service_id = 0) + { + return Db::transaction(function () use ($id, $merId, $data, $split, $method,$service_id) { + if ($split['is_split'] && !empty($split['split'])) { + foreach ($split['split'] as $v) { + $splitData[$v['id']] = $v['num']; + } + $order = $this->dao->get($id); + $newOrder = app()->make(StoreOrderSplitRepository::class)->splitOrder($order, $splitData,$service_id); + if ($newOrder){ + $id = $newOrder->order_id; + } else { + throw new ValidateException('商品不能全部拆单'); + } + } + return $this->{$method}($id, $merId, $data,$service_id); + }); + } + + /** + * TODO 发货订单操作 + * @param $id + * @param $data + * @return mixed + * @author Qinii + * @day 7/26/21 + */ + public function delivery($id, $merId, $data, $service_id = 0) + { + $data['status'] = 1; + $order = $this->dao->get($id); + if ($order['is_virtual'] && $data['delivery_type'] != 3) + throw new ValidateException('虚拟商品只能虚拟发货'); + //订单记录 + $statusRepository = app()->make(StoreOrderStatusRepository::class); + switch ($data['delivery_type']) { + case 1: + $exprss = app()->make(ExpressRepository::class)->getWhere(['code' => $data['delivery_name']]); + if (!$exprss) throw new ValidateException('快递公司不存在'); + $data['delivery_name'] = $exprss['name']; + $change_type = $statusRepository::ORDER_DELIVERY_COURIER; + $change_message = '订单已配送【快递名称】:' . $exprss['name'] . '; 【快递单号】:' . $data['delivery_id']; + $temp_code = 'DELIVER_GOODS_CODE'; + break; + case 2: + if (!preg_match("/^1[3456789]{1}\d{9}$/", $data['delivery_id'])) throw new ValidateException('手机号格式错误'); + $change_type = 'delivery_1'; + $change_message = '订单已配送【送货人姓名】:' . $data['delivery_name'] . '; 【手机号】:' . $data['delivery_id']; + $temp_code = 'ORDER_DELIVER_SUCCESS'; + break; + case 3: + $change_type = $statusRepository::ORDER_DELIVERY_NOTHING; + $change_message = '订单已配送【虚拟发货】'; + $data['status'] = 2; + break; + case 4: + $exprss = app()->make(ExpressRepository::class)->getWhere(['code' => $data['delivery_name']]); + if (!$exprss) throw new ValidateException('快递公司不存在'); + $data['delivery_name'] = $exprss['name']; + $change_type = $statusRepository::ORDER_DELIVERY_COURIER; + $change_message = '订单已配送【快递名称】:' . $exprss['name'] . '; 【快递单号】:' . $data['delivery_id']; + $temp_code = 'DELIVER_GOODS_CODE'; + break; + } + + event('order.delivery.before', compact('order', 'data')); + $this->dao->update($id, $data); + + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => $change_message, + 'change_type' => $change_type, + ]; + if ($service_id) { + $statusRepository->createServiceLog($service_id,$orderStatus); + } else { + $statusRepository->createAdminLog($orderStatus); + } + + + //虚拟发货后用户直接确认收获 + if($data['status'] == 2){ + $user = app()->make(UserRepository::class)->get($order['uid']); + //订单记录 + $this->takeAfter($order,$user); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '虚拟发货后', + 'change_type' => $statusRepository::ORDER_STATUS_TAKE, + ]; + $statusRepository->createSysLog($orderStatus); + + } + if (isset($temp_code)) Queue::push(SendSmsJob::class, ['tempId' => $temp_code, 'id' => $order->order_id]); + + event('order.delivery', compact('order', 'data')); + return $data; + } + + /** + * TODO 同城配送 + * @param int $id + * @param int $merId + * @param array $data + * @author Qinii + * @day 2/16/22 + */ + public function cityDelivery(int $id, int $merId, array $data, $service_id) + { + $make = app()->make(DeliveryOrderRepository::class); + $order = $this->dao->get($id); + if ($order['is_virtual']) + throw new ValidateException('虚拟商品只能虚拟发货'); + $make->create($id, $merId, $data, $order); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $this->dao->update($id, ['delivery_type' => 5, 'status' => 1,'remark' => $data['remark']]); + + $orderStatus = [ + 'order_id' => $id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单配送【同城配送】', + 'change_type' => $storeOrderStatusRepository::ORDER_DELIVERY_SELF, + ]; + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + + Queue::push(SendSmsJob::class, ['tempId' => 'ORDER_DELIVER_SUCCESS', 'id' => $id]); + } + + + public function getOne($id, ?int $merId) + { + $where = [$this->getPk() => $id]; + if ($merId) { + $whre['mer_id'] = $merId; + $whre['is_system_del'] = 0; + } + $res = $this->dao->getWhere($where, '*', [ + 'orderProduct', + 'user' => function ($query) { + $query->field('uid,real_name,nickname,is_svip,svip_endtime,phone'); + }, + 'refundOrder' => function ($query) { + $query->field('order_id,extension_one,extension_two,refund_price,integral')->where('status', 3); + }, + 'finalOrder', + 'TopSpread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ] + ); + if (!$res) throw new ValidateException('数据不存在'); + $res['integral'] = (int)$res['integral']; + return $res->append(['refund_extension_one', 'refund_extension_two']); + } + + public function getOrderStatus($where, $page, $limit) + { + $where['type'] = StoreOrderStatusRepository::TYPE_ORDER; + return app()->make(StoreOrderStatusRepository::class)->search($where, $page, $limit); + } + + public function remarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('merchantStoreOrderRemark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('remark', '备注', $data['remark'])->required(), + ]); + return $form->setTitle('订单备注'); + } + + public function adminMarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantOrderMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('admin_mark', '备注', $data['admin_mark'])->required(), + ]); + return $form->setTitle('订单备注'); + } + + /** + * TODO 平台每个商户的订单列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-15 + */ + public function adminMerGetList($where, $page, $limit) + { + $where['paid'] = 1; + $query = $this->dao->search($where, null); + $count = $query->count(); + $list = $query->with([ + 'orderProduct', + 'merchant' => function ($query) { + $query->field('mer_id,mer_name,is_trader'); + }, + 'groupOrder' => function ($query) { + $query->field('group_order_id,group_order_sn'); + }, + 'finalOrder', + 'user' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ])->page($page, $limit)->select()->append(['refund_extension_one', 'refund_extension_two']); + + return compact('count', 'list'); + } + + public function reconList($where, $page, $limit) + { + $ids = app()->make(MerchantReconciliationOrderRepository::class)->getIds($where); + $query = $this->dao->search([], null)->whereIn('order_id', $ids); + $count = $query->count(); + $list = $query->with(['orderProduct'])->page($page, $limit)->select()->each(function ($item) { + //(实付金额 - 一级佣金 - 二级佣金) * 抽成 + $commission_rate = ($item['commission_rate'] / 100); + //佣金 + $_order_extension = bcadd($item['extension_one'], $item['extension_two'], 3); + //手续费 = (实付金额 - 一级佣金 - 二级佣金) * 比例 + $_order_rate = bcmul(bcsub($item['pay_price'], $_order_extension, 3), $commission_rate, 3); + $item['order_extension'] = round($_order_extension, 2); + $item['order_rate'] = round($_order_rate, 2); + return $item; + }); + + return compact('count', 'list'); + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @author Qinii + */ + public function merchantGetList(array $where, $page, $limit) + { + $status = $where['status']; + unset($where['status']); + $query = $this->dao->search($where)->where($this->getOrderType($status)) + ->with([ + 'orderProduct', + 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }, + 'verifyService' => function ($query) { + $query->field('service_id,nickname'); + }, + 'finalOrder', + 'groupUser.groupBuying', + 'TopSpread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['refund_extension_one', 'refund_extension_two']) + ->each(function($item){ + // 1:退款中 2:部分退款 3 = 全退 + $refunding = 0; + if ($item['orderProduct']) { + $is_refund = array_column($item['orderProduct']->toArray(),'is_refund'); + $is_refund = array_unique($is_refund); + if (in_array(1,$is_refund)) { + $refunding = 1; + } else if (in_array(2,$is_refund)) { + $refunding = 2; + } else if (in_array(3,$is_refund)) { + $refunding = 3; + } + } + $item['refunding'] = $refunding; + }); + + + return compact('count', 'list'); + } + + /** + * TODO 平台总的订单列表 + * @param array $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-15 + */ + public function adminGetList(array $where, $page, $limit) + { + $status = $where['status']; + unset($where['status']); + $query = $this->dao->search($where, null)->where($this->getOrderType($status)) + ->with([ + 'orderProduct', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name,is_trader'); + }, + 'verifyService' => function ($query) { + return $query->field('service_id,nickname'); + }, + 'groupOrder' => function ($query) { + $query->field('group_order_id,group_order_sn'); + }, + 'finalOrder', + 'groupUser.groupBuying', + 'TopSpread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + 'user' => function ($query) { + $query->field('uid,nickname,avatar'); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['refund_extension_one', 'refund_extension_two']); + + return compact('count', 'list'); + } + + public function getStat(array $where, $status) + { + unset($where['status']); + $make = app()->make(StoreRefundOrderRepository::class); + $presellOrderRepository = app()->make(PresellOrderRepository::class); + + //退款订单id + $orderId = $this->dao->search($where)->where($this->getOrderType($status))->column('order_id'); + //退款金额 + $orderRefund = $make->refundPirceByOrder($orderId); + //实际支付订单数量 + $all = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->count(); + //实际支付订单金额 + $countQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1); + $countOrderId = $countQuery->column('order_id'); + $countPay1 = $countQuery->sum('StoreOrder.pay_price'); + $countPay2 = $presellOrderRepository->search(['paid' => 1, 'order_ids' => $countOrderId])->sum('pay_price'); + $countPay = bcadd($countPay1, $countPay2, 2); + + //余额支付 + $banclQuery = $this->dao->search(array_merge($where, ['paid' => 1, 'pay_type' => 0]))->where($this->getOrderType($status)); + $banclOrderId = $banclQuery->column('order_id'); + $banclPay1 = $banclQuery->sum('StoreOrder.pay_price'); + $banclPay2 = $presellOrderRepository->search(['pay_type' => [0], 'paid' => 1, 'order_ids' => $banclOrderId])->sum('pay_price'); + $banclPay = bcadd($banclPay1, $banclPay2, 2); + + //微信金额 + $wechatQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->where('pay_type', 'in', [1, 2, 3, 6]); + $wechatOrderId = $wechatQuery->column('order_id'); + $wechatPay1 = $wechatQuery->sum('StoreOrder.pay_price'); + $wechatPay2 = $presellOrderRepository->search(['pay_type' => [1, 2, 3, 6], 'paid' => 1, 'order_ids' => $wechatOrderId])->sum('pay_price'); + $wechatPay = bcadd($wechatPay1, $wechatPay2, 2); + + //支付宝金额 + $aliQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->where('pay_type', 'in', [4, 5]); + $aliOrderId = $aliQuery->column('order_id'); + $aliPay1 = $aliQuery->sum('StoreOrder.pay_price'); + $aliPay2 = $presellOrderRepository->search(['pay_type' => [4, 5], 'paid' => 1, 'order_ids' => $aliOrderId])->sum('pay_price'); + $aliPay = bcadd($aliPay1, $aliPay2, 2); + + + $stat = [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $all, + 'field' => '件', + 'name' => '已支付订单数量' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => (float)$countPay, + 'field' => '元', + 'name' => '实际支付金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)$orderRefund, + 'field' => '元', + 'name' => '已退款金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)$wechatPay, + 'field' => '元', + 'name' => '微信支付金额' + ], + [ + 'className' => 'el-icon-s-finance', + 'count' => (float)$banclPay, + 'field' => '元', + 'name' => '余额支付金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)$aliPay, + 'field' => '元', + 'name' => '支付宝支付金额' + ], + ]; + return $stat; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->where('StoreOrder.is_del', 0); + $count = $query->count(); + $list = $query->with([ + 'orderProduct', + 'presellOrder', + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name'); + }, + 'community', + 'receipt' => function ($query) { + return $query->field('order_id,order_receipt_id'); + }, + ])->page($page, $limit)->order('pay_time DESC')->append(['refund_status'])->select(); + + foreach ($list as $order) { + if ($order->activity_type == 2) { + if ($order->presellOrder) { + $order->presellOrder->append(['activeStatus']); + $order->presell_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2); + } else { + $order->presell_price = $order->pay_price; + } + } + $order->takeOrderCount = count($order['takeOrderList']); + unset($order['takeOrderList']); + } + + return compact( 'count','list'); + } + + public function userList($uid, $page, $limit) + { + $query = $this->dao->search([ + 'uid' => $uid, + 'paid' => 1 + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + + public function userMerList($uid, $merId, $page, $limit) + { + $query = $this->dao->search([ + 'uid' => $uid, + 'mer_id' => $merId, + 'paid' => 1 + ]); + $count = $query->count(); + $list = $query->with(['presellOrder'])->page($page, $limit)->select(); + foreach ($list as $order) { + if ($order->activity_type == 2 && $order->status >= 0 && $order->status < 10 && $order->presellOrder) { + $order->pay_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2); + } + } + return compact('count', 'list'); + } + + public function express(int $orderId, ?int $merId) + { + $order = $this->dao->get($orderId); + if ($merId && $order['mer_id'] != $merId) throw new ValidateException('订单信息不存在'); + if (!in_array($order['delivery_type'], [1, 4])) throw new ValidateException('订单状态错误'); + return ExpressService::express($order->delivery_id, $order->delivery_name, $order->user_phone); + } + + public function checkPrinterConfig(int $merId) + { + if (!merchantConfig($merId, 'printing_status')) + throw new ValidateException('打印功能未开启'); + $config = [ + 'clientId' => merchantConfig($merId, 'printing_client_id'), + 'apiKey' => merchantConfig($merId, 'printing_api_key'), + 'partner' => merchantConfig($merId, 'develop_id'), + 'terminal' => merchantConfig($merId, 'terminal_number') + ]; + if (!$config['clientId'] || !$config['apiKey'] || !$config['partner'] || !$config['terminal']) + throw new ValidateException('打印机配置错误'); + return $config; + } + + /** + * TODO 打印机 -- 暂无使用 + * @param int $id + * @param int $merId + * @return bool|mixed|string + * @author Qinii + * @day 2020-07-30 + */ + public function printer(int $id, int $merId) + { + $order = $this->dao->getWhere(['order_id' => $id], '*', ['orderProduct', 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }]); + foreach ($order['orderProduct'] as $item) { + $product[] = [ + 'store_name' => $item['cart_info']['product']['store_name'] . '【' . $item['cart_info']['productAttr']['sku'] . '】', + 'product_num' => $item['product_num'], + 'price' => bcdiv($item['product_price'], $item['product_num'], 2), + 'product_price' => $item['product_price'], + ]; + } + $data = [ + 'order_sn' => $order['order_sn'], + 'pay_time' => $order['pay_time'], + 'real_name' => $order['real_name'], + 'user_phone' => $order['user_phone'], + 'user_address' => $order['user_address'], + 'total_price' => $order['total_price'], + 'coupon_price' => $order['coupon_price'], + 'pay_price' => $order['pay_price'], + 'total_postage' => $order['total_postage'], + 'pay_postage' => $order['pay_postage'], + 'mark' => $order['mark'], + ]; + $config = $this->checkPrinterConfig($merId); + $printer = new Printer('yi_lian_yun', $config); + event('order.print.before', compact('order')); + + $res = $printer->setPrinterContent([ + 'name' => $order['merchant']['mer_name'], + 'orderInfo' => $data, + 'product' => $product + ])->startPrinter(); + + event('order.print', compact('order', 'res')); + + return $res; + } + + public function batchPrinter(int $id, int $merId) + { + $order = $this->dao->getWhere(['order_id' => $id], '*', ['orderProduct', 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }]); + + foreach ($order['orderProduct'] as $item) { + $product[] = [ + 'store_name' => $item['cart_info']['product']['store_name'] . '【' . $item['cart_info']['productAttr']['sku'] . '】', + 'product_num' => $item['product_num'], + 'price' => bcdiv($item['product_price'], $item['product_num'], 2), + 'product_price' => $item['product_price'], + ]; + } + + $data = [ + 'order_sn' => $order['order_sn'], + 'order_type' => $order['order_type'], + 'pay_time' => $order['pay_time'], + 'real_name' => $order['real_name'], + 'user_phone' => $order['user_phone'], + 'user_address' => $order['user_address'], + 'total_price' => $order['total_price'], + 'coupon_price' => $order['coupon_price'], + 'pay_price' => $order['pay_price'], + 'total_postage' => $order['total_postage'], + 'pay_postage' => $order['pay_postage'], + 'mark' => $order['mark'], + ]; + + $printer = app()->make(StorePrinterRepository::class)->getPrinter($merId); + event('order.print.before', compact('order')); + foreach ($printer as $config) { + $printer = new Printer('yi_lian_yun', $config); + $res = $printer->setPrinterContent([ + 'name' => $order['merchant']['mer_name'], + 'orderInfo' => $data, + 'product' => $product + ])->startPrinter(); + } + + event('order.print', compact('order', 'res')); + } + + + public function verifyOrder(int $id, int $merId, array $data, $serviceId = 0) + { + $order = $this->dao->getWhere(['order_id' => $id, 'mer_id' => $merId,'verify_code' => $data['verify_code'],'order_type' => 1],'*',['orderProduct']); + if (!$order) throw new ValidateException('订单不存在'); + if (!$order->paid) throw new ValidateException('订单未支付'); + if ($order['status']) throw new ValidateException('订单已全部核销,请勿重复操作'); + foreach ($data['data'] as $v) { + $splitData[$v['id']] = $v['num']; + } + $spl = app()->make(StoreOrderSplitRepository::class)->splitOrder($order, $splitData, $serviceId, 1); + if ($spl) $order = $spl; + $order->status = 2; + $order->verify_time = date('Y-m-d H:i:s'); + $order->verify_service_id = $serviceId; + event('order.verify.before', compact('order')); + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + Db::transaction(function () use ($order,$storeOrderStatusRepository,$serviceId) { + $this->takeAfter($order, $order->user); + $order->save(); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单已核销', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_TAKE, + ]; + if ($serviceId){ + $storeOrderStatusRepository->createServiceLog($serviceId,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + + }); + event('order.verify', compact('order')); + } + + public function wxQrcode($orderId, $verify_code) + { + $siteUrl = systemConfig('site_url'); + $name = md5('owx' . $orderId . date('Ymd')) . '.jpg'; + $attachmentRepository = app()->make(AttachmentRepository::class); + $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]); + + if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) { + $imageInfo->delete(); + $imageInfo = null; + } + if (!$imageInfo) { + // $codeUrl = set_http_type(rtrim($siteUrl, '/') . '/pages/admin/order_cancellation/index?verify_code=' . $verify_code, request()->isSsl() ? 0 : 1);//二维码链接 + $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($verify_code, $name); + if (is_string($imageInfo)) throw new ValidateException('二维码生成失败'); + + $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl); + + $attachmentRepository->create(systemConfig('upload_type') ?: 1, -2, $orderId, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $urlCode = $imageInfo['dir']; + } else $urlCode = $imageInfo['attachment_src']; + return $urlCode; + } + + /** + * TODO 根据商品ID获取订单数 + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-05 + */ + public function seckillOrderCounut(int $productId) + { + $where = [ + 'activity_id' => $productId, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + $count = $this->dao->getTattendCount($where, null)->count(); + $count_ = $this->dao->getSeckillRefundCount($where, 2); + $count__ = $this->dao->getSeckillRefundCount($where, 1); + return $count - $count_ - $count__; + } + + /** + * TODO 根据商品sku获取订单数 + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-05 + */ + public function seckillSkuOrderCounut(string $sku) + { + $where = [ + 'product_sku' => $sku, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + $count = $this->dao->getTattendCount($where, null)->count(); + $count_ = $this->dao->getSeckillRefundCount($where, 2); + $count__ = $this->dao->getSeckillRefundCount($where, 1); + return $count - $count_ - $count__; + } + + /** + * TODO 获取sku的总销量 + * @param string $sku + * @return int|mixed + * @author Qinii + * @day 3/4/21 + */ + public function skuSalesCount(string $sku) + { + $where = [ + 'product_sku' => $sku, + 'product_type' => 1, + ]; + $count = $this->dao->getTattendSuccessCount($where, null)->count(); + $count_ = $this->dao->getSeckillRefundCount($where, 2); + $count__ = $this->dao->getSeckillRefundCount($where, 1); + return $count - $count_ - $count__; + } + + /** + * TODO 秒杀获取个人当天限购 + * @param int $uid + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-15 + */ + public function getDayPayCount(int $uid, int $productId) + { + $make = app()->make(StoreSeckillActiveRepository::class); + $active = $make->getWhere(['product_id' => $productId]); + if ($active['once_pay_count'] == 0) return true; + + $where = [ + 'activity_id' => $productId, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + + $count = $this->dao->getTattendCount($where, $uid)->count(); + return ($active['once_pay_count'] > $count); + } + + /** + * TODO 秒杀获取个人总限购 + * @param int $uid + * @param int $productId + * @return int + * @author Qinii + * @day 2020-08-15 + */ + public function getPayCount(int $uid, int $productId) + { + $make = app()->make(StoreSeckillActiveRepository::class); + $active = $make->getWhere(['product_id' => $productId]); + if ($active['all_pay_count'] == 0) return true; + $where = [ + 'activity_id' => $productId, + 'product_type' => 1, + 'day' => date('Y-m-d', time()) + ]; + $count = $this->dao->getTattendCount($where, $uid)->count(); + return ($active['all_pay_count'] > $count); + } + + /** + * 根据订单id查看是否全部退款 + * @Author:Qinii + * @Date: 2020/9/11 + * @param int $orderId + * @return bool + */ + public function checkRefundStatusById(int $orderId, int $refundId) + { + return Db::transaction(function () use ($orderId, $refundId) { + $res = $this->dao->search(['order_id' => $orderId])->with(['orderProduct'])->find(); + $refund = app()->make(StoreRefundOrderRepository::class)->getRefundCount($orderId, $refundId); + if ($refund) return false; + foreach ($res['orderProduct'] as $item) { + if ($item['refund_num'] !== 0) return false; + $item->is_refund = 3; + $item->save(); + } + $res->status = -1; + $res->save(); + $this->orderRefundAllAfter($res); + return true; + }); + } + + public function orderRefundAllAfter($order) + { + + if ($order->activity_type == 10) { + app()->make(StoreDiscountRepository::class)->incStock($order->orderProduct[0]['activity_id']); + } + $mainId = $order->main_id ?: $order->order_id; + $count = $this->query([])->where('status', '<>', -1)->where(function ($query) use ($mainId) { + $query->where('order_id', $mainId)->whereOr('main_id', $mainId); + })->count(); + //拆单后完全退完 + if (!$count) { + if ($order->main_id) { + $order = $this->query(['order_id' => $mainId])->find(); + } + $couponId = []; + if ($order->coupon_id) { + $couponId = explode(',', $order->coupon_id); + } + app()->make(MerchantRepository::class)->computedLockMoney($order); + //总单所有订单全部退完 + if (!$this->query([])->where('status', '<>', -1)->where('group_order_id', $order->group_order_id)->count()) { + if ($order->groupOrder->coupon_id) { + $couponId[] = $order->groupOrder->coupon_id; + } + } + if (count($couponId)) { + app()->make(StoreCouponUserRepository::class)->updates($couponId, ['status' => 0]); + } + + } + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单已全部退款', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_REFUND_ALL, + ]; + $storeOrderStatusRepository->createSysLog($orderStatus); + + event('order.refundAll', compact('order')); + } + + /** + * @param $id + * @param $uid + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/9/17 + */ + public function userDel($id, $uid) + { + $order = $this->dao->getWhere([['status', 'in', [0, 3, -1, 11]], ['order_id', '=', $id], ['uid', '=', $uid], ['is_del', '=', 0]]); + if (!$order || ($order->status == 0 && $order->paid == 1)) + throw new ValidateException('订单状态有误'); + event('order.userDel.before', compact('order')); + $this->delOrder($order, '订单删除'); + event('order.userDel', compact('order')); + } + + public function delOrder($order, $info = '订单删除') + { + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => $info, + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_DELETE, + ]; + $productRepository = app()->make(ProductRepository::class); + Db::transaction(function () use ($info, $order, $orderStatus, $storeOrderStatusRepository,$productRepository) { + $order->is_del = 1; + $order->save(); + $storeOrderStatusRepository->createUserLog($orderStatus); + foreach ($order->orderProduct as $cart) { + $productRepository->orderProductIncStock($order, $cart); + } + }); + } + + public function merDelete($id) + { + Db::transaction(function () use ($id) { + $data['is_system_del'] = 1; + $this->dao->update($id, $data); + app()->make(StoreOrderReceiptRepository::class)->deleteByOrderId($id); + }); + } + + /** + * @param $id + * @return \FormBuilder\Form + * @author Qinii + */ + public function sendProductForm($id, $data) + { + $express = app()->make(ExpressRepository::class)->options(); + $form = Elm::createForm(Route::buildUrl('merchantStoreOrderDelivery', ['id' => $id])->build()); + + if (in_array($data['delivery_type'], [1, 2])) { + if ($data['delivery_type'] == 1) { + $form->setRule([ + Elm::hidden('delivery_type', 1), + [ + 'type' => 'span', + 'title' => '原快递名称', + 'children' => [(string)$data['delivery_name']] + ], + [ + 'type' => 'span', + 'title' => '原快递单号', + 'children' => [(string)$data['delivery_id']] + ], + Elm::select('delivery_name', '快递名称')->options(function () use ($express) { + return $express; + }), + Elm::input('delivery_id', '快递单号')->required(), + ]); + } else { + $form->setRule([ + Elm::hidden('delivery_type', 2), + [ + 'type' => 'span', + 'title' => '原送货人姓名', + 'children' => [(string)$data['delivery_name']] + ], + [ + 'type' => 'span', + 'title' => '原手机号', + 'children' => [(string)$data['delivery_id']] + ], + Elm::input('delivery_name', '送货人姓名')->required(), + Elm::input('delivery_id', '手机号')->required(), + ]); + } + } + if ($data['delivery_type'] == 3) { + $form->setRule([ + Elm::hidden('delivery_type', 3), + [ + 'type' => 'span', + 'title' => '发货类型', + 'children' => ['无需配送'] + ] + ]); + } + if (!$data['delivery_type']) { + $form->setRule([ + Elm::radio('delivery_type', '发货类型', 1) + ->setOptions([ + ['value' => 1, 'label' => '发货'], + ['value' => 2, 'label' => '送货'], + ['value' => 3, 'label' => '无需配送'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::select('delivery_name', '快递名称')->options(function () use ($express) { + return $express; + }), + Elm::input('delivery_id', '快递单号')->required(), + ] + ], + [ + 'value' => 2, + 'rule' => [ + Elm::input('delivery_name', '送货人姓名')->required(), + Elm::input('delivery_id', '手机号')->required(), + ] + ], + [ + 'value' => 3, + 'rule' => [] + ], + + ]), + ]); + } + + return $form->setTitle('发货信息'); + } + + /** + * TODO 导入发货信息 + * @param array $data + * @param $merId + * @author Qinii + * @day 3/16/21 + */ + public function setWhereDeliveryStatus(array $arrary, $merId) + { + //读取excel + $data = SpreadsheetExcelService::instance()->_import($arrary['path'], $arrary['sql'], $arrary['where'], 4); + if (!$data) return; + $import_id = $arrary['import_id']; + Db::transaction(function () use ($data, $merId, $import_id) { + $result = []; + $num = 0; + $count = 0; + $status = 0; + foreach ($data as $datum) { + $value = []; + $ret = []; + if ($datum['where']) { + $count = $count + 1; + if (empty($datum['value']['delivery_id'])) { + $mark = '发货单号为空'; + } else { + $ret = $this->getSearch([]) + ->where('status', 0) + ->where('paid', 1) + ->where('order_type', 0) + ->where('mer_id', $merId) + ->where($datum['where']) + ->find(); + $mark = '数据有误或已发货'; + } + if ($ret) { + try { + $value = array_merge($datum['value'], ['status' => 1]); + $value['delivery_type'] = 1; + $this->delivery($ret['order_id'], $merId, $value); + + $status = 1; + $mark = ''; + + $num = $num + 1; + } catch (\Exception $exception) { + $mark = $exception->getMessage(); + } + } + $datum['where']['mark'] = $mark; + $datum['where']['mer_id'] = $merId; + $datum['where']['status'] = $status; + $datum['where']['import_id'] = $import_id; + $result[] = array_merge($datum['where'], $datum['value']); + } + } + // 记录入库操作 + if (!empty($result)) app()->make(StoreImportDeliveryRepository::class)->insertAll($result); + $_status = ($count == $num) ? 1 : (($num < 1) ? -1 : 10); + app()->make(StoreImportRepository::class)->update($import_id, ['count' => $count, 'success' => $num, 'status' => $_status]); + }); + if (file_exists($arrary['path'])) unlink($arrary['path']); + } + + /** + * TODO 根据订单查询相关联的自订单 + * @param $id + * @param $merId + * @return \think\Collection + * @author Qinii + * @day 2023/2/22 + */ + public function childrenList($id,$merId) + { + $data = $this->dao->get($id); + $query = $this->dao->getSearch([])->with(['orderProduct'])->where('order_id','<>',$id); + if ($merId) $query->where('mer_id',$merId); + if ($data['main_id']) { + $query->where(function($query) use($data,$id){ + $query->where('main_id',$data['main_id'])->whereOr('order_id',$data['main_id']); + }); + } else { + $query->where('main_id',$id); + } + return $query->select(); + } +} diff --git a/app/common/repositories/store/order/StoreOrderSplitRepository.php b/app/common/repositories/store/order/StoreOrderSplitRepository.php new file mode 100644 index 00000000..7ff387f5 --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderSplitRepository.php @@ -0,0 +1,228 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\order; + +use app\common\dao\store\order\StoreOrderDao; +use app\common\model\store\order\StoreOrder; +use crmeb\services\LockService; +use think\exception\ValidateException; +use think\facade\Db; + +/** + * Class StoreOrderSplitRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2022/3/10 + * @mixin StoreOrderDao + */ +class StoreOrderSplitRepository extends StoreOrderRepository +{ + public function splitOrder(StoreOrder $order, array $rule, $service_id = 0, $type = null) + { + return app()->make(LockService::class)->exec('order.split.' . $order->order_id, function () use ($rule, $order,$service_id,$type) { + return $this->execSplitOrder($order, $rule, $service_id,$type); + }); + } + + public function execSplitOrder(StoreOrder $order, array $rule, $service_id = 0, $type = null) + { + if ($order['status'] != 0) { + throw new ValidateException('订单已发货'); + } + if ($order['activity_type'] == 2 && !$type) { + throw new ValidateException('预售订单不能拆单'); + } + return Db::transaction(function () use ($order, $rule,$service_id) { + $newOrderId = 0; + $newOrder = $order->getOrigin(); + $newOrder['total_num'] = 0; + $newOrder['total_price'] = 0; + $newOrder['total_postage'] = 0; + $newOrder['pay_price'] = 0; + $newOrder['pay_postage'] = 0; + $newOrder['extension_one'] = 0; + $newOrder['extension_two'] = 0; + $newOrder['coupon_price'] = 0; + $newOrder['platform_coupon_price'] = 0; + $newOrder['svip_discount'] = 0; + $newOrder['cost'] = 0; + $newOrder['integral_price'] = 0; + $newOrder['integral'] = 0; + $newOrder['give_integral'] = 0; + $newOrder['coupon_id'] = ''; + + $inserts = []; + + $flag = false; + + foreach ($order['orderProduct'] as $product) { + if (!isset($rule[$product['order_product_id']])) { + if ($product['refund_num'] > 0) { + $flag = true; + } + continue; + } + $num = (int)$rule[$product['order_product_id']]; + if ($num <= 0) { + throw new ValidateException('拆单数必须大于0'); + } + if ($num > $product['refund_num']) { + throw new ValidateException('商品超出最大拆单数'); + } + if ($num != $product['refund_num']) { + $flag = true; + } + } + + if (!$flag) { + return $flag; + //throw new ValidateException('商品不能全部拆单'); + } + + foreach ($order['orderProduct'] as $product) { + if (!isset($rule[$product['order_product_id']])) continue; + $num = (int)$rule[$product['order_product_id']]; + + $newProduct = $product->getOrigin(); + unset($newProduct['order_product_id'], $newProduct['create_time']); + $newProduct['order_id'] = &$newOrderId; + $newProduct['is_refund'] = 0; + $newProduct['is_reply'] = 0; + + if ($product['product_num'] == $num && !$product['is_refund']) { + $product->delete(); + } else { + $newProduct['product_num'] = $num; + $newProduct['refund_num'] = $num; + + if (!$product['refund_num'] && $product['is_refund'] == 2) { + $product['is_refund'] = 3; + } + + $newProduct['product_price'] = $product['product_price'] > 0 ? round(bcmul(bcdiv($product['product_price'], $product['product_num'], 3), $num, 3), 2) : 0; + $newProduct['total_price'] = $product['total_price'] > 0 ? round(bcmul(bcdiv($product['total_price'], $product['product_num'], 2), $num, 2), 2) : 0; + $newProduct['extension_one'] = $product['extension_one']; + $newProduct['extension_two'] = $product['extension_two']; + $newProduct['coupon_price'] = $product['coupon_price'] > 0 ? bcmul(bcdiv($product['coupon_price'], $product['product_num'], 2), $num, 2) : 0; + $newProduct['svip_discount'] = $product['svip_discount'] > 0 ? bcmul(bcdiv($product['svip_discount'], $product['product_num'], 2), $num, 2) : 0; + $newProduct['integral_price'] = $product['integral_price'] > 0 ? bcmul(bcdiv($product['integral_price'], $product['product_num'], 2), $num, 2) : 0; + $newProduct['platform_coupon_price'] = $product['platform_coupon_price'] > 0 ? bcmul(bcdiv($product['platform_coupon_price'], $product['product_num'], 2), $num, 2) : 0; + $newProduct['postage_price'] = $product['postage_price'] > 0 ? bcmul(bcdiv($product['postage_price'], $product['product_num'], 2), $num, 2) : 0; + $newProduct['integral_total'] = $product['integral_total'] > 0 ? floor(bcmul(bcdiv($product['integral_total'], $product['integral_total'], 2), $num, 0)) : 0; + + $product['product_price'] = $product['product_price'] > 0 ? bcsub($product['product_price'], $newProduct['product_price'], 2) : 0; + $product['total_price'] = $product['total_price'] > 0 ? bcsub($product['total_price'], $newProduct['total_price'], 2) : 0; + $product['coupon_price'] = $product['coupon_price'] > 0 ? bcsub($product['coupon_price'], $newProduct['coupon_price'], 2) : 0; + $product['svip_discount'] = $product['svip_discount'] > 0 ? bcsub($product['svip_discount'], $newProduct['svip_discount'], 2) : 0; + $product['integral_price'] = $product['integral_price'] > 0 ? bcsub($product['integral_price'], $newProduct['integral_price'], 2) : 0; + $product['platform_coupon_price'] = $product['platform_coupon_price'] > 0 ? bcsub($product['platform_coupon_price'], $newProduct['platform_coupon_price'], 2) : 0; + $product['postage_price'] = $product['postage_price'] > 0 ? bcsub($product['postage_price'], $newProduct['postage_price'], 2) : 0; + $product['integral_total'] = $product['integral_total'] > 0 ? bcsub($product['integral_total'], $newProduct['integral_total'], 0) : 0; + + $product['product_num'] -= $num; + $product['refund_num'] -= $num; + + $product->save(); + } + + $give_integral = $order['give_integral'] > 0 ? floor(bcmul(bcdiv($newProduct['product_price'], $order['pay_price'], 2), $order['give_integral'], 0)) : 0; + $extension_one = $newProduct['extension_one'] > 0 ? bcmul($newProduct['extension_one'], $num, 2) : 0; + $extension_two = $newProduct['extension_two'] > 0 ? bcmul($newProduct['extension_two'], $num, 2) : 0; + $order['total_num'] -= $newProduct['product_num']; + $order['total_price'] = $order['total_price'] > 0 ? bcsub($order['total_price'], $newProduct['total_price'], 2) : 0; + $order['total_postage'] = $order['total_postage'] > 0 ? bcsub($order['total_postage'], $newProduct['postage_price'], 2) : 0; + $order['pay_postage'] = $order['total_postage']; + $order['extension_one'] = $order['extension_one'] > 0 ? bcsub($order['extension_one'], $extension_one, 2) : 0; + $order['extension_two'] = $order['extension_two'] > 0 ? bcsub($order['extension_two'], $extension_two, 2) : 0; + $order['svip_discount'] = $order['svip_discount'] > 0 ? bcsub($order['svip_discount'], $newProduct['svip_discount'], 2) : 0; + $order['coupon_price'] = $order['coupon_price'] > 0 ? bcsub($order['coupon_price'], $newProduct['coupon_price'], 2) : 0; + $order['coupon_price'] = $order['platform_coupon_price'] > 0 ? bcsub($order['coupon_price'], $newProduct['platform_coupon_price'], 2) : $order['coupon_price']; + $order['platform_coupon_price'] = $order['platform_coupon_price'] > 0 ? bcsub($order['platform_coupon_price'], $newProduct['platform_coupon_price'], 2) : 0; + $order['cost'] = $order['cost'] > 0 ? bcsub($order['cost'], $newProduct['cost'], 2) : 0; + $order['integral_price'] = $order['integral_price'] > 0 ? bcsub($order['integral_price'], $newProduct['integral_price'], 2) : 0; + $order['integral'] = $order['integral'] > 0 ? bcsub($order['integral'], $newProduct['integral_total'], 2) : 0; + $order['give_integral'] = ($order['give_integral'] > 0 && $newProduct['total_price'] > 0) ? bcsub($order['give_integral'], $give_integral, 0) : 0; + $order['pay_price'] = $order['pay_price'] > 0 ? bcsub($order['pay_price'], $newProduct['product_price'], 2) : 0; + + $newOrder['total_num'] += $newProduct['product_num']; + $newOrder['total_price'] = bcadd($newOrder['total_price'], $newProduct['total_price'], 2); + $newOrder['total_postage'] = bcadd($newOrder['total_postage'], $newProduct['postage_price'], 2); + $newOrder['pay_postage'] = $newOrder['total_postage']; + $newOrder['extension_one'] = bcadd($newOrder['extension_one'], $extension_one, 2); + $newOrder['extension_two'] = bcadd($newOrder['extension_two'], $extension_two, 2); + $newOrder['svip_discount'] = bcadd($newOrder['svip_discount'], $newProduct['svip_discount'], 2); + $newOrder['coupon_price'] = bcadd($newOrder['coupon_price'], $newProduct['coupon_price'], 2); + $newOrder['coupon_price'] = bcadd($newOrder['coupon_price'], $newProduct['platform_coupon_price'], 2); + $newOrder['platform_coupon_price'] = bcadd($newOrder['platform_coupon_price'], $newProduct['platform_coupon_price'], 2); + $newOrder['cost'] = bcadd($newOrder['cost'], $newProduct['cost'], 2); + $newOrder['integral_price'] = bcadd($newOrder['integral_price'], $newProduct['integral_price'], 2); + $newOrder['integral'] = bcadd($newOrder['integral'], $newProduct['integral_total'], 2); + $newOrder['give_integral'] = bcadd($newOrder['give_integral'], $give_integral, 2); + $newOrder['pay_price'] = bcadd($newOrder['pay_price'], $newProduct['product_price'], 2); + + $inserts[] = $newProduct; + } + + if (!count($inserts)) { + throw new ValidateException('请选择需拆出的商品'); + } + + $newOrder['pay_price'] = bcadd($newOrder['pay_price'], $newOrder['pay_postage'], 2); + $order['pay_price'] = bcsub($order['pay_price'], $newOrder['pay_postage'], 2); + $newOrder['order_sn'] = explode('-', $newOrder['order_sn'])[0] . ('-' . ($this->getSearch([])->where('main_id', $order['order_id'])->count() + 1)); + $newOrder['main_id'] = $order['main_id'] ?: $order['order_id']; + if ($newOrder['verify_code']) { + $newOrder['verify_code'] = $this->verifyCode(); + } + unset($newOrder['order_id']); + $newOrder = $this->create($newOrder); + $newOrderId = $newOrder['order_id']; + app()->make(StoreOrderProductRepository::class)->insertAll($inserts); + + $flag = true; + foreach ($order['orderProduct'] as $product) { + $flag = $flag && $product['is_refund'] == 3; + } + if ($flag) { + $order['status'] = -1; + } + $order->save(); + if ($flag) { + $this->orderRefundAllAfter($order); + } + $statusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '生成子订单:'.$newOrder->order_sn, + 'change_type' => $statusRepository::ORDER_STATUS_SPLIT, + ]; + $newOrderStatus = [ + 'order_id' => $newOrder->order_id, + 'order_sn' => $newOrder->order_sn, + 'type' => $statusRepository::TYPE_ORDER, + 'change_message' => '生成子订单', + 'change_type' => $statusRepository::ORDER_STATUS_SPLIT, + ]; + + if ($service_id) { + $statusRepository->createServiceLog($service_id,$orderStatus); + $statusRepository->createServiceLog($service_id,$newOrderStatus); + } else { + $statusRepository->createAdminLog($orderStatus); + $statusRepository->createAdminLog($newOrderStatus); + } + return $newOrder; + }); + } +} diff --git a/app/common/repositories/store/order/StoreOrderStatusRepository.php b/app/common/repositories/store/order/StoreOrderStatusRepository.php new file mode 100644 index 00000000..72294d6a --- /dev/null +++ b/app/common/repositories/store/order/StoreOrderStatusRepository.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + +use app\common\dao\store\order\StoreOrderStatusDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\store\service\StoreServiceUserRepository; + +/** + * Class StoreOrderStatusRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/11 + * @mixin StoreOrderStatusDao + */ +class StoreOrderStatusRepository extends BaseRepository +{ + //订单日志 + public const TYPE_ORDER = 'order'; + //退款单日志 + public const TYPE_REFUND = 'refund'; + //商品日志 +// public const TYPE_PRODUCT = 'product'; + + //操作者类型 + public const U_TYPE_SYSTEM = 0; + public const U_TYPE_USER = 1; + public const U_TYPE_ADMIN = 2; + public const U_TYPE_MERCHANT = 3; + public const U_TYPE_SERVICE = 4; + + //订单变动类型 + //取消 + const ORDER_STATUS_CANCEL = 'cancel'; + //改价 + const ORDER_STATUS_CHANGE = 'change'; + //创建 + const ORDER_STATUS_CREATE = 'create'; + //删除 + const ORDER_STATUS_DELETE = 'delete'; + //收货 + const ORDER_STATUS_TAKE = 'take'; + //拆单 + const ORDER_STATUS_SPLIT = 'split'; + //完成 + const ORDER_STATUS_OVER = 'over'; + const ORDER_STATUS_AUTO_OVER = 'auto_over'; + //预售订单 + const ORDER_STATUS_PRESELL= 'presell'; + const ORDER_STATUS_PRESELL_CLOSE = 'presell_close'; + //全部退款 + const ORDER_STATUS_REFUND_ALL = 'refund_all'; + //支付成功 + const ORDER_STATUS_PAY_SUCCCESS = 'pay_success'; + //拼图成功 + const ORDER_STATUS_GROUP_SUCCESS = 'group_success'; + //申请退款 + const CHANGE_REFUND_CREATGE = 'refund_create'; + //已发货 + const CHANGE_BACK_GOODS = 'back_goods'; + //退款申请已通过 + const CHANGE_REFUND_AGREE = 'refund_agree'; + //退款成功 + const CHANGE_REFUND_PRICE = 'refund_price'; + //订单退款已拒绝 + const CHANGE_REFUND_REFUSE = 'refund_refuse'; + //用户取消退款 + const CHANGE_REFUND_CANCEL = 'refund_cancel'; + + /* + 2 => '待取货', + 3 => '配送中', + 4 => '已完成', + -1 => '已取消', + 9 => '物品返回中', + 10 => '物品返回完成', + 100 => '骑士到店', + */ + const ORDER_DELIVERY_COURIER = 'delivery_0'; + const ORDER_DELIVERY_SELF = 'delivery_1'; + const ORDER_DELIVERY_NOTHING = 'delivery_2'; + const ORDER_DELIVERY_CITY = 'delivery_5'; + const ORDER_DELIVERY_CITY_CANCEL = 'delivery_5_-1'; + const ORDER_DELIVERY_CITY_ARRIVE = 'delivery_5_100'; + const ORDER_DELIVERY_CITY_WAITING = 'delivery_5_2'; + const ORDER_DELIVERY_CITY_ING = 'delivery_5_3'; + const ORDER_DELIVERY_CITY_OVER = 'delivery_5_4'; + const ORDER_DELIVERY_CITY_REFUND = 'delivery_5_10'; + const ORDER_DELIVERY_CITY_REFUNDING = 'delivery_5_9'; + + + /** + * StoreOrderStatusRepository constructor. + * @param StoreOrderStatusDao $dao + */ + public function __construct(StoreOrderStatusDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $order_id + * @param $change_type + * @param $change_message + * @return \app\common\dao\BaseDao|\think\Model + * @author xaboy + * @day 2020/6/11 + */ + public function status($order_id, $change_type, $change_message) + { + return $this->dao->create(compact('order_id', 'change_message', 'change_type')); + } + + public function search($where,$page, $limit) + { + $query = $this->dao->search($where)->order('change_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + public function createAdminLog(array $data) + { + $request = request(); + $data['user_type'] = $request->userType(); + $data['uid'] = $request->adminId(); + $data['nickname'] = $request->adminInfo()->real_name; + return $this->dao->create($data); + } + + public function createServiceLog($service_id, array $data) + { + $service = app()->make(StoreServiceRepository::class)->getWhere(['service_id' => $service_id]); + $data['user_type'] = self::U_TYPE_SERVICE; + $data['uid'] = $service_id; + $data['nickname'] = $service->nickname; + return $this->dao->create($data); + } + + public function createUserLog(array $data) + { + $data['user_type'] = self::U_TYPE_USER; + $data['uid'] = request()->uid(); + $data['nickname'] = request()->userInfo()->nickname; + return $this->dao->create($data); + } + + public function createSysLog(array $data) + { + $data['user_type'] = self::U_TYPE_SYSTEM; + $data['uid'] = 0; + $data['nickname'] = '系统'; + return $this->dao->create($data); + } + + public function batchCreateLog($data) + { + if(!empty($data)) { + return $this->dao->insertAll($data); + } + } +} diff --git a/app/common/repositories/store/order/StoreRefundOrderRepository.php b/app/common/repositories/store/order/StoreRefundOrderRepository.php new file mode 100644 index 00000000..523acd0e --- /dev/null +++ b/app/common/repositories/store/order/StoreRefundOrderRepository.php @@ -0,0 +1,1576 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreRefundOrderDao; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\order\StoreRefundOrder; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\AlipayService; +use crmeb\services\ExpressService; +use crmeb\services\MiniProgramService; +use crmeb\services\SwooleTaskService; +use crmeb\services\WechatService; +use Exception; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class StoreRefundOrderRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/12 + * @mixin StoreRefundOrderDao + */ +class StoreRefundOrderRepository extends BaseRepository +{ + + //状态 0:待审核 -1:审核未通过 1:待退货 2:待收货 3:已退款 -10 取消 + public const REFUND_STATUS_WAIT = 0; + public const REFUND_STATUS_BACK = 1; + public const REFUND_STATUS_THEGOODS = 2; + public const REFUND_STATUS_SUCCESS = 1; + public const REFUND_STATUS_REFUSED = -1; + public const REFUND_STATUS_CANCEL= -2; + + + /** + * StoreRefundOrderRepository constructor. + * @param StoreRefundOrderDao $dao + */ + public function __construct(StoreRefundOrderDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function userList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->setOption('field', [])->field('refund_order_id,refund_price,mer_id,status') + ->with(['merchant' => function ($query) { + $query->field('mer_name,mer_id'); + }, 'refundProduct.product'])->page($page, $limit)->select(); + return compact('list', 'count'); + } + + /** + * @param $id + * @param $uid + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function userDetail($id, $uid) + { + return $this->dao->search([ + 'id' => $id, + 'uid' => $uid, + 'is_del' => 0, + ])->with('refundProduct.product')->append(['auto_refund_time'])->find(); + } + + /** + * @param $id + * @param $uid + * @author xaboy + * @day 2020/6/17 + */ + public function userDel($id, $uid) + { + $ret = $this->dao->get($id); + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $ret->refund_order_id, + 'order_sn' => $ret->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => '创建退款单', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_DELETE, + ]; + Db::transaction(function () use ($uid, $id,$storeOrderStatusRepository,$orderStatus) { + $this->dao->userDel($uid, $id); + $storeOrderStatusRepository->createUserLog($orderStatus); + }); + } + + public function createRefund(StoreOrder $order, $refund_type = 1, $refund_message = '自动发起退款', $refund_postage = true) + { + $products = $order->orderProduct; + $ids = array_column($products->toArray(), 'order_product_id'); + $productRefundPrices = app()->make(StoreRefundProductRepository::class)->userRefundPrice($ids); + + $totalRefundPrice = 0; + $totalRefundNum = 0; + $total_extension_one = 0; + $total_extension_two = 0; + $totalIntegral = 0; + $totalPlatformRefundPrice = 0; + $totalPostage = 0; + $refundProduct = []; + $refund_order_id = 0; + foreach ($products as $product) { + $productRefundPrice = $productRefundPrices[$product['order_product_id']] ?? []; + if ($product['extension_one'] > 0) + $total_extension_one = bcadd($total_extension_one, bcmul($product['refund_num'], $product['extension_one'], 2), 2); + if ($product['extension_two'] > 0) + $total_extension_two = bcadd($total_extension_two, bcmul($product['refund_num'], $product['extension_two'], 2), 2); + $postagePrice = ($refund_postage || !$order->status || $order->status == 9) ? bcsub($product['postage_price'], $productRefundPrice['refund_postage'] ?? 0, 2) : 0; + $totalRefundNum += $product['refund_num']; + $refundPrice = 0; + //计算可退金额 + if ($product['product_price'] > 0) { + $refundPrice = bcsub($product['product_price'], bcsub($productRefundPrice['refund_price'] ?? 0, $productRefundPrice['refund_postage'] ?? 0, 2), 2); + } + $platform_refund_price = 0; + //计算退的平台优惠券金额 + if ($product['platform_coupon_price'] > 0) { + $platform_refund_price = bcsub($product['platform_coupon_price'], $productRefundPrice['platform_refund_price'] ?? 0, 2); + } + $integral = 0; + if ($product['integral'] > 0) { + $integral = bcsub($product['integral_total'], $productRefundPrice['refund_integral'] ?? 0, 0); + } + + $totalPostage = bcadd($totalPostage, $postagePrice, 2); + $totalRefundPrice = bcadd($totalRefundPrice, $refundPrice, 2); + $totalPlatformRefundPrice = bcadd($totalPlatformRefundPrice, $platform_refund_price, 2); + $totalIntegral = bcadd($totalIntegral, $integral, 2); + + $refundProduct[] = [ + 'refund_order_id' => &$refund_order_id, + 'refund_num' => $product['refund_num'], + 'order_product_id' => $product['order_product_id'], + 'platform_refund_price' => $platform_refund_price, + 'refund_integral' => $integral, + 'refund_price' => $refundPrice, + 'refund_postage' => $postagePrice, + ]; + } + $data = compact('refund_message', 'refund_type'); + $data['order_id'] = $products[0]['order_id']; + $data['uid'] = $products[0]['uid']; + $data['mer_id'] = $order['mer_id']; + $data['refund_order_sn'] = app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_REFUND); + $data['refund_num'] = $totalRefundNum; + $data['extension_one'] = $total_extension_one; + $data['extension_two'] = $total_extension_two; + $data['refund_price'] = bcadd($totalPostage, $totalRefundPrice, 2); + $data['integral'] = $totalIntegral; + $data['platform_refund_price'] = $totalPlatformRefundPrice; + $data['refund_postage'] = $totalPostage; + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + + return Db::transaction(function () use ($refundProduct, $data, $products, $order, &$refund_order_id,$storeOrderStatusRepository,$refund_message) { + event('refund.creates.before', compact('data')); + $refund = $this->dao->create($data); + $refund_order_id = $refund->refund_order_id; + foreach ($products as $product) { + $product->refund_num = 0; + $product->is_refund = 1; + $product->save(); + } + $orderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $order->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => $refund_message, + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CREATE, + ]; + $storeOrderStatusRepository->createSysLog($orderStatus); + app()->make(StoreRefundProductRepository::class)->insertAll($refundProduct); + return $refund; + }); + } + + public function getRefundsTotalPrice($order, $products) + { + $productRefundPrices = app()->make(StoreRefundProductRepository::class)->userRefundPrice($products->column('order_product_id')); + $totalPostage = 0; + $totalRefundPrice = 0; + foreach ($products as $product) { + $productRefundPrice = $productRefundPrices[$product['order_product_id']] ?? []; + $postagePrice = (!$order->status || $order->status == 9) ? bcsub($product['postage_price'], $productRefundPrice['refund_postage'] ?? 0, 2) : 0; + $refundPrice = 0; + if ($product['product_price'] > 0) { + $refundPrice = bcsub($product['product_price'], bcsub($productRefundPrice['refund_price'] ?? 0,$productRefundPrice['refund_postage']??0 ,2), 2); + } + $totalPostage = bcadd($totalPostage, $postagePrice, 2); + $totalRefundPrice = bcadd($totalRefundPrice, $refundPrice, 2); + } + return bcadd($totalPostage, $totalRefundPrice, 2); + } + + public function getRefundTotalPrice($order, $products) + { + $productRefundPrices = app()->make(StoreRefundProductRepository::class)->userRefundPrice($products->column('order_product_id')); + $product = $products[0]; + $productRefundPrice = $productRefundPrices[$product['order_product_id']] ?? []; + $total_refund_price = bcsub($product['product_price'], bcsub($productRefundPrice['refund_price'] ?? 0, $productRefundPrice['refund_postage'] ?? 0, 2), 2); + $postage_price = (!$order->status || $order->status == 9) ? bcsub($product['postage_price'], $productRefundPrice['refund_postage'] ?? 0, 2) : 0; + + return compact('total_refund_price', 'postage_price'); + } + + /** + * @param StoreOrder $order + * @param array $ids + * @param $uid + * @param array $data + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/17 + */ + public function refunds(StoreOrder $order, array $ids, $uid, array $data) + { + $orderId = $order->order_id; + $products = app()->make(StoreOrderProductRepository::class)->userRefundProducts($ids, $uid, $orderId); + if (!$products || count($ids) != count($products)) + throw new ValidateException('请选择正确的退款商品'); + $productRefundPrices = app()->make(StoreRefundProductRepository::class)->userRefundPrice($ids); + $totalRefundPrice = 0; + $totalRefundNum = 0; + $total_extension_one = 0; + $total_extension_two = 0; + $totalIntegral = 0; + $totalPlatformRefundPrice = 0; + $totalPostage = 0; + $refundProduct = []; + $refund_order_id = 0; + foreach ($products as $product) { + $productRefundPrice = $productRefundPrices[$product['order_product_id']] ?? []; + if ($product['extension_one'] > 0) + $total_extension_one = bcadd($total_extension_one, bcmul($product['refund_num'], $product['extension_one'], 2), 2); + if ($product['extension_two'] > 0) + $total_extension_two = bcadd($total_extension_two, bcmul($product['refund_num'], $product['extension_two'], 2), 2); + $postagePrice = (!$order->status || $order->status == 9) ? bcsub($product['postage_price'], $productRefundPrice['refund_postage'] ?? 0, 2) : 0; + $totalRefundNum += $product['refund_num']; + $refundPrice = 0; + //计算可退金额 + if ($product['product_price'] > 0) { + $refundPrice = bcsub($product['product_price'], bcsub($productRefundPrice['refund_price'] ?? 0, $productRefundPrice['refund_postage'] ?? 0, 2), 2); + } + $platform_refund_price = 0; + //计算退的平台优惠券金额 + if ($product['platform_coupon_price'] > 0) { + $platform_refund_price = bcsub($product['platform_coupon_price'], $productRefundPrice['platform_refund_price'] ?? 0, 2); + } + $integral = 0; + if ($product['integral'] > 0) { + $integral = bcsub($product['integral_total'], $productRefundPrice['refund_integral'] ?? 0, 0); + } + + $totalPostage = bcadd($totalPostage, $postagePrice, 2); + $totalRefundPrice = bcadd($totalRefundPrice, $refundPrice, 2); + $totalPlatformRefundPrice = bcadd($totalPlatformRefundPrice, $platform_refund_price, 2); + $totalIntegral = bcadd($totalIntegral, $integral, 2); + + $refundProduct[] = [ + 'refund_order_id' => &$refund_order_id, + 'refund_num' => $product['refund_num'], + 'order_product_id' => $product['order_product_id'], + 'platform_refund_price' => $platform_refund_price, + 'refund_integral' => $integral, + 'refund_price' => $refundPrice, + 'refund_postage' => $postagePrice, + ]; + } + $data['order_id'] = $products[0]['order_id']; + $data['uid'] = $products[0]['uid']; + $data['mer_id'] = $order['mer_id']; + $data['refund_order_sn'] = app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_REFUND); + $data['refund_num'] = $totalRefundNum; + $data['extension_one'] = $total_extension_one; + $data['extension_two'] = $total_extension_two; + $data['refund_price'] = bcadd($totalPostage, $totalRefundPrice, 2); + $data['integral'] = $totalIntegral; + $data['platform_refund_price'] = $totalPlatformRefundPrice; + $data['refund_postage'] = $totalPostage; + + return Db::transaction(function () use ($refundProduct, $data, $products, $order, &$refund_order_id) { + event('refund.creates.before', compact('data')); + $refund = $this->dao->create($data); + $refund_order_id = $refund->refund_order_id; + foreach ($products as $product) { + $product->refund_num = 0; + $product->is_refund = 1; + $product->save(); + } + app()->make(StoreRefundProductRepository::class)->insertAll($refundProduct); + $this->applyRefundAfter($refund, $order); + return $refund; + }); + } + + public function applyRefundAfter($refund, $order) + { + event('refund.create', compact('refund', 'order')); + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $refund->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => '创建退款单', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CREATE, + ]; + $storeOrderStatusRepository->createUserLog($orderStatus); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '申请退款', + 'change_type' => $storeOrderStatusRepository::CHANGE_REFUND_CREATGE, + ]; + $storeOrderStatusRepository->createUserLog($orderStatus); + Queue::push(SendSmsJob::class, ['tempId' => 'ADMIN_RETURN_GOODS_CODE', 'id' => $refund->refund_order_id]); + SwooleTaskService::merchant('notice', [ + 'type' => 'new_refund_order', + 'data' => [ + 'title' => '新退款单', + 'message' => '您有一个新的退款单', + 'id' => $refund->refund_order_id + ] + ], $order->mer_id); + } + + /** + * @param StoreOrder $order + * @param $productId + * @param $num + * @param $uid + * @param array $data + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/17 + */ + public function refund(StoreOrder $order, $productId, $num, $uid, array $data) + { + $orderId = $order->order_id; + //TODO 订单状态生成佣金 + $product = app()->make(StoreOrderProductRepository::class)->userRefundProducts([$productId], $uid, $orderId); + if (!$product) + throw new ValidateException('请选择正确的退款商品'); + $product = $product[0]; + if ($product['refund_num'] < $num) + throw new ValidateException('可退款商品不足' . floatval($num) . '件'); + $productRefundPrice = app()->make(StoreRefundProductRepository::class)->userRefundPrice([$productId])[$productId] ?? []; + + //计算可退运费 + $postagePrice = (!$order->status || $order->status == 9) ? bcsub($product['postage_price'], $productRefundPrice['refund_postage'] ?? 0, 2) : 0; + + $refundPrice = 0; + //计算可退金额 + if ($product['product_price'] > 0) { + if ($product['refund_num'] == $num) { + $refundPrice = bcsub($product['product_price'], bcsub($productRefundPrice['refund_price'] ?? 0, $productRefundPrice['refund_postage'] ?? 0, 2), 2); + } else { + $refundPrice = bcmul(bcdiv($product['product_price'], $product['product_num'], 2), $num, 2); + } + } + $totalRefundPrice = bcadd($refundPrice, $postagePrice, 2); + if ($totalRefundPrice < $data['refund_price']) + throw new ValidateException('最高可退款' . floatval($totalRefundPrice) . '元'); + + $data['refund_postage'] = 0; + + if ($data['refund_price'] > $refundPrice) { + $data['refund_postage'] = bcsub($data['refund_price'], $refundPrice, 2); + } + + $data['order_id'] = $product['order_id']; + + $platform_refund_price = 0; + //计算退的平台优惠券金额 + if ($product['platform_coupon_price'] > 0) { + if ($product['refund_num'] == $num) { + $platform_refund_price = bcsub($product['platform_coupon_price'], $productRefundPrice['platform_refund_price'] ?? 0, 2); + } else { + $platform_refund_price = bcmul(bcdiv($product['platform_coupon_price'], $product['product_num'], 2), $num, 2); + } + } + + $data['platform_refund_price'] = $platform_refund_price; + + $integral = 0; + if ($product['integral'] > 0) { + if ($product['refund_num'] == $num) { + $integral = bcsub($product['integral_total'], $productRefundPrice['refund_integral'] ?? 0, 0); + } else { + $integral = bcmul($product['integral'], $num, 0); + } + } + + $data['integral'] = $integral; + + $total_extension_one = 0; + $total_extension_two = 0; + if ($product['extension_one'] > 0) + $total_extension_one = bcmul($num, $product['extension_one'], 2); + if ($product['extension_two'] > 0) + $total_extension_two = bcmul($num, $product['extension_two'], 2); + + $data['uid'] = $product['uid']; + $data['mer_id'] = $order['mer_id']; + $data['refund_order_sn'] = app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_REFUND); + $data['refund_num'] = $num; + $data['extension_one'] = $total_extension_one; + $data['extension_two'] = $total_extension_two; + + return Db::transaction(function () use ($order, $data, $product, $productId, $num) { + event('refund.create.before', compact('data')); + $refund = $this->dao->create($data); + app()->make(StoreRefundProductRepository::class)->create([ + 'refund_num' => $num, + 'refund_order_id' => $refund->refund_order_id, + 'order_product_id' => $productId, + 'platform_refund_price' => $data['platform_refund_price'], + 'refund_price' => $data['refund_price'], + 'refund_integral' => $data['integral'], + 'refund_postage' => $data['refund_postage'], + ]); + $product->refund_num -= $num; + $product->is_refund = 1; + $product->save(); + $this->applyRefundAfter($refund, $order); + return $refund; + }); + } + + + + /** + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-06-12 + */ + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->search($where)->where('is_system_del', 0)->where('status','<>',-2)->with([ + 'order' => function ($query) { + $query->field('order_id,order_sn,activity_type,real_name,user_address,status,order_type,is_del'); + }, + 'refundProduct.product', + 'user' => function ($query) { + $query->field('uid,nickname,phone'); + }]) + ->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + $stat = [ + 'count' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id']]), + 'audit' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 0]), + 'refuse' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => -1]), + 'agree' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 1]), + 'backgood' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 2]), + 'end' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 3]), + ]; + return compact('count', 'list', 'stat'); + } + + public function getListByService(array $where, int $page, int $limit) + { + $query = $this->dao->search($where)->where('is_system_del', 0) + ->with([ + 'order' => function ($query) { + $query->field('order_id,order_sn,activity_type,real_name,user_address'); + }, + 'refundProduct.product', +// 'user' => function ($query) { +// $query->field('uid,nickname,phone'); +// } + ]) + ->order('create_time DESC,status ASC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function getAdminList(array $where, int $page, int $limit) + { + $query = $this->dao->search($where)->where('status','<>',-2)->with(['order' => function ($query) { + $query->field('order_id,order_sn,activity_type'); + }, 'refundProduct.product', 'user' => function ($query) { + $query->field('uid,nickname,phone'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + $stat = [ + 'count' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id']]), + 'audit' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 0]), + 'refuse' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => -1]), + 'agree' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 1]), + 'backgood' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 2]), + 'end' => $this->dao->getWhereCount(['is_system_del' => 0, 'mer_id' => $where['mer_id'], 'status' => 3]), + ]; + return compact('count', 'list', 'stat'); + } + + + /** + * TODO 总后台所有订单 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-06-25 + */ + public function getAllList(array $where, int $page, int $limit) + { + $query = $this->dao->search($where)->with(['order' => function ($query) { + $query->field('order_id,order_sn,activity_type'); + }, 'merchant' => function ($query) { + $query->field('mer_id,mer_name,is_trader'); + }, 'refundProduct.product', 'user' => function ($query) { + $query->field('uid,nickname,phone'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + $stat = [ + 'all' => $this->dao->getWhereCount([]), + 'audit' => $this->dao->getWhereCount(['status' => 0]), + 'refuse' => $this->dao->getWhereCount(['status' => -1]), + 'agree' => $this->dao->getWhereCount(['status' => 1]), + 'backgood' => $this->dao->getWhereCount(['status' => 2]), + 'end' => $this->dao->getWhereCount(['status' => 3]), + ]; + return compact('count', 'list', 'stat'); + } + + public function reconList($where, $page, $limit) + { + $ids = app()->make(MerchantReconciliationOrderRepository::class)->getIds($where); + $query = $this->dao->search([])->whereIn('refund_order_id', $ids)->with(['order' => function ($query) { + $query->field('order_id,order_sn,activity_type'); + }, 'refundProduct.product', 'user' => function ($query) { + $query->field('uid,nickname,phone'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + /** + * @param int $merId + * @param int $id + * @return bool + * @author Qinii + * @day 2020-06-12 + */ + public function getStatusExists(int $merId, int $id) + { + $where = [ + 'mer_id' => $merId, + 'refund_order_id' => $id, + 'status' => 0, + ]; + return $this->dao->getFieldExists($where); + } + + /** + * TODO 是否为收到退货状态 + * @param int $merId + * @param int $id + * @return bool + * @author Qinii + * @day 2020-06-13 + */ + public function getRefundPriceExists(int $merId, int $id) + { + $where = [ + 'mer_id' => $merId, + 'refund_order_id' => $id, + 'status' => 2, + ]; + return $this->dao->getFieldExists($where); + } + + public function getUserDelExists(int $merId, int $id) + { + $where = [ + 'mer_id' => $merId, + 'refund_order_id' => $id, + 'is_del' => 1, + ]; + return $this->dao->getFieldExists($where); + } + + /** + * @param int $merId + * @param int $id + * @return bool + * @author Qinii + * @day 2020-06-12 + */ + public function getExistsById(int $merId, int $id) + { + $where = [ + 'mer_id' => $merId, + 'refund_order_id' => $id, + ]; + return $this->dao->getFieldExists($where); + } + + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('merchantStoreRefundMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('mer_mark', '备注', $data['mer_mark']) + ]); + + return $form->setTitle('备注信息'); + } + + public function adminMarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantRefundOrderMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('admin_mark', '备注', $data['admin_mark']) + ]); + + return $form->setTitle('备注信息'); + } + + /** + * TODO 退款单已发货 + * @param $id + * @return Form + * @author Qinii + * @day 2020-06-13 + */ + + public function backGoods($uid, $id, $data) + { + $refund = $this->userDetail($id, $uid); + if (!$refund) + throw new ValidateException('退款单不存在'); + if ($refund->status != 1) + throw new ValidateException('退款单状态有误'); + $refund->status = 2; + $refund->status_time = date('Y-m-d H:i:s'); + + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $refund->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => '退款单退回商品已发货', + 'change_type' => $storeOrderStatusRepository::CHANGE_BACK_GOODS, + ]; + Db::transaction(function () use ($refund, $data, $id, $uid,$storeOrderStatusRepository,$orderStatus) { + $refund->save($data); + $storeOrderStatusRepository->createUserLog($orderStatus); + event('refund.backGoods',compact('uid','id','data')); + }); + Queue::push(SendSmsJob::class, [ + 'tempId' => 'ADMIN_DELIVERY_CODE', + 'id' => $id + ]); + } + + /** + * TODO + * @param $id + * @return Form + * @author Qinii + * @day 2020-06-13 + */ + public function statusForm($id) + { + $res = $this->getWhere(['refund_order_id' => $id]); + $form = Elm::createForm(Route::buildUrl('merchantStoreRefundOrderSwitchStatus', ['id' => $id])->build()); + + if ($res['refund_type'] == 1) { + $form->setRule([ + Elm::radio('status', '审核', -1)->setOptions([ + ['value' => 1, 'label' => '同意'], + ['value' => -1, 'label' => '拒绝'], + ])->control([ + [ + 'value' => -1, + 'rule' => [ + Elm::input('fail_message', '拒绝原因')->required() + ] + ], + ]), + ]); + } + if ($res['refund_type'] == 2) { + $form->setRule([ + Elm::radio('status', '审核', -1)->setOptions([ + ['value' => 1, 'label' => '同意'], + ['value' => -1, 'label' => '拒绝'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::input('mer_delivery_user', '收货人', merchantConfig($res['mer_id'], 'mer_refund_user'))->required(), + Elm::input('mer_delivery_address', '收货地址', merchantConfig($res['mer_id'], 'mer_refund_address'))->required(), + Elm::input('phone', '手机号', merchantConfig($res['mer_id'], 'set_phone'))->required(), + ] + ], + [ + 'value' => -1, + 'rule' => [ + Elm::input('fail_message', '拒绝原因')->required() + ] + ], + ]), + + ]); + } + + return $form->setTitle('退款审核'); + } + + /** + * TODO 拒绝退款 + * @param $id + * @param $data + * @author Qinii + * @day 2020-06-13 + */ + public function refuse($id, $data, $service_id = 0) + { + $refund = $this->getWhere(['refund_order_id' => $id], '*', ['refundProduct.product']); + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $refund->order_id, + 'order_sn' => $refund->order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '订单退款已拒绝:'.$refund->refund_order_sn, + 'change_type' => $storeOrderStatusRepository::CHANGE_REFUND_REFUSE, + ]; + $refundOrderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $refund->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => '订单退款已拒绝', + 'change_type' => $storeOrderStatusRepository::CHANGE_REFUND_REFUSE, + ]; + + Db::transaction(function () use ($id, $data,$refund,$service_id,$storeOrderStatusRepository,$orderStatus,$refundOrderStatus) { + + $data['status_time'] = date('Y-m-d H:i:s'); + $this->getProductRefundNumber($refund, -1); + $this->dao->update($id, $data); + + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + $storeOrderStatusRepository->createServiceLog($service_id,$refundOrderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + $storeOrderStatusRepository->createAdminLog($refundOrderStatus); + } + + event('refund.refuse',compact('id','refund')); + Queue::push(SendSmsJob::class, ['tempId' => 'REFUND_FAIL_CODE', 'id' => $id]); + }); + } + + + /** + * TODO 同意退款 + * @param $id + * @param $data + * @param $adminId + * @author Qinii + * @day 2020-06-13 + */ + public function agree(int $id, array $data, $service_id = 0) + { + + //已退款金额 + $_refund_price = $this->checkRefundPrice($id); + + $refund = $this->dao->getWhere(['refund_order_id' => $id], '*', ['refundProduct.product']); + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $refund->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + ]; + Db::transaction(function () use ($id, $data, $_refund_price, $refund,$storeOrderStatusRepository,$orderStatus,$service_id) { + $this->getProductRefundNumber($refund, 1); + if ($refund['refund_type'] == 1) { + //TODO 退款单同意退款 + $refund = $this->doRefundPrice($id, $_refund_price); + $data['status'] = 3; + $orderStatus['change_message'] = '退款成功'; + $orderStatus['change_type'] = $storeOrderStatusRepository::ORDER_STATUS_CREATE; + $this->refundAfter($refund); + } + if ($refund['refund_type'] == 2) { + $data['status'] = 1; + $orderStatus['change_message'] = '退款申请已通过,请将商品寄回'; + $orderStatus['change_type'] = $storeOrderStatusRepository::CHANGE_REFUND_AGREE; + Queue::push(SendSmsJob::class, ['tempId' => 'REFUND_SUCCESS_CODE', 'id' => $id]); + } + $data['status_time'] = date('Y-m-d H:i:s'); + $this->dao->update($id, $data); + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + event('refund.agree', compact('id', 'refund')); + }); + } + + /** + * @Author:Qinii + * @Date: 2020/8/29 + * @param $res + * @param $status + * @return bool + */ + public function getProductRefundNumber($res, $status, $after = false) + { + /** + * 1.同意退款 + * 1.1 仅退款 + * 1.1.1 是 , 如果退款数量 等于 购买数量 is_refund = 3 全退退款 不等于 is_refund = 2 部分退款 + * 1.1.2 否, is_refund = 1 退款中 + * 1.2 退款退货 is_refund = 1 + * + * 2. 拒绝退款 + * 2.1 如果退款数量 等于 购买数量 返还可退款数 is_refund = 0 + * 2.2 商品总数小于可退数量 返还可退数 以商品数为准 + * 2.3 是否存在其他图款单,是 ,退款中 ,否, 部分退款 + */ + $refundId = $this->getRefundCount($res->order_id, $res['refund_order_id']); + $make = app()->make(StoreRefundProductRepository::class); + foreach ($res['refundProduct'] as $item) { + $is_refund = $item->product->is_refund; + if ($status == 1) { //同意 + if ($after) { + $is_refund = ($item->refund_num == $item->product->product_num) ? 3 : 2; + } else { + if ($res['refund_type'] == 1) { + $is_refund = ($item->refund_num == $item->product->product_num) ? 3 : 2; + } + } + } else { //拒绝 + $refund_num = $item->refund_num + $item->product->refund_num; //返还可退款数 + if ($item->product->product_num == $refund_num) $is_refund = 0; + if ($item->product->product_num < $refund_num) $refund_num = $item->product->product_num; + $item->product->refund_num = $refund_num; + } + if (!empty($refundId)) { + $has = $make->getWhereCount([['refund_order_id', 'in', $refundId], ['order_product_id', '=', $item->product->order_product_id]]); + if ($has) $is_refund = 1; + } + $item->product->is_refund = $is_refund; + $item->product->save(); + } + return true; + } + + /** + * 获取订单存在的未处理完成的退款单 + * @Author:Qinii + * @Date: 2020/9/25 + * @param int $orderId + * @param int|null $refundOrderId + * @return array + */ + public function getRefundCount(int $orderId, ?int $refundOrderId) + { + $where = [ + 'type' => 1, + 'order_id' => $orderId, + ]; + + return $this->dao->search($where)->when($refundOrderId, function ($query) use ($refundOrderId) { + $query->where('refund_order_id', '<>', $refundOrderId); + })->column('refund_order_id'); + } + + public function refundGiveIntegral(StoreRefundOrder $refundOrder) + { + if ($refundOrder->refund_price > 0 && $refundOrder->order->pay_price > 0) { + $userBillRepository = app()->make(UserBillRepository::class); + $bill = $userBillRepository->getWhere(['category' => 'integral', 'type' => 'lock', 'link_id' => $refundOrder->order->group_order_id]); + if ($bill && $bill->status != 1) { + + if ($refundOrder->order->status == -1) { + $number = bcsub($bill->number, $userBillRepository->refundIntegral($refundOrder->order->group_order_id, $bill->uid), 0); + } else { + $number = bcmul(bcdiv($refundOrder['refund_price'], $refundOrder->order->pay_price, 3), $refundOrder->order->give_integral, 0); + } + if ($number <= 0) return; + + $userBillRepository->decBill($bill->uid, 'integral', 'refund_lock', [ + 'link_id' => $refundOrder->order->group_order_id, + 'status' => 1, + 'title' => '扣除赠送积分', + 'number' => $number, + 'mark' => '订单退款扣除赠送积分' . intval($number), + 'balance' => $refundOrder->user->integral + ]); + } + } + } + + /** + * @param StoreRefundOrder $refundOrder + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/17 + */ + public function descBrokerage(StoreRefundOrder $refundOrder) + { + $userBillRepository = app()->make(UserBillRepository::class); + $userRepository = app()->make(UserRepository::class); + if ($refundOrder['extension_one'] > 0) { + $bill = $userBillRepository->getWhere(['category' => 'brokerage', 'type' => 'order_one', 'link_id' => $refundOrder->order_id]); + $refundOrder->order->extension_one = bcsub($refundOrder->order->extension_one, $refundOrder['extension_one'], 2); + if ($bill && $bill->status != 1) { + $userRepository->incBrokerage($bill->uid, $refundOrder['extension_one'], '-'); + $userBillRepository->decBill($bill->uid, 'brokerage', 'refund_one', [ + 'link_id' => $refundOrder->order_id, + 'status' => 1, + 'title' => '用户退款', + 'number' => $refundOrder['extension_one'], + 'mark' => '用户退款扣除推广佣金' . floatval($refundOrder['extension_one']), + 'balance' => 0 + ]); + } + if (!$bill || $bill->status != 1) { + app()->make(FinancialRecordRepository::class)->inc([ + 'order_id' => $refundOrder->refund_order_id, + 'order_sn' => $refundOrder->refund_order_sn, + 'user_info' => $bill ? $userRepository->getUsername($bill->uid) : '退还一级佣金', + 'user_id' => $bill ? $bill->uid : 0, + 'type' => 1, + 'financial_type' => 'refund_brokerage_one', + 'number' => $refundOrder['extension_one'], + ], $refundOrder->mer_id); + } + } + if ($refundOrder['extension_two'] > 0) { + $bill = $userBillRepository->getWhere(['category' => 'brokerage', 'type' => 'order_two', 'link_id' => $refundOrder->order_id]); + $refundOrder->order->extension_two = bcsub($refundOrder->order->extension_two, $refundOrder['extension_two'], 2); + if ($bill && $bill->status != 1) { + $userRepository->incBrokerage($bill->uid, $refundOrder['extension_two'], '-'); + $userBillRepository->decBill($bill->uid, 'brokerage', 'refund_two', [ + 'link_id' => $refundOrder->order_id, + 'status' => 1, + 'title' => '用户退款', + 'number' => $refundOrder['extension_two'], + 'mark' => '用户退款扣除推广佣金' . floatval($refundOrder['extension_two']), + 'balance' => 0 + ]); + } + if (!$bill || $bill->status != 1) { + app()->make(FinancialRecordRepository::class)->inc([ + 'order_id' => $refundOrder->refund_order_id, + 'order_sn' => $refundOrder->refund_order_sn, + 'user_info' => $bill ? $userRepository->getUsername($bill->uid) : '退还二级佣金', + 'user_id' => $bill ? $bill->uid : 0, + 'type' => 1, + 'financial_type' => 'refund_brokerage_two', + 'number' => $refundOrder['extension_two'], + ], $refundOrder->mer_id); + } + } + $refundOrder->order->save(); + } + + /** + * //TODO 退款后 + * @param StoreRefundOrder $refundOrder + * @author xaboy + * @day 2020/6/17 + */ + public function refundAfter(StoreRefundOrder $refundOrder) + { + //返还库存 + $refundOrder->append(['refundProduct.product']); + $productRepository = app()->make(ProductRepository::class); + if ($refundOrder['refund_type'] == 2 || $refundOrder->order->status == 0 || $refundOrder->order->status == 9) { + foreach ($refundOrder->refundProduct as $item) { + $productRepository->orderProductIncStock($refundOrder->order, $item->product, $item->refund_num); + } + } + $refundAll = app()->make(StoreOrderRepository::class)->checkRefundStatusById($refundOrder['order_id'], $refundOrder['refund_order_id']); + if ($refundAll) { + $refundOrder->order->status = -1; + } + Queue::push(SendSmsJob::class, ['tempId' => 'REFUND_CONFORM_CODE', 'id' => $refundOrder->refund_order_id]); + $this->descBrokerage($refundOrder); + + //退回平台优惠 + if ($refundOrder->platform_refund_price > 0) { + if ($refundOrder->order->firstProfitsharing) { + $model = $refundOrder->order->firstProfitsharing; + $model->profitsharing_mer_price = bcsub($model->profitsharing_mer_price, $refundOrder->platform_refund_price, 2); + $model->save(); + } else { + app()->make(MerchantRepository::class)->subLockMoney($refundOrder->mer_id, 'order', $refundOrder->order->order_id, $refundOrder->platform_refund_price); + } + $isVipCoupon = app()->make(StoreGroupOrderRepository::class)->isVipCoupon($refundOrder->order->groupOrder); + app()->make(FinancialRecordRepository::class)->dec([ + 'order_id' => $refundOrder->refund_order_id, + 'order_sn' => $refundOrder->refund_order_sn, + 'user_info' => $refundOrder->user->nickname, + 'user_id' => $refundOrder->uid, + 'financial_type' => $isVipCoupon ? 'refund_svip_coupon' : 'refund_platform_coupon', + 'type' => 1, + 'number' => $refundOrder->platform_refund_price, + ], $refundOrder->mer_id); + } + + //退回积分 + if ($refundOrder->integral > 0) { + $make = app()->make(UserRepository::class); + $make->update($refundOrder->uid, ['integral' => Db::raw('integral+' . $refundOrder->integral)]); + $userIntegral = $make->get($refundOrder->uid)->integral; + $make1 = app()->make(UserBillRepository::class); + $make1->incBill($refundOrder->uid, 'integral', 'refund', [ + 'link_id' => $refundOrder->order_id, + 'status' => 1, + 'title' => '订单退款', + 'number' => $refundOrder->integral, + 'mark' => '订单退款,返还' . intval($refundOrder->integral) . '积分', + 'balance' => $userIntegral + ]); + $make1->incBill($refundOrder->uid, 'mer_integral', 'refund', [ + 'link_id' => $refundOrder->order_id, + 'status' => 1, + 'title' => '订单退款', + 'number' => $refundOrder->integral, + 'mark' => '订单退款,返还' . intval($refundOrder->integral) . '积分', + 'balance' => $userIntegral, + 'mer_id' => $refundOrder->mer_id + ]); + } + + //退还赠送积分 + $this->refundGiveIntegral($refundOrder); + + app()->make(FinancialRecordRepository::class)->dec([ + 'order_id' => $refundOrder->refund_order_id, + 'order_sn' => $refundOrder->refund_order_sn, + 'user_info' => $refundOrder->user->nickname, + 'user_id' => $refundOrder->uid, + 'financial_type' => 'refund_order', + 'type' => 1, + 'number' => $refundOrder->refund_price, + ], $refundOrder->mer_id); + } + + public function getRefundMerPrice(StoreRefundOrder $refundOrder, $refundPrice = null) + { + if ($refundPrice === null) { + $refundPrice = $refundOrder->refund_price; + $extension_one = $refundOrder['extension_one']; + $extension_two = $refundOrder['extension_two']; + } else { + $rate = bcdiv($refundPrice, $refundOrder->refund_price, 3); + $extension_one = $refundOrder['extension_one'] > 0 ? bcmul($rate, $refundOrder['extension_one'], 2) : 0; + $extension_two = $refundOrder['extension_two'] > 0 ? bcmul($rate, $refundOrder['extension_two'], 2) : 0; + } + $extension = bcadd($extension_one, $extension_two, 3); + $commission_rate = ($refundOrder->order->commission_rate / 100); + $_refundRate = 0; + if ($refundOrder->order->commission_rate > 0) { + $_refundRate = bcmul($commission_rate, bcsub($refundPrice, $extension, 2), 2); + } + return bcsub(bcsub($refundPrice, $extension, 2), $_refundRate, 2); + } + + + /** + * TODO 退款单同意退款退货 + * @param $id + * @param $admin + * @author Qinii + * @day 2020-06-13 + */ + public function adminRefund($id, $service_id = null) + { + $refund = $this->dao->getWhere(['refund_order_id' => $id], '*', ['refundProduct.product']); + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $refund->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => '退款成功', + 'change_type' => $storeOrderStatusRepository::CHANGE_REFUND_PRICE, + ]; + Db::transaction(function () use ($service_id, $id,$refund,$storeOrderStatusRepository,$orderStatus) { + $data['status'] = 3; + $data['status_time'] = date('Y-m-d H:i:s'); + $this->dao->update($id, $data); + if ($service_id) { + $storeOrderStatusRepository->createServiceLog($service_id,$orderStatus); + } else { + $storeOrderStatusRepository->createAdminLog($orderStatus); + } + $this->getProductRefundNumber($refund, 1, true); + $refund = $this->doRefundPrice($id, 0); + if ($refund) $this->refundAfter($refund); + }); + } + + /** + * TODO 退款操作 + * @param $id + * @param $adminId + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + * @day 2020-06-13 + */ + public function doRefundPrice($id, $refundPrice) + { + $res = $this->dao->getWhere(['refund_order_id' => $id], "*", ['order']); + if (!$res->order) { + $res->fail_message = '订单信息不全'; + $res->sataus = -1; + $res->save(); + return; + } + if ($res->refund_price <= 0) return $res; + + if ($res->order->activity_type == 2) { + $data = $this->getFinalOrder($res, $refundPrice); + } else { + if ($res->order->groupOrder->is_combine) { + $data[] = [ + 'type' => 10, + 'id' => $res->order->order_id, + 'sn' => $res->order->groupOrder->group_order_sn, + 'data' => $res->getCombineRefundParams() + ]; + } else { + $data[] = [ + 'type' => $res->order->pay_type, + 'id' => $res->order->order_id, + 'sn' => $res->order->groupOrder->group_order_sn, + 'data' => [ + 'refund_id' => $res->refund_order_sn, + 'pay_price' => $res->order->groupOrder->pay_price, + 'refund_price' => $res->refund_price, + 'refund_message' => $res->refund_message, + 'open_id' => $res->user->wechat->routine_openid ?? null, + 'transaction_id' => $res->order->transaction_id, + ] + ]; + } + } + $refundPriceAll = 0; + $refundRate = 0; + $totalExtension = bcadd($res['extension_one'], $res['extension_two'], 2); + $_extension = 0; + $i = count($data); + foreach ($data as $datum => $item) { + if ($item['data']['pay_price'] > 0 && $item['data']['refund_price'] > 0) { + //0余额 1微信 2小程序 + $refundPrice = $this->getRefundMerPrice($res, $item['data']['refund_price']); + + if ($res->order->commission_rate > 0) { + $commission_rate = ($res->order->commission_rate / 100); + + if ($datum == ($i - 1)) { + $extension = bcsub($totalExtension, $_extension, 2); + } else { + $extension = bcmul(bcdiv($item['data']['refund_price'], $res->refund_price, 2), $totalExtension, 2); + $_extension = bcadd($_extension, $extension, 2); + } + $_refundRate = bcmul($commission_rate, bcsub($item['data']['refund_price'], $extension, 2), 2); + $refundRate = bcadd($refundRate, $_refundRate, 2); + } + $refundPriceAll = bcadd($refundPriceAll, $refundPrice, 2); + + try { + $orderType = (isset($item['presell']) && $item['presell']) ? 'presell' : 'order'; + if ($item['type'] == 0) { + $this->refundBill($item, $res->uid, $id); + app()->make(MerchantRepository::class)->subLockMoney($res->mer_id, $orderType, $item['id'], $refundPrice); + } else { + if ($item['type'] == 10) $server = WechatService::create()->combinePay(); + if (in_array($item['type'], [2])) $server = MiniProgramService::create(); + if (in_array($item['type'], [4, 5])) $server = AlipayService::create(); + if (in_array($item['type'], [1, 3, 6])) $server = WechatService::create(); + $server->payOrderRefund($item['sn'], $item['data']); + if ($item['type'] == 10) { + $make = app()->make(StoreOrderProfitsharingRepository::class); + if ($orderType === 'presell') { + $make->refundPresallPrice($res, $item['data']['refund_price'], $refundPrice); + } else { + $make->refundPrice($res, $item['data']['refund_price'], $refundPrice); + } + } else { + app()->make(MerchantRepository::class)->subLockMoney($res->mer_id, $orderType, $item['id'], $refundPrice); + } + } + } catch (Exception $e) { + throw new ValidateException($e->getMessage()); + } + } + } + + app()->make(FinancialRecordRepository::class)->inc([ + 'order_id' => $res->refund_order_id, + 'order_sn' => $res->refund_order_sn, + 'user_info' => $res->user->nickname, + 'user_id' => $res->uid, + 'financial_type' => 'refund_true', + 'number' => $refundPriceAll, + 'type' => 1, + ], $res->mer_id); + + app()->make(FinancialRecordRepository::class)->inc([ + 'order_id' => $res->refund_order_id, + 'order_sn' => $res->refund_order_sn, + 'user_info' => $res->user->nickname, + 'user_id' => $res->uid, + 'type' => 1, + 'financial_type' => 'refund_charge', + 'number' => $refundRate, + ], $res->mer_id); + return $res; + } + + + /** + * TODO 余额退款 + * @param $data + * @param $uid + * @param $id + * @author Qinii + * @day 2020-11-03 + */ + public function refundBill($data, $uid, $id) + { + try { + $user = app()->make(UserRepository::class)->get($uid); + $balance = bcadd($user->now_money, $data['data']['refund_price'], 2); + $user->save(['now_money' => $balance]); + + app()->make(UserBillRepository::class) + ->incBill($uid, 'now_money', 'refund', [ + 'link_id' => $id, + 'status' => 1, + 'title' => '退款增加余额', + 'number' => $data['data']['refund_price'], + 'mark' => '退款增加' . floatval($data['data']['refund_price']) . '余额,退款订单号:' . $data['sn'], + 'balance' => $balance + ]); + } catch (Exception $e) { + throw new ValidateException('余额退款失败'); + } + } + + public function express($ordertId) + { + $refundOrder = $this->dao->get($ordertId); + return ExpressService::express($refundOrder->delivery_id, $refundOrder->delivery_type, $refundOrder->delivery_phone); + } + + /** + * 退款金额是否超过可退金额 + * @Author:Qinii + * @Date: 2020/9/2 + * @param int $refundId + * @return bool + */ + public function checkRefundPrice(int $refundId) + { + $refund = $this->dao->get($refundId); + if($refund['refund_price'] < 0) throw new ValidateException('退款金额不能小于0'); + $order = app()->make(StoreOrderRepository::class)->get($refund['order_id']); + $pay_price = $order['pay_price']; + + //预售 + if ($order['activity_type'] == 2) { + $final_price = app()->make(PresellOrderRepository::class)->getSearch(['order_id' => $refund['order_id']])->value('pay_price'); + $pay_price = bcadd($pay_price, ($final_price ? $final_price : 0), 2); + } + + //已退金额 + $refund_price = $this->dao->refundPirceByOrder([$refund['order_id']]); + + if (bccomp(bcsub($pay_price, $refund_price, 2), $refund['refund_price'], 2) == -1) + throw new ValidateException('退款金额超出订单可退金额'); + + return $refund_price; + } + + public function getFinalOrder(StoreRefundOrder $res, $refundPrice) + { + /** + * 1 已退款金额大于定金订单 直接退尾款订单 + * 2 已退款金额小于定金订单 + * 2.1 当前退款金额 大于剩余定金金额 退款两次 + * 2.2 当前退款金额 小于等于剩余定金金额 退款一次 + */ + $result = []; + if (bccomp($res->order->pay_price, $refundPrice, 2) == -1) { + $final = app()->make(PresellOrderRepository::class)->getSearch(['order_id' => $res['order_id']])->find(); + if ($final->is_combine) { + $result[] = [ + 'type' => 10, + 'id' => $final->presell_order_id, + 'sn' => $final['presell_order_sn'], + 'presell' => 1, + 'data' => [ + 'sub_mchid' => $res->merchant->sub_mchid, + 'order_sn' => $res->order->order_sn, + 'refund_order_sn' => $res->refund_order_sn, + 'pay_price' => $res->order->pay_price, + 'refund_price' => $res->refund_price, + ] + ]; + } else { + $result[] = [ + 'type' => $final->is_combine ? 10 : $final->pay_type, + 'id' => $final->presell_order_id, + 'sn' => $final['presell_order_sn'], + 'data' => [ + 'refund_id' => $res->refund_order_sn, + 'pay_price' => $res->order->pay_price, + 'refund_price' => $res->refund_price + ] + ]; + } + } else { + //定金金额 - 已退款金额 = 剩余定金 + $sub_order_price = bcsub($res->order->pay_price, $refundPrice, 2); + //剩余定金于此次退款金额对比 + $sub_comp = bccomp($sub_order_price, $res->refund_price, 2); + //定金订单 + if ($sub_comp == 1 || $sub_comp == 0) { + if ($res->order->groupOrder->is_combine) { + $result[] = [ + 'type' => 10, + 'id' => $res->order->order_id, + 'sn' => $res->order->order_sn, + 'data' => $res->getCombineRefundParams() + ]; + } else { + $result[] = [ + 'type' => $res->order->pay_type, + 'id' => $res->order->order_id, + 'sn' => $res->order->groupOrder->group_order_sn, + 'data' => [ + 'refund_id' => $res->refund_order_sn, + 'pay_price' => $res->order->pay_price, + 'refund_price' => $res->refund_price + ] + ]; + } + } + + //两个分别计算 + if ($sub_comp == -1) { + if ($res->order->groupOrder->is_combine) { + $data = $res->getCombineRefundParams(); + $data['refund_price'] = $sub_order_price; + $result[] = [ + 'type' => 10, + 'id' => $res->order->order_id, + 'sn' => $res->order->order_sn, + 'data' => $data + ]; + } else { + $result[] = [ + 'type' => $res->order->pay_type, + 'sn' => $res->order->groupOrder->group_order_sn, + 'id' => $res->order->order_id, + 'data' => [ + 'refund_id' => $res->refund_order_sn, + 'pay_price' => $res->order->pay_price, + 'refund_price' => $sub_order_price + ] + ]; + } + + $final = app()->make(PresellOrderRepository::class)->getSearch(['order_id' => $res['order_id']])->find(); + if ($final->is_combine) { + $result[] = [ + 'type' => 10, + 'id' => $final->presell_order_id, + 'sn' => $final['presell_order_sn'], + 'presell' => 1, + 'data' => [ + 'sub_mchid' => $res->merchant->sub_mchid, + 'order_sn' => $final['presell_order_sn'], + 'refund_order_sn' => $res->refund_order_sn . '1', + 'pay_price' => $final->pay_price, + 'refund_price' => bcsub($res->refund_price, $sub_order_price, 2) + ] + ]; + } else { + $result[] = [ + 'type' => $final->is_combine ? 10 : $final->pay_type, + 'id' => $final->presell_order_id, + 'sn' => $final['presell_order_sn'] . '1', + 'data' => [ + 'refund_id' => $final['presell_order_sn'], + 'pay_price' => $final->pay_price, + 'refund_price' => bcsub($res->refund_price, $sub_order_price, 2) + ] + ]; + } + } + } + return $result; + } + + /** + * TODO 订单自动退款 + * @param $id + * @param int $refund_type + * @param string $message + * @author Qinii + * @day 1/15/21 + */ + public function autoRefundOrder($id, $refund_type = 1, $message = '') + { + $order = app()->make(StoreOrderRepository::class)->get($id); + if (!$order) return; + if ($order->status == -1) return; + if ($order['paid'] == 1) { + //已支付 + $refund_make = app()->make(StoreRefundOrderRepository::class); + $refund = $refund_make->createRefund($order, $refund_type, $message); + $refund_make->agree($refund[$refund_make->getPk()], [], 0); + } else { + if (!$order->is_del) { + app()->make(StoreOrderRepository::class)->delOrder($order, $message); + } + } + } + + + /** + * TODO 移动端客服退款信息 + * @param int $id + * @param int $merId + * @return array + * @author Qinii + * @day 6/2/22 + */ + public function serverRefundDetail(int $id, int $merId) + { + if (!$this->dao->merHas($merId, $id)) { + throw new ValidateException('数据不存在'); + } + $data = $this->dao->getWhere(['mer_id' => $merId, $this->dao->getPk() => $id],'*', ['refundProduct.product','order']); + $total_price = $total_postage = 0.00; + foreach ($data['refundProduct'] as $itme) { + $total_price = bcadd($total_price , bcmul($itme['refund_num'] , $itme['product']['product_price'],2),2); + $total_postage = bcadd($total_postage , $itme['product']['postage_price'], 2); + } + $data['total_num'] = $data['order']['total_num']; + unset($data['refundProduct'],$data['order']); + $data['total_price'] = $total_price; + $data['total_postage'] = $total_postage; + $refund_info = null; + if ($data['refund_type'] == 2) { + $refund_info['mer_delivery_user'] = merchantConfig($merId,'mer_refund_user'); + $refund_info['mer_delivery_address'] = merchantConfig($merId,'mer_refund_address'); + $refund_info['phone'] = merchantConfig($merId,'set_phone'); + } + $data['refund_info'] = $refund_info; + + return $data; + } + + /** + * TODO 用户取消退款单申请 + * @param int $id + * @param $user + * @author Qinii + * @day 2022/11/18 + */ + public function cancel(int $id, $user) + { + //状态 0:待审核 -1:审核未通过 1:待退货 2:待收货 3:已退款 + $refund = $this->dao->getWhere(['refund_order_id' => $id, 'uid' => $user->uid],'*', ['refundProduct.product']); + if (!$refund) throw new ValidateException('数据不存在'); + if (!in_array($refund['status'],[self::REFUND_STATUS_WAIT, self::REFUND_STATUS_BACK])) + throw new ValidateException('当前状态不可取消'); + + //退款订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $refund->refund_order_id, + 'order_sn' => $refund->refund_order_sn, + 'type' => $storeOrderStatusRepository::TYPE_REFUND, + 'change_message' => '用户取消退款', + 'change_type' => $storeOrderStatusRepository::CHANGE_REFUND_CANCEL, + ]; + + Db::transaction(function () use ($id, $refund,$storeOrderStatusRepository,$orderStatus) { + $this->getProductRefundNumber($refund, -1); + $this->dao->update($id, ['status_time' => date('Y-m-d H:i:s'), 'status' => self::REFUND_STATUS_CANCEL]); + $storeOrderStatusRepository->createUserLog($orderStatus); + }); + } +} diff --git a/app/common/repositories/store/order/StoreRefundProductRepository.php b/app/common/repositories/store/order/StoreRefundProductRepository.php new file mode 100644 index 00000000..1c9da8f9 --- /dev/null +++ b/app/common/repositories/store/order/StoreRefundProductRepository.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreRefundProductDao; +use app\common\repositories\BaseRepository; + +/** + * Class StoreRefundProductRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/12 + * @mixin StoreRefundProductDao + */ +class StoreRefundProductRepository extends BaseRepository +{ + /** + * StoreRefundProductRepository constructor. + * @param StoreRefundProductDao $dao + */ + public function __construct(StoreRefundProductDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/order/StoreRefundStatusRepository.php b/app/common/repositories/store/order/StoreRefundStatusRepository.php new file mode 100644 index 00000000..899f58f7 --- /dev/null +++ b/app/common/repositories/store/order/StoreRefundStatusRepository.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\order; + + +use app\common\dao\store\order\StoreOrderStatusDao; +use app\common\dao\store\order\StoreRefundStatusDao; +use app\common\repositories\BaseRepository; + +/** + * Class StoreRefundStatusRepository + * @package app\common\repositories\store\order + * @author xaboy + * @day 2020/6/12 + */ +class StoreRefundStatusRepository extends BaseRepository +{ + //已发货 + const CHANGE_BACK_GOODS = 'back_goods'; + //创建退款单 + const CHANGE_CREATE = 'create'; + //删除记录 + const CHANGE_DELETE = 'delete'; + //退款申请已通过 + const CHANGE_REFUND_AGREE = 'refund_agree'; + //退款成功 + const CHANGE_REFUND_PRICE = 'refund_price'; + //订单退款已拒绝 + const CHANGE_REFUND_REFUSE = 'refund_refuse'; + //用户取消退款 + const CHANGE_REFUND_CANCEL = 'refund_cancel'; + /** + * StoreRefundStatusRepository constructor. + * @param StoreRefundStatusDao $dao + */ + public function __construct(StoreRefundStatusDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $refund_order_id + * @param $change_type + * @param $change_message + * @return \app\common\dao\BaseDao|\think\Model + * @author xaboy + * @day 2020/6/12 + */ + public function status($refund_order_id, $change_type, $change_message) + { + return $this->dao->create(compact('refund_order_id', 'change_message', 'change_type')); + } + + public function search($id, $page, $limit) + { + $query = $this->dao->search($id); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/store/parameter/ParameterRepository.php b/app/common/repositories/store/parameter/ParameterRepository.php new file mode 100644 index 00000000..0519758f --- /dev/null +++ b/app/common/repositories/store/parameter/ParameterRepository.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\parameter; + +use app\common\dao\store\parameter\ParameterDao; +use app\common\repositories\BaseRepository; + +class ParameterRepository extends BaseRepository +{ + /** + * @var ParameterDao + */ + protected $dao; + + + /** + * ParameterRepository constructor. + * @param ParameterDao $dao + */ + public function __construct(ParameterDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 更新或者添加参数 + * @param $id + * @param $merId + * @param $data + * @author Qinii + * @day 2022/11/22 + */ + public function createOrUpdate($id, $merId, $data) + { + foreach ($data as $datum) { + if (isset($datum['parameter_id']) && $datum['parameter_id']) { + $update = [ + 'name' => $datum['name'], + 'value' => $datum['value'], + 'sort' => $datum['sort'], + ]; + $this->dao->update($datum['parameter_id'], $update); + $changeKey[] = $datum['parameter_id']; + } else { + $create[] = [ + 'template_id' => $id, + 'name' => $datum['name'], + 'value' => $datum['value'], + 'sort' => $datum['sort'], + 'mer_id' => $merId + ]; + } + } + if (!empty($create)) $this->dao->insertAll($create); + } + + /** + * TODO 更新差异的删除操作 + * @param int $id + * @param array $params + * @author Qinii + * @day 2022/11/22 + */ + public function diffDelete(int $id, array $params) + { + $paramsKey = array_unique(array_column($params,'parameter_id')); + $this->dao->getSearch([])->where('template_id',$id)->whereNotIn('parameter_id',$paramsKey)->delete(); + } +} + diff --git a/app/common/repositories/store/parameter/ParameterTemplateRepository.php b/app/common/repositories/store/parameter/ParameterTemplateRepository.php new file mode 100644 index 00000000..2f9dda4b --- /dev/null +++ b/app/common/repositories/store/parameter/ParameterTemplateRepository.php @@ -0,0 +1,175 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\parameter; + +use app\common\dao\store\parameter\ParameterTemplateDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\RelevanceRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class ParameterTemplateRepository extends BaseRepository +{ + /** + * @var ParameterTemplateDao + */ + protected $dao; + + + /** + * ParameterRepository constructor. + * @param ParameterTemplateDao $dao + */ + public function __construct(ParameterTemplateDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2022/11/22 + */ + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with([ + 'cateId' => function($query){ + $query->with(['category' =>function($query) { + $query->field('store_category_id,cate_name'); + }]); + }, + 'merchant' => function($query) { + $query->field('mer_id,mer_name'); + } +// 'parameter' =>function($query){ +// $query->field('parameter_id,template_id,name,value,sort')->order('sort DESC'); +// } + ])->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function getSelect(array $where) + { + return$this->dao->getSearch($where)->field('template_name label,template_id value')->select(); + } + + /** + * TODO 详情 + * @param $id + * @param $merId + * @return array|\think\Model + * @author Qinii + * @day 2022/11/22 + */ + public function detail($id,$merId) + { + $where['template_id'] = $id; + if ($merId) $where['mer_id'] = $merId; + $data = $this->dao->getSearch($where)->with([ + 'cateId' => function($query){ + $query->with(['category' =>function($query) { + $query->field('store_category_id,cate_name'); + }]); + }, + 'parameter' =>function($query){ + $query->field('parameter_id,template_id,name,value,sort')->order('sort DESC'); + }, + 'merchant' => function($query){ + $query->field('mer_name,mer_id'); + } + ])->find(); + if (!$data) throw new ValidateException('数据不存在'); + return $data; + } + + public function show($where) + { + $data = $this->dao->getSearch($where)->with([ + 'parameter' =>function($query){ + $query->field('parameter_id,template_id,name,value,mer_id,sort')->order('sort DESC'); + } + ])->order('mer_id ASC,create_time DESC')->select(); + $list = []; + foreach ($data as $datum) { + if ($datum['parameter']) { + foreach ($datum['parameter'] as $item) { + $list[] = $item; + } + } + } + return $list; + } + /** + * TODO 添加模板 + * @param $merId + * @param $data + * @author Qinii + * @day 2022/11/22 + */ + public function create($merId, $data) + { + $params = $data['params']; + $cate = array_unique($data['cate_ids']); + $tem = [ + 'template_name' => $data['template_name'], + 'sort' => $data['sort'], + 'mer_id' => $merId + ]; + $paramMake = app()->make(ParameterRepository::class); + $releMake = app()->make(RelevanceRepository::class); + Db::transaction(function() use($params, $tem, $cate,$merId,$paramMake,$releMake) { + $temp = $this->dao->create($tem); + $paramMake->createOrUpdate($temp->template_id, $merId, $params); + if (!empty($cate)) $releMake->createMany($temp->template_id, $cate, RelevanceRepository::PRODUCT_PARAMES_CATE); + }); + } + + public function update($id, $data, $merId = 0) + { + $params = $data['params']; + $cate = array_unique($data['cate_ids']); + $tem = [ + 'template_name' => $data['template_name'], + 'sort' => $data['sort'], + ]; + + $paramMake = app()->make(ParameterRepository::class); + $releMake = app()->make(RelevanceRepository::class); + Db::transaction(function() use($id, $params, $tem, $cate,$paramMake,$releMake,$merId) { + $this->dao->update($id,$tem); + $paramMake->diffDelete($id, $params); + $paramMake->createOrUpdate($id, $merId, $params); + $releMake->batchDelete($id,RelevanceRepository::PRODUCT_PARAMES_CATE); + if (!empty($cate)) $releMake->createMany($id, $cate, RelevanceRepository::PRODUCT_PARAMES_CATE);; + }); + } + + public function delete($id) + { + $paramMake = app()->make(ParameterRepository::class); + $releMake = app()->make(RelevanceRepository::class); + Db::transaction(function() use($id, $paramMake,$releMake) { + $this->dao->delete($id); + $paramMake->getSearch(['template_id' => $id])->delete(); + $releMake->batchDelete($id,RelevanceRepository::PRODUCT_PARAMES_CATE); + }); + } + +} + diff --git a/app/common/repositories/store/parameter/ParameterValueRepository.php b/app/common/repositories/store/parameter/ParameterValueRepository.php new file mode 100644 index 00000000..f472a0bb --- /dev/null +++ b/app/common/repositories/store/parameter/ParameterValueRepository.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\parameter; + +use app\common\dao\store\parameter\ParameterValueDao; +use app\common\repositories\BaseRepository; + +class ParameterValueRepository extends BaseRepository +{ + /** + * @var ParameterValueDao + */ + protected $dao; + + + /** + * ParameterRepository constructor. + * @param ParameterValueDao $dao + */ + public function __construct(ParameterValueDao $dao) + { + $this->dao = $dao; + } + + public function create($id, $data,$merId) + { + if (empty($data)) return ; + foreach ($data as $datum) { + if ($datum['name'] && $datum['value']) { + $create[] = [ + 'product_id' => $id, + 'name' => $datum['name'] , + 'value' => $datum['value'], + 'sort' => $datum['sort'], + 'parameter_id' => $datum['parameter_id'] ?? 0, + 'mer_id' => $datum['mer_id'] ?? $merId, + 'create_time' => date('Y-m-d H:i:s',time()) + ]; + } + } + if ($create) $this->dao->insertAll($create); + } + + +} + diff --git a/app/common/repositories/store/product/ProductAssistRepository.php b/app/common/repositories/store/product/ProductAssistRepository.php new file mode 100644 index 00000000..30109a83 --- /dev/null +++ b/app/common/repositories/store/product/ProductAssistRepository.php @@ -0,0 +1,513 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductAssistDao; +use app\common\model\store\product\ProductLabel; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\services\SwooleTaskService; +use think\exception\ValidateException; +use think\facade\Db; + +class ProductAssistRepository extends BaseRepository +{ + public function __construct(ProductAssistDao $dao) + { + $this->dao = $dao; + } + + public function create(int $merId,array $data) + { + $product_make = app()->make(ProductRepository::class); + $product = [ + 'image' => $data['image'], + 'store_name' => $data['store_name'], + 'store_info' => $data['store_info'], + 'slider_image' => $data['slider_image'], + 'temp_id' => $data['temp_id'], + 'is_show' => 0, + 'product_type' => 3, + 'status' => 1, + 'old_product_id' => $data['product_id'], + 'guarantee_template_id'=>$data['guarantee_template_id'], + 'sales' => 0, + 'rate' => 3, + 'integral_rate' => 0, + 'delivery_way' => $data['delivery_way'], + 'delivery_free' => $data['delivery_free'], + ]; + + Db::transaction(function()use($data,$product_make,$product,$merId){ + event('product.assistCreate.before',compact('data')); + $product_id = $product_make->productCopy($data['product_id'],$product,3); + $assist = [ + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'status' => 0, + 'is_show' => $data['is_show'] ?? 1, + 'product_id' => $product_id, + 'store_name' => $data['store_name'], + 'store_info' => $data['store_info'], + 'pay_count' => $data['pay_count'], + 'mer_id' => $merId, + 'assist_count' => $data['assist_count'], + 'assist_user_count' => $data['assist_user_count'], + 'product_status' => 0, + ]; + + $sku_make = app()->make(ProductAssistSkuRepository::class); + + $productAssist = $this->dao->create($assist); + + $sku = $this->sltSku($data,$productAssist->product_assist_id,$data['product_id']); + + $sku_make->insertAll($sku); + $data['price'] = $sku[0]['assist_price']; + $data['mer_id'] = $merId; + app()->make(SpuRepository::class)->create($data,$product_id,$productAssist->product_assist_id,3); + event('product.assistCreate',compact('productAssist')); + SwooleTaskService::admin('notice', [ + 'type' => 'new_assist', + 'data' => [ + 'title' => '商品审核', + 'message' => '您有一个新的助力商品待审核', + 'id' => $productAssist->product_assist_id + ] + ]); + }); + } + + /** + * TODO 检测是否每个sku的价格 + * @param array $data + * @param int $presellType + * @return array + * @author Qinii + * @day 2020-10-12 + */ + public function sltSku(array $data,int $assistId,int $productId) + { + $make = app()->make(ProductAttrValueRepository::class); + $sku = []; + if(count($data['attrValue']) > 1) throw new ValidateException('助力商品只能选择一个SKU'); + $item = $data['attrValue'][0]; + + if(!isset($item['assist_price']))throw new ValidateException('请输入助力价格'); + $skuData = $make->getWhere(['unique' => $item['unique'],'product_id' => $productId]); + if(!$skuData) throw new ValidateException('SKU不存在'); + if($skuData['stock'] < $item['stock']) throw new ValidateException('限购数量不得大于库存'); + if(bccomp($item['assist_price'],$skuData['price'],2) == 1) throw new ValidateException('助力价格不得大于原价'); + $sku[] = [ + 'product_assist_id' => $assistId, + 'product_id' => $productId, + 'unique' => $item['unique'], + 'stock' => $item['stock'], + 'assist_price' => $item['assist_price'], + 'stock_count' => $item['stock'], + ]; + + return $sku; + } + + + /** + * TODO 商户后台列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-12 + */ + public function getMerchantList(array $where,int $page,int $limit) + { + $query = $this->dao->search($where) + ->with(['assistSku','product']) + ->append(['assist_status','all','pay', 'success','us_status','stock_count','stock']) + ->order('Product.sort DESC,Product.create_time DESC'); + $count = $query->count(); + $data = $query->page($page,$limit)->setOption('field', [])->field('ProductAssist.*,U.mer_labels') + ->select()->each(function($item){ + $item['product']['store_name'] = $item['store_name']; + $item['product']['store_info'] = $item['store_info']; + return $item; + }); + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count','list'); + } + + /** + * TODO 平台列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-19 + */ + public function getAdminList(array $where,int $page,int $limit) + { + $query = $this->dao->search($where) + ->append(['assist_status','all','pay', 'success','us_status','star','stock_count','stock']) + ->with(['product','assistSku','merchant' => function($query){ + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + }]); + $count = $query->count(); + $data = $query->page($page,$limit)->field('ProductAssist.*,U.star,U.rank,U.sys_labels')->select() + ->each(function($item){ + $item['product']['store_name'] = $item['store_name']; + $item['product']['store_info'] = $item['store_info']; + return $item; + }); + + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count','list'); + } + + /** + * TODO 移动端列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-19 + */ + public function getApiList(array $where, int $page,int $limit) + { + $where = array_merge($where,$this->dao->assistShow()); + $query = $this->dao->search($where)->where('ProductAssist.is_del',0) + ->append(['assist_status','user_count']) + ->with(['assistSku','product','merchant' => function($query){ + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + }]); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + /** + * TODO merchant 详情 + * @param int $merId + * @param int $id + * @return array + * @author Qinii + * @day 2020-10-13 + */ + public function detail(?int $merId,int $id) + { + $where[$this->dao->getPk()] = $id; + $where['is_del'] = 0; + if($merId)$where['mer_id'] = $merId; + $data = $this->dao->getWhere($where,'*', + [ + 'product' => ['content','attr','oldAttrValue'], + 'assistSku', + 'merchant'=> function($query){ + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + } + ]) + ->append(['assist_status','all','pay','success','us_status'])->toArray(); + + if(!$data) throw new ValidateException('数据不存在'); + if(!$data['product']) throw new ValidateException('该商品已不存在'); + + $spu_where = ['activity_id' => $id, 'product_type' => 3, 'product_id' => $data['product']['product_id']]; + $spu = app()->make(SpuRepository::class)->getSearch($spu_where)->find(); + $data['star'] = $spu['star'] ?? ''; + $data['mer_labels'] = $spu['mer_labels'] ?? ''; + + $sku_make = app()->make(ProductAssistSkuRepository::class); + $data['product']['delivery_way'] = empty($data['product']['delivery_way']) ? [] : explode(',',$data['product']['delivery_way']); + foreach ($data['product']['oldAttrValue'] as $key => $item) { + $sku = explode(',', $item['sku']); + $item['old_stock'] = $item['stock']; + $item['assistSku'] = $sku_make->getSearch([$this->dao->getPk() => $id,'unique' => $item['unique']])->find(); + foreach ($sku as $k => $v) { + $item['value' . $k] = $v; + } + $data['product']['attrValue'][$key] = $item; + } + foreach ($data['product']['attr'] as $k => $v) { + $data['product']['attr'][$k] = [ + 'value' => $v['attr_name'], + 'detail' => $v['attr_values'] + ]; + } + unset($data['product']['oldAttrValue']); + + $data['product']['store_name'] = $data['store_name']; + $data['product']['store_info'] = $data['store_info']; + return $data; + } + + + /** + * TODO 移动端 详情 + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 2020-10-19 + */ + public function apiDetail(int $id) + { + $where = $this->dao->assistShow(); + $where[$this->dao->getPk()] = $id; + $data = $this->dao->search($where)->append(['assist_status'])->find(); + if(!$data) { + app()->make(SpuRepository::class)->changeStatus($id,3); + throw new ValidateException('商品已下架'); + } + $make = app()->make(ProductRepository::class); + $data['product'] = $make->apiProductDetail(['product_id' => $data['product_id']],3,$id); + $data['product']['store_name'] = $data['store_name']; + $data['product']['store_info'] = $data['store_info']; + return $data; + } + + + /** + * TODO 商户编辑 Daft Punk FKJ Else + * @param int $id + * @param array $data + * @author Qinii + * @day 2020-10-13 + */ + public function edit(int $id,array $data) + { + + $resultData = [ + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'assist_user_count' => $data['assist_user_count'], + 'assist_count' => $data['assist_count'], + 'status' => $data['status'] , + 'is_show' => $data['is_show'] ?? 1, + 'store_name' => $data['store_name'], + 'pay_count' => $data['pay_count'], + 'store_info' => $data['store_info'], + ]; + + $product = [ + 'image' => $data['image'], + 'slider_image' => implode(',', $data['slider_image']), + 'temp_id' => $data['temp_id'], + 'product_type' => 3, + 'guarantee_template_id'=>$data['guarantee_template_id'], + 'delivery_way' => implode(',',$data['delivery_way']), + 'delivery_free' => $data['delivery_free'], + 'sort' => $data['sort'], + ]; + Db::transaction(function()use($id,$resultData,$product,$data){ + $res = $this->dao->get($id); + event('product.assistUpdate.before',compact('id','data')); + $this->dao->update($id,$resultData); + + $sku_make = app()->make(ProductAssistSkuRepository::class); + + $sku = $this->sltSku($data,$id,$res->product->old_product_id); + $sku_make->clear($id); + $sku_make->insertAll($sku); + + $product_make = app()->make(ProductRepository::class); + $product_make->update($res['product_id'],$product); + $data['price'] = $sku[0]['assist_price']; + app()->make(SpuRepository::class)->baseUpdate($data,$res['product_id'],$id,3); + event('product.assistUpdate',compact('id')); + SwooleTaskService::admin('notice', [ + 'type' => 'new_assist', + 'data' => [ + 'title' => '商品审核', + 'message' => '您有一个新的助力商品待审核', + 'id' => $id + ] + ]); + }); + } + + /** + * TODO 删除信息 + * @param array $where + * @author Qinii + * @day 2020-10-17 + */ + public function delete(array $where) + { + $productAssist = $this->dao->getWhere($where,'*',['product']); + if(!$productAssist) throw new ValidateException('数据不存在'); + Db::transaction(function()use($productAssist){ + $productAssist->is_del = 1; + $productAssist->save(); + event('product.assistDelete',compact('productAssist')); +// queue(ChangeSpuStatusJob::class, ['id' => $productAssist[$this->getPk()], 'product_type' => 3]); + app()->make(SpuRepository::class)->changeStatus($productAssist[$this->getPk()],3); + }); + } + + public function get(int $id) + { + $data = $this->dao->getWhere([$this->dao->getPk() => $id],'*',['assistSku.sku'])->toArray(); + $res = app()->make(ProductRepository::class)->getAdminOneProduct($data['product_id'],$id); + $res['product_assist_id'] = $data['product_assist_id']; + return $res; + } + + public function updateProduct(int $id,array $data) + { + $this->dao->update($id,['store_name' => $data['store_name']]); + $res = $this->dao->get($id); + $res->store_name = $data['store_name']; + $res->save(); + app()->make(SpuRepository::class)->changRank($id,$res['product_id'],3,$data); + unset($data['star']); + app()->make(ProductRepository::class)->adminUpdate($res['product_id'],$data); + + } + + + public function checkAssist($id,$uid) + { + $where = $this->dao->assistShow(); + $where[$this->dao->getPk()] = $id; + $data = $this->dao->search($where)->with(['product','assistSku.sku'])->append(['assist_status'])->find(); + if (!$data) throw new ValidateException('活动已结束'); + if($data['pay_count']){ + $make = app()->make(StoreOrderRepository::class); + $arr = ['exsits_id' => $id,'product_type' => 3]; + $_counot = $make->getTattendCount($arr,$uid)->count(); + if($_counot >= $data['pay_count']) throw new ValidateException('您以达到购买次数上限'); + } + if(!$data) throw new ValidateException('商品不在活动时间内'); + if($data['assist_status'] !== 1) + throw new ValidateException('商品不在活动时间内'); + if(!isset($data['assistSku'][0]['sku'])) + throw new ValidateException('商品SKU不存在'); + if($data['assistSku'][0]['stock'] < 1 || $data['assistSku'][0]['sku']['stock'] < 1) + throw new ValidateException('商品库存不足'); + return $data; + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-11-24 + */ + public function getUserCount() + { + $_data = app()->make(ProductAssistUserRepository::class)->userCount(); + $_data1 = app()->make(ProductAssistSetRepository::class)->userCount(); + $data['count'] = $_data['count'] + $_data1['count']; + $data['list'] = $_data['list']; + return $data; + } + + /** + * TODO 助力商品加入购物车检测 + * @param array $data + * @param $userInfo + * @author Qinii + * @day 2020-10-21 + */ + public function cartCheck(array $data,$userInfo) + { + /** + * 1 查询出商品信息; + * 2 商品是否存在 + * 3 购买是否超过限制 + * 4 库存检测 + */ + if(!$data['is_new']) throw new ValidateException('助力商品不可加入购物车'); + + $where = $this->dao->assistShow(); + $where[$this->dao->getPk()] = $data['product_id']; + $result = $this->dao->search($where)->with('product')->find(); + if (!$result) throw new ValidateException('商品已下架'); + + if($result['pay_count'] !== 0){ + $make = app()->make(StoreOrderRepository::class); + $tattend = [ + 'activity_id' => $data['product_id'], + 'product_type' => 3, + ]; + $count = $make->getTattendCount($tattend,$userInfo->uid)->count(); + if ($count >= $result['pay_count']) throw new ValidateException('您的本次活动购买数量上限'); + } + + $sku_make = app()->make(ProductAssistSkuRepository::class); + $_where = ['unique' => $data['product_attr_unique'], $this->dao->getPk() => $data['product_id']]; + $presellSku = $sku_make->getWhere($_where,'*',['sku']); + + if(($presellSku['stock'] < $data['cart_num']) || ($presellSku['sku']['stock'] < $data['cart_num'])) + throw new ValidateException('库存不足'); + $product = $result['product']; + $sku = $presellSku['sku']; + $cart = null; + return compact('product','sku','cart'); + } + + public function updateSort(int $id,?int $merId,array $data) + { + $where[$this->dao->getPk()] = $id; + if($merId) $where['mer_id'] = $merId; + $ret = $this->dao->getWhere($where); + if(!$ret) throw new ValidateException('数据不存在'); + app()->make(ProductRepository::class)->update($ret['product_id'],$data); + $make = app()->make(SpuRepository::class); + return $make->updateSort($ret['product_id'],$ret[$this->dao->getPk()],3,$data); + } + + public function switchStatus($id, $data) + { + $data['product_status'] = $data['status']; + $ret = $this->dao->get($id); + if (!$ret) + throw new ValidateException('数据不存在'); + event('product.assistStatus.before', compact('id', 'data')); + $this->dao->update($id, $data); + event('product.assistStatus', compact('id', 'data')); + + $type = ProductRepository::NOTIC_MSG[$data['status']][3]; + $message = '您有1个助力'. ProductRepository::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $data['status'] == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $id + ] + ], $ret->mer_id); + app()->make(SpuRepository::class)->changeStatus($id,3); + } + +} diff --git a/app/common/repositories/store/product/ProductAssistSetRepository.php b/app/common/repositories/store/product/ProductAssistSetRepository.php new file mode 100644 index 00000000..199859a2 --- /dev/null +++ b/app/common/repositories/store/product/ProductAssistSetRepository.php @@ -0,0 +1,291 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\model\store\product\ProductAssistSet; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductAssistSetDao; +use app\common\repositories\store\order\StoreOrderRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class ProductAssistSetRepository extends BaseRepository +{ + public function __construct(ProductAssistSetDao $dao) + { + $this->dao = $dao; + } + + public function getApiList(array $where,int $page,int $limit) + { + $query = $this->dao->getSearch($where)->order('create_time DESC') + ->with([ + "assist", + "assistSku", + 'product' => function($query){ + $query->field('product_id,image,store_name,status,unit_name,rank,mer_status,slider_image,mer_id,price'); + }]); + $count = $query->count(); + $list = $query->page($page,$limit)->append(['check','stop_time'])->select()->each(function ($item)use($where){ + $order = $this->getOrderInfo($where['uid'],$item['product_assist_set_id']); + return $item['order'] = $order ? $order : new \stdClass(); + }); + return compact('count','list'); + } + + public function getMerchantList(array $where,int $page,int $limit) + { + $query = $this->dao->getSearch($where)->order('create_time DESC') + ->with(['assist.assistSku','product' => function($query){ + $query->field('product_id,image,store_name,status,unit_name,rank,mer_status,slider_image,mer_id'); + },'user' => function($query){ + $query->field('uid,nickname'); + }]) + ->append(['check','user_count']); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + public function getAdminList(array $where,int $page,int $limit) + { + $query = $this->dao->getSearch($where)->order('create_time DESC') + ->with(['assist.assistSku','product' => function($query){ + $query->field('product_id,image,store_name,status,unit_name,rank,mer_status,slider_image,mer_id'); + },'merchant','user' => function($query){ + $query->field('uid,nickname'); + }]) + ->append(['check','user_count']); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + /** + * TODO 发起助力活动 + * @param int $assistId + * @param int $uid + * @return \app\common\dao\BaseDao|array|\think\Model|null + * @author Qinii + * @day 2020-10-27 + */ + public function create(int $assistId,int $uid) + { + $where['product_assist_id'] = $assistId; + $where['uid'] = $uid; + $where['is_del'] = 0; + $make = app()->make(StoreOrderRepository::class); + $arr = ['exsits_id' => $assistId,'product_type' => 3]; + $make->getTattendCount($arr,$uid)->count(); + + $result = $this->dao->getSearch($where)->where('status','in',[1,10])->find(); + if($result){ + $order = $this->getOrderInfo($uid,$result['product_assist_set_id']); + $paid = $order['paid'] ?? null; + if(!$order || $result['status'] == 1 || !$paid) return $result; + } + $make = app()->make(ProductAssistRepository::class); + $res = $make->checkAssist($assistId,$uid); + $where['product_id'] = $res['product_id']; + $where['assist_count'] = $res['assist_count']; + $where['assist_user_count'] = $res['assist_user_count']; + $where['mer_id'] = $res['mer_id']; + $where['share_num'] = 1; + $where['view_num'] = 1; + $result = $this->dao->create($where); + + return $result; + } + + /** + * TODO 助力操作 + * @param int $id + * @param $userInfo + * @author Qinii + * @day 2020-10-27 + */ + public function set(int $id,$userInfo) + { + $where = [ + "product_assist_set_id" => $id, + "status" => 1, + ]; + $result = $this->dao->getSearch($where)->find(); + if(!$result) throw new ValidateException('活动不存在或已关闭'); + + $relation = $this->relation($result,$userInfo->uid); + if(!$relation) throw new ValidateException('活动不存在或已关闭'); + if($relation == -1)throw new ValidateException('您的助力次数已达上限'); + if($relation == 10)throw new ValidateException('不能为自己助力'); + + if($result['assist_count'] <= $result['yet_assist_coount']) { + $result->yet_assist_count = $result->assist_count ; + $result->status = 10; + $result->save(); + throw new ValidateException('助力已完成'); + } + + $data = [ + "product_assist_set_id" => $id, + 'uid' => $userInfo->uid, + 'avatar_img' => $userInfo->avatar, + 'nickname' => $userInfo->nickname, + "product_assist_id" => $result['product_assist_id'] + ]; + + Db::transaction(function()use($id,$data,$result){ + + $yet = $result->yet_assist_count + 1; + + if($yet >= $result['assist_count']){ + $yet = $result->assist_count; + $result->status = 10; + } + $result->yet_assist_count = $yet; + $result->save(); + + $make = app()->make(ProductAssistUserRepository::class); + $make->create($data); + }); + } + + /** + * TODO + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 2020-10-27 + */ + public function detail(int $id,$userInfo) + { + $where = [ + "product_assist_set_id" => $id, + ]; + $res = $this->dao->getSearch($where)->with([ + 'product.content' => function($query){ + $query->field('product_id,store_name,image,old_product_id'); + }, + 'assist.assistSku.sku', + 'user' =>function($query){ + $query->field('uid,avatar,nickname'); + } + ])->append(['stopTime'])->find(); + if(!$res) throw new ValidateException('数据丢失'); + $res['product']['unique'] = $res['assist']['assistSku'][0]['unique']; + $relation = $this->relation($res,$userInfo->uid); + $res['relation'] = $relation; + $countData = app()->make(ProductAssistRepository::class)->getUserCount(); + $res['user_count_all'] = $countData['count']; + $res['user_count_product'] = $res->assist->user_count; + $order = $this->getOrderInfo($userInfo->uid,$id); + if($relation == 10) $res['order'] = $order ? $order : new \stdClass(); + + //已经参与活动了,不可在发起活动 + $where = [ + "product_assist_id" => $res['product_assist_id'], + 'uid' => $userInfo->uid, + 'status' => 1 + ]; + $res['create_status'] = true; + if($res['uid'] !== $userInfo->uid) $this->dao->incNum(2,$id); + + return $res; + } + + public function getOrderInfo(int $uid,int $assistSetId) + { + $result = null; + $order_make = app()->make(StoreOrderRepository::class); + $tattend = [ + 'activity_id' => $assistSetId, + 'product_type' => 3 + ]; + $order = $order_make->getTattendCount($tattend,$uid)->find(); + if($order){ + $result = [ + 'paid' => $order['paid'], + 'order_id' => $order['order_id'], + 'group_order_id' => $order['group_order_id'], + ]; + } + + return $result; + } + /** + * TODO 用户于当前助力活动的关系 + * @param ProductAssistSetRepository $res + * @param int $uid + * @return bool + * @author Qinii + * @day 2020-10-27 + */ + public function relation(ProductAssistSet $res,int $uid) + { + if($res['status'] == -1 ) return false; // 活动过结束 + //过期 活动结束 + if($res->stop_time < time()) { + $res->status = -1; + $res->save(); + return false; + } + if($uid == $res['uid']){ + //发起者 + $relation = 10; + }else{ + // + //不可助力 + $relation = -2; + $make = app()->make(ProductAssistUserRepository::class); + $_count = $make->getSearch(['product_assist_set_id' => $res['product_assist_set_id'],'uid' => $uid])->count(); + if(!$_count){ + $count = $make->getSearch(['product_assist_id' => $res['product_assist_id'],'uid' => $uid])->count(); + $relation = -1; + //用户还可以助力 + if($count < $res['assist_user_count'])$relation = 1; + } + } + return $relation; + } + + public function cartCheck(array $data,$userInfo) + { + /** + * 1 活动是否助力完成 + * 2 商品是否有效 + * 2 库存是否不足 + */ + if(!$data['is_new']) throw new ValidateException('助力商品不可加入购物车'); + if($data['cart_num'] != 1) throw new ValidateException('助力商品每次只能购买一件'); + $where[$this->dao->getPk()] = $data['product_id']; + $where['uid'] = $userInfo->uid; + $result = $this->dao->getSearch($where)->find(); + if(!$result) throw new ValidateException('请先发起您自己的助力活动'); + + $order_make = app()->make(StoreOrderRepository::class); + $tattend = [ + 'activity_id' => $data['product_id'], + 'product_type' => 3, + ]; + if($order_make->getTattendCount($tattend,$userInfo->uid)->count()) + throw new ValidateException('请勿重复下单'); + $make = app()->make(ProductAssistRepository::class); + + if($result['status'] == -1) throw new ValidateException('活动已结束'); + if($result['assist_count'] !== $result['yet_assist_count']) throw new ValidateException('快去邀请好友来助力吧'); + $res = $make->checkAssist($result['product_assist_id'],$userInfo->uid); + $product = $res['product']; + $sku = $product['assistSku']; + $cart = null; + return compact('product','sku','cart'); + } +} + diff --git a/app/common/repositories/store/product/ProductAssistSkuRepository.php b/app/common/repositories/store/product/ProductAssistSkuRepository.php new file mode 100644 index 00000000..f6070208 --- /dev/null +++ b/app/common/repositories/store/product/ProductAssistSkuRepository.php @@ -0,0 +1,25 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductAssistSkuDao; +use app\common\repositories\BaseRepository; +use think\facade\Db; + +class ProductAssistSkuRepository extends BaseRepository +{ + public function __construct(ProductAssistSkuDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/product/ProductAssistUserRepository.php b/app/common/repositories/store/product/ProductAssistUserRepository.php new file mode 100644 index 00000000..37674891 --- /dev/null +++ b/app/common/repositories/store/product/ProductAssistUserRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductAssistUserDao; +use think\exception\ValidateException; + +class ProductAssistUserRepository extends BaseRepository +{ + public function __construct(ProductAssistUserDao $dao) + { + $this->dao = $dao; + } + + public function userList(array $where,int $page ,int $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + + return compact('count','list'); + } +} diff --git a/app/common/repositories/store/product/ProductAttrRepository.php b/app/common/repositories/store/product/ProductAttrRepository.php new file mode 100644 index 00000000..83bb4bf2 --- /dev/null +++ b/app/common/repositories/store/product/ProductAttrRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductAttrDao as dao; + +class ProductAttrRepository extends BaseRepository +{ + + protected $dao; + + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + + +} diff --git a/app/common/repositories/store/product/ProductAttrValueRepository.php b/app/common/repositories/store/product/ProductAttrValueRepository.php new file mode 100644 index 00000000..477b604b --- /dev/null +++ b/app/common/repositories/store/product/ProductAttrValueRepository.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductAttrValueDao as dao; + +/** + * Class ProductAttrValueRepository + * @package app\common\repositories\store\product + * @mixin dao + */ +class ProductAttrValueRepository extends BaseRepository +{ + + protected $dao; + + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return mixed + */ + public function priceCount(int $id) + { + return min($this->dao->getFieldColumnt('product_id',$id,'price')); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return mixed + */ + public function stockCount(int $id) + { + return $this->dao->getFieldSum('product_id',$id,'stock'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int|null $merId + * @param string $value + * @return bool + */ + public function merUniqueExists(?int $merId,string $value) + { + return $this->dao->merFieldExists($merId,'unique',$value); + } + + /** + * TODO + * @param $unique + * @return mixed + * @author Qinii + * @day 2020-08-05 + */ + public function getOptionByUnique($unique) + { + return $this->dao->getFieldExists(null,'unique',$unique)->find(); + } + + +} diff --git a/app/common/repositories/store/product/ProductCateRepository.php b/app/common/repositories/store/product/ProductCateRepository.php new file mode 100644 index 00000000..2a1873d5 --- /dev/null +++ b/app/common/repositories/store/product/ProductCateRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductCateDao as dao; + +class ProductCateRepository extends BaseRepository +{ + + protected $dao; + + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + + +} diff --git a/app/common/repositories/store/product/ProductContentRepository.php b/app/common/repositories/store/product/ProductContentRepository.php new file mode 100644 index 00000000..f640a721 --- /dev/null +++ b/app/common/repositories/store/product/ProductContentRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductContentDao as dao; + +class ProductContentRepository extends BaseRepository +{ + + protected $dao; + + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + + +} diff --git a/app/common/repositories/store/product/ProductCopyRepository.php b/app/common/repositories/store/product/ProductCopyRepository.php new file mode 100644 index 00000000..ca4bcda8 --- /dev/null +++ b/app/common/repositories/store/product/ProductCopyRepository.php @@ -0,0 +1,333 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\repositories\system\attachment\AttachmentCategoryRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\services\CopyProductService; +use crmeb\services\CrmebServeServices; +use crmeb\services\DownloadImageService; +use Exception; +use think\exception\ValidateException; +use app\common\dao\store\product\ProductCopyDao; +use think\facade\Cache; +use think\facade\Db; + +class ProductCopyRepository extends BaseRepository +{ + protected $host = ['taobao', 'tmall', 'jd', 'pinduoduo', 'suning', 'yangkeduo','1688']; + protected $AttachmentCategoryName = '远程下载'; + protected $dao; + protected $updateImage = ['image', 'slider_image']; + protected $AttachmentCategoryPath = 'copy'; + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(ProductCopyDao $dao) + { + $this->dao = $dao; + } + + public function getProduct($url,$merId) + { + $key = $merId.'_url_'.$url; + if ($result= Cache::get($key)) return $result; + if (systemConfig('copy_product_status') == 1) { + $resultData = $this->useApi($url); + } else { + $resultData['data'] = app()->make(CrmebServeServices::class)->copy()->goods($url); + $resultData['status'] = true; + } + if ($resultData['status'] && $resultData['status']) { + $result = $this->getParamsData($resultData['data']); + Cache::set($key,$result); + $this->add(['type' => 'copy', 'num' => -1, 'info' => $url , 'mer_id' => $merId, 'message' => '采集商品',],$merId); + return $result; + } else { + if (isset($resultData['msg'])) + throw new ValidateException('接口错误信息:'.$resultData['msg']); + throw new ValidateException('采集失败,请更换链接重试!'); + } + + } + + /** + * TODO 99api采集 + * @param $url + * @return array + * @author Qinii + * @day 2022/11/11 + */ + public function useApi($url) + { + $apikey = systemConfig('copy_product_apikey'); + if (!$apikey) throw new ValidateException('请前往平台后台-设置-第三方接口-配置接口密钥'); + $url_arr = parse_url($url); + if (isset($url_arr['host'])) { + foreach ($this->host as $name) { + if (strpos($url_arr['host'], $name) !== false) { + $type = $name; + } + } + } + $type = ($type == 'pinduoduo' || $type == 'yangkeduo') ? 'pdd' : $type; + try{ + switch ($type) { + case 'taobao': + case 'tmall': + $params = []; + if (isset($url_arr['query']) && $url_arr['query']) { + $queryParts = explode('&', $url_arr['query']); + foreach ($queryParts as $param) { + $item = explode('=', $param); + if (isset($item[0]) && $item[1]) $params[$item[0]] = $item[1]; + } + } + $id = $params['id'] ?? ''; + break; + case 'jd': + $params = []; + if (isset($url_arr['path']) && $url_arr['path']) { + $path = str_replace('.html', '', $url_arr['path']); + $params = explode('/', $path); + } + $id = $params[1] ?? ''; + break; + case 'pdd': + $params = []; + if (isset($url_arr['query']) && $url_arr['query']) { + $queryParts = explode('&', $url_arr['query']); + foreach ($queryParts as $param) { + $item = explode('=', $param); + if (isset($item[0]) && $item[1]) $params[$item[0]] = $item[1]; + } + } + $id = $params['goods_id'] ?? ''; + break; + case 'suning': + $params = []; + if (isset($url_arr['path']) && $url_arr['path']) { + $path = str_replace('.html', '', $url_arr['path']); + $params = explode('/', $path); + } + $id = $params[2] ?? ''; + $shopid = $params[1] ?? ''; + break; + case '1688': + $params = []; + if (isset($url_arr['query']) && $url_arr['query']) { + $path = str_replace('.html', '', $url_arr['path']); + $params = explode('/', $path); + } + $id = $params[2] ?? ''; + $shopid = $params[1] ?? ''; + $type = 'alibaba'; + break; + + } + }catch (Exception $exception){ + throw new ValidateException('url有误'); + } + $result = CopyProductService::getInfo($type, ['itemid' => $id, 'shopid' => $shopid ?? ''], $apikey); + return $result; + } + + /** + * TODO 整理参数 + * @param $data + * @return array + * @author Qinii + * @day 2022/11/11 + * + */ + public function getParamsData($data) + { + if(!is_array($data['slider_image'])) $data['slider_image'] = json_decode($data['slider_image']); + $params = ProductRepository::CREATE_PARAMS; + foreach ($params as $param) { + if (is_array($param)) { + $res[$param[0]] = $param[1]; + } else { + $res[$param] = $data[$param] ?? ''; + } + if (in_array($param,$this->updateImage)) { + $res[$param] = $this->getImageByUrl($data[$param]); + } + } + $res['attr'] = $data['items'] ?? $data['info']['attr']; + $res['spec_type'] = count($res['attr']) ? '1' : '0'; + $res['content'] = $this->getDescriptionImage($data['description_image'] ?? $data['description_images'],$data['description']); + return $res; + } + + /** + * TODO 替换详情页的图片地址 + * @param $images + * @param $html + * @return mixed|string|string[]|null + * @author Qinii + * @day 2022/11/11 + */ + public function getDescriptionImage($images, $html) + { + preg_match_all('#]*>#i', $html, $match); + if (isset($match[1])) { + foreach ($match[1] as $item) { + $uploadValue = $this->getImageByUrl($item); + //下载成功更新数据库 + if ($uploadValue) { + //替换图片 + $html = str_replace($item, $uploadValue, $html); + } else { + //替换掉没有下载下来的图片 + $html = preg_replace('##i', '', $html); + } + } + } + return $html; + } + + /** + * TODO 根据url下载图片 + * @param $data + * @return array|mixed|string + * @author Qinii + * @day 2022/11/11 + */ + public function getImageByUrl($data) + { + $merId = request()->merId(); + $category = app()->make( AttachmentCategoryRepository::class)->findOrCreate([ + 'attachment_category_enname' => $this->AttachmentCategoryPath, + 'attachment_category_name' => $this->AttachmentCategoryName, + 'mer_id' => $merId, + 'pid' => 0, + ]); + $make = app()->make(AttachmentRepository::class); + $serve = app()->make(DownloadImageService::class); + $type = (int)systemConfig('upload_type') ?: 1; + + if (is_array($data)) { + foreach ($data as $datum) { + $arcurl = is_int(strpos($datum, 'http')) ? $datum : 'http://' . ltrim( $datum, '\//'); + $image = $serve->downloadImage($arcurl,$this->AttachmentCategoryPath); + $dir = $type == 1 ? rtrim(systemConfig('site_url'), '/').$image['path'] : $image['path']; + $data = [ + 'attachment_category_id' => $category->attachment_category_id, + 'attachment_name' => $image['name'], + 'attachment_src' => $dir + ]; + $make->create($type,$merId, request()->adminId(), $data); + $res[] = $dir; + } + } else { + $arcurl = is_int(strpos($data, 'http')) ? $data : 'http://' . ltrim( $data, '\//'); + $image = $serve->downloadImage($arcurl,$this->AttachmentCategoryPath); + $dir = $type == 1 ? rtrim(systemConfig('site_url'), '/').$image['path'] : $image['path']; + $data = [ + 'attachment_category_id' => $category->attachment_category_id, + 'attachment_name' => $image['name'], + 'attachment_src' => $dir + ]; + $make->create($type,$merId, request()->adminId(), $data); + $res = $dir; + } + return $res; + } + + + /** + * TODO 添加记录并修改数据 + * @param $data + * @param $merId + * @author Qinii + * @day 2020-08-06 + */ + public function add($data,$merId) + { + $make = app()->make(MerchantRepository::class); + $getOne = $make->get($merId); + + switch ($data['type']) { + case 'mer_dump': + //nobreak; + case 'pay_dump': + $field = 'export_dump_num'; + break; + case 'sys': + //nobreak; + //nobreak; + case 'pay_copy': + //nobreak; + case 'copy': + //nobreak; + $field = 'copy_product_num'; + break; + default: + $field = 'copy_product_num'; + break; + } + + + $number = $getOne[$field] + $data['num']; + $arr = [ + 'type' => $data['type'], + 'num' => $data['num'], + 'info' => $data['info']??'' , + 'mer_id'=> $merId, + 'message' => $data['message'] ?? '', + 'number' => ($number < 0) ? 0 : $number, + ]; + Db::transaction(function()use($arr,$make,$field){ + $this->dao->create($arr); + if ($arr['num'] < 0) { + $make->sumFieldNum($arr['mer_id'],$arr['num'],$field); + } else { + $make->addFieldNum($arr['mer_id'],$arr['num'],$field); + } + }); + } + + /** + * TODO 默认赠送复制次数 + * @param $merId + * @author Qinii + * @day 2020-08-06 + */ + public function defaulCopyNum($merId) + { + if(systemConfig('copy_product_status')){ + $data = [ + 'type' => 'sys', + 'num' => systemConfig('copy_product_defaul') ?? 0, + 'message' => '赠送次数', + ]; + $this->add($data,$merId); + } + } + + public function getList(array $where,int $page, int $limit) + { + $query = $this->dao->search($where)->with([ + 'merchant' => function ($query) { + return $query->field('mer_id,mer_name'); + } + ]); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } +} diff --git a/app/common/repositories/store/product/ProductGroupBuyingRepository.php b/app/common/repositories/store/product/ProductGroupBuyingRepository.php new file mode 100644 index 00000000..e7b33925 --- /dev/null +++ b/app/common/repositories/store/product/ProductGroupBuyingRepository.php @@ -0,0 +1,349 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\model\store\order\StoreOrder; +use app\common\model\store\product\ProductGroupBuying; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductGroupBuyingDao; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\CancelGroupBuyingJob; +use crmeb\jobs\SendSmsJob; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; + +class ProductGroupBuyingRepository extends BaseRepository +{ + protected $dao; + + /** + * ProductGroupRepository constructor. + * @param ProductGroupDao $dao + */ + public function __construct(ProductGroupBuyingDao $dao) + { + $this->dao = $dao; + } + + public function checkGroupStatus(int $groupId,$userInfo) + { + $this->checkStatus($groupId); + $data = $this->dao->getSearch([$this->dao->getPk() => $groupId,'is_del' => 0])->find(); + $user = null; + if($userInfo) { + $_where = [ + 'group_buying_id' => $groupId, + 'uid' => $userInfo->uid, + 'is_del' => 0 + ]; + $user = app()->make(ProductGroupUserRepository::class)->getWhere($_where); + } + if(!$data || ($data['status'] !== 0) || $user) return false; + return true; + } + + /** + * TODO 参团操作 + * @param $userInfo + * @param int $activeId + * @param int $groupId + * @param int $orderId + * @author Qinii + * @day 1/11/21 + */ + public function create($userInfo, int $activeId, int $groupId, int $orderId) + { + /** + * 1. 活动商品是否在售, + * 2. 团是否存在, + * 2.1 存在是否可加入 + * 2.2 不存在,创建团,标记为团长 + * 3. 记录参团人信息 + */ + $active_make = app()->make(ProductGroupRepository::class); + + $where = $active_make->actionShow(); + $where['product_group_id'] = $activeId; + $active = $active_make->search($where)->find(); + if(!$active) throw new ValidateException('活动商品已下架'); + if ($groupId && !$this->checkGroupStatus($groupId,$userInfo))$groupId = 0; + + return Db::transaction(function () use ($userInfo, $active, $groupId, $activeId, $orderId) { + if (!$groupId) { + $ficti_status = systemConfig('ficti_status') ? $active['ficti_status'] : 0; + $time = time() + $active['time'] * 3600; + $_group = [ + 'product_group_id' => $activeId, + 'ficti_status' => $ficti_status, + 'ficti_num' => $ficti_status ? $active['ficti_num'] : 0, + 'buying_count_num' => $active['buying_count_num'], + 'buying_num' => $active['buying_num'], + 'end_time' => $time, + 'mer_id' => $active['mer_id'], + ]; + $group = $this->dao->create($_group); + $groupId = $group->group_buying_id; + $is_initiator = 1; + } + $_where = [ + 'product_group_id' => $activeId, + 'group_buying_id' => $groupId, + 'is_initiator' => $is_initiator ?? 0, + 'order_id' => $orderId, + ]; + $user_make = app()->make(ProductGroupUserRepository::class); + $user_make->create($userInfo, $_where); + $this->dao->incField($groupId, 'yet_buying_num'); + if (!isset($is_initiator)) $this->checkStatus($groupId); + return $groupId; + }); + } + + /** + * TODO 成功后检测并修改状态 + * @param $groupId + * @author Qinii + * @day 1/11/21 + */ + public function checkStatus(?int $groupId) + { + $where = ['status' => 0, 'end_time' => time()]; + if ($groupId) $where = ['group_buying_id' => $groupId]; + $result = $this->dao->getSearch($where)->with([ + 'groupUser' => function($query){ + $query->where('uid','>',0)->where('is_del',0); + }, + ])->select(); + if (!$result) return true; + foreach ($result as $res) { + if ($res['yet_buying_num'] >= $res['buying_count_num']) { + $this->successChange($res); + }else{ + if ($res['end_time'] <= time()) { + if ($res['ficti_status'] && $res['yet_buying_num'] >= $res['buying_num']) { + $this->setFictiGroup($res); + } else { + $res->status = -1; + $res->save(); + foreach ($res->groupUser as $item){ + Queue::push(CancelGroupBuyingJob::class, ['order_id' => $item['order_id'],'message' => '拼团失败,自动退款']); + } + } + } + } + } + } + + /** + * TODO 虚拟成团 操作 + * @param ProductGroupBuying $res + * @author Qinii + * @day 1/11/21 + */ + public function setFictiGroup(ProductGroupBuying $res) + { + $j = $res['buying_count_num'] - $res['yet_buying_num']; + $user_make = app()->make(UserRepository::class); + $query = $user_make->search([]); + $count = $query->count(); + $id = rand(1, ($count - $j)); + $arr = $query->where('uid', '>', $id)->limit($j)->column('avatar'); + $data = []; + $_count = count($arr); + for ($i = 1; $i <= $j; $i++) { + $data[] = [ + 'group_buying_id' => $res['group_buying_id'], + 'product_group_id' => $res['product_group_id'], + 'uid' => 0, + 'order_id' => 0, + 'nickname' => '匿名', + 'avatar' => $arr[rand(0, $_count - 1)], + 'status' => 0 + ]; + } + Db::transaction(function ()use($res,$data){ + app()->make(ProductGroupUserRepository::class)->insertAll($data); + $this->successChange($res); + }); + + } + + /** + * TODO 成功后更改团状态 + * @param ProductGroupBuying $res + * @author Qinii + * @day 1/14/21 + */ + public function successChange(ProductGroupBuying $res) + { + $res->status = 10; + $res->save(); + app()->make(ProductGroupRepository::class)->incField($res['product_group_id'], 'success_num', 1); + $productGroupUserRepository = app()->make(ProductGroupUserRepository::class); + $productGroupUserRepository->updateStatus($res['group_buying_id']); + $user = $productGroupUserRepository->groupOrderIds($res['group_buying_id']); + $storeOrderStatusRepository = app()->make(storeOrderStatusRepository::class); + $data = $orderIds = []; + foreach ($user as $item) { + $data[] = [ + 'order_id' => $item['order_id'], + 'order_sn' => $item['orderInfo']['order_sn'], + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '拼团成功', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_GROUP_SUCCESS, + 'uid' => 0, + 'nickname' => '系统', + 'user_type' => $storeOrderStatusRepository::U_TYPE_SYSTEM, + ]; + $orderIds[] = $item['order_id']; + } + if ($data && $orderIds) { + Db::transaction(function () use ($storeOrderStatusRepository, $orderIds, $data, $res) { + $storeOrderStatusRepository->batchCreateLog($data); + app()->make(StoreOrderRepository::class) + ->getSearch([]) + ->whereIn('order_id', $orderIds) + ->update(['status' => 0]); + Queue::push(SendSmsJob::class, ['tempId' => 'USER_BALANCE_CHANGE', 'id' => $res->group_buying_id]); + }); + } + + } + + + /** + * TODO 平台团列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 1/12/21 + */ + public function getAdminList($where, $page, $limit) + { + $query = $this->dao->search($where)->with([ + 'productGroup' => [ + 'product' => function ($query) { + $query->field('product_id,store_name,image'); + } + ], + 'merchant' => function ($query) { + $query->field('mer_id,mer_name,mer_avatar,is_trader'); + }, + 'initiator' + ])->order('B.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[])->field('B.*')->select()->append(['stop_time']); + return compact('count', 'list'); + } + + + /** + * TODO 商户团列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 1/12/21 + */ + public function getMerchantList($where, $page, $limit) + { + $query = $this->dao->search($where)->with([ + 'productGroup' => [ + 'product' => function ($query) { + $query->field('product_id,store_name,image'); + } + ], + 'initiator' + ])->order('B.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[])->field('B.*')->select()->append(['stop_time']); + + return compact('count', 'list'); + } + + /** + * TODO 详情 + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 1/13/21 + */ + public function detail(int $id,$userInfo) + { + $where = ['group_buying_id' => $id]; + $data = $this->dao->getSearch($where)->where('is_del',0)->with([ + 'groupUser' => function($query){ + $query->where('is_del',0)->field('group_buying_id,product_group_id,is_initiator,nickname,avatar')->order('is_initiator DESC'); + }, + ])->hidden(['ficti_status','ficti_num'])->find(); + if(!$data) throw new ValidateException('无此团信息'); + $make = app()->make(ProductRepository::class); + $data['product'] = $make->apiProductDetail(['product_id' => $data->productGroup['product_id']],4,$data->productGroup['product_group_id']); + $data['product']['ot_price'] = $data['product']['price']; + $data['product']['price'] = $data->productGroup['price']; + if($userInfo) { + $make = app()->make(ProductGroupUserRepository::class); + $data['self'] = $make->getSearch(['group_buying_id' => $id,'uid' => $userInfo->uid,'is_del' => 0])->find(); + $count = $data['self'] ? 1: 0; + } + $data['create_status'] = $count ?? 0; + unset($data['productGroup']); + return $data; + } + + /** + * TODO 取消参团 + * @param int $groupId + * @param $userInfo + * @author Qinii + * @day 1/13/21 + */ + public function cancelGroup(int $groupId,$userInfo) + { + $this->checkStatus($groupId); + $res = $this->dao->get($groupId); + if(!$res) throw new ValidateException('数据丢失'); + if($res['status'] == 10 ) throw new ValidateException('已拼团成功,不可取消,请在订单详情中申请退款'); + if($res['status'] == -1 ) throw new ValidateException('已拼团失败,不可取消,订单将会自动退款'); + $make = app()->make(ProductGroupUserRepository::class); + $where = [ + 'group_buying_id' => $groupId, + 'uid' => $userInfo->uid , + 'is_del' => 0 + ]; + $user = $make->getSearch($where)->find(); + if(!$user) throw new ValidateException('您没有参加此团'); + Db::transaction(function()use($res,$user,$groupId,$make){ + // 如果团成员少于两人 直接关闭此团 + if($res['yet_buying_num'] < 2){ + $res->is_del = 1; + $res->status = -1; + $res->save(); + }else{ + //返回团对数量 + $this->dao->decField($groupId,'yet_buying_num',1); + //如果是团长,转移团长 + if($user['is_initiator']) $make->changeInitator($groupId,$user->uid); + $user->is_initiator = 0; + $user->is_del = 1; + $user->save(); + } + app()->make(StoreRefundOrderRepository::class)->autoRefundOrder($user['order_id'],1,'取消拼团,自动退款'); + }); + } +} diff --git a/app/common/repositories/store/product/ProductGroupRepository.php b/app/common/repositories/store/product/ProductGroupRepository.php new file mode 100644 index 00000000..48e6189e --- /dev/null +++ b/app/common/repositories/store/product/ProductGroupRepository.php @@ -0,0 +1,497 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\model\store\product\ProductLabel; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductGroupDao; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\StoreCategoryRepository; +use crmeb\services\SwooleTaskService; +use think\exception\ValidateException; +use think\facade\Db; +use think\Queue; + +class ProductGroupRepository extends BaseRepository +{ + protected $dao; + + /** + * ProductGroupRepository constructor. + * @param ProductGroupDao $dao + */ + public function __construct(ProductGroupDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO + * @param $merId + * @param $data + * @author Qinii + * @day 1/8/21 + */ + public function create($merId,$data) + { + $product_make = app()->make(ProductRepository::class); + $product = [ + 'store_name' => $data['store_name'], + 'image' => $data['image'], + 'slider_image' => $data['slider_image'], + 'store_info' => $data['store_info'], + 'unit_name' => $data['unit_name'], + 'temp_id' => $data['temp_id'], + 'product_type' => 4, + 'status' => 1, + 'sort' => $data['sort'], + 'old_product_id' => $data['product_id'], + 'guarantee_template_id'=>$data['guarantee_template_id'], + 'sales' => 0, + 'rate' => 3, + 'integral_rate' => 0, + 'delivery_way' => $data['delivery_way'], + 'delivery_free' => $data['delivery_free'], + ]; + + Db::transaction(function()use($data,$product_make,$product,$merId) { + event('product.groupCreate.before',compact('data','merId')); + $product_id = $product_make->productCopy($data['product_id'], $product, 4); + $slt = $this->sltNumber($data); + + $result = [ + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'status' => 0, + 'is_show' => $data['is_show'] ?? 1, + 'product_id' => $product_id, + 'pay_count' => $data['pay_count'], + 'once_pay_count' => $data['once_pay_count'], + 'mer_id' => $merId, + 'buying_count_num' => $data['buying_count_num'], + 'buying_num' => $slt['buying_num'], + 'ficti_status' => $data['ficti_status'], + 'ficti_num' => $slt['ficti_num'], + 'time' => $data['time'] + ]; + + $productGroup = $this->dao->create($result); + + $sku_make = app()->make(ProductGroupSkuRepository::class); + $res = $this->sltSku($data,$productGroup->product_group_id,$data['product_id']); + $sku_make->insertAll($res['sku']); + + $this->dao->update($productGroup->product_group_id,['price' => $res['price']]); + $product_make->update($product_id,['price' => $res['old_price']]); + $data['mer_id'] = $merId; + $data['price'] = $res['price']; + app()->make(SpuRepository::class)->create($data, $product_id, $productGroup->product_group_id, 4); + event('product.groupCreate.before',compact('productGroup')); + SwooleTaskService::admin('notice', [ + 'type' => 'new_group', + 'data' => [ + 'title' => '商品审核', + 'message' => '您有一个新的拼团商品待审核', + 'id' => $productGroup->product_group_id + ] + ]); + }); + } + + /** + * TODO + * @param int $id + * @param array $data + * @author Qinii + * @day 1/8/21 + */ + public function edit(int $id,array $data) + { + $product = [ + 'image' => $data['image'], + 'store_name' => $data['store_name'], + 'store_info' => $data['store_info'], + 'slider_image' => implode(',', $data['slider_image']), + 'temp_id' => $data['temp_id'], + 'unit_name' => $data['unit_name'], + 'sort' => $data['sort'], + 'guarantee_template_id'=>$data['guarantee_template_id'], + 'delivery_way' => implode(',',$data['delivery_way']), + 'delivery_free' => $data['delivery_free'], + ]; + $slt = $this->sltNumber($data); + $active = [ + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'status' => 1, + 'is_show' => $data['is_show'] ?? 1, + 'pay_count' => $data['pay_count'], + 'once_pay_count' => $data['once_pay_count'], + 'buying_count_num' => $data['buying_count_num'], + 'buying_num' => $slt['buying_num'], + 'ficti_status' => $data['ficti_status'], + 'ficti_num' => $slt['ficti_num'], + 'time' => $data['time'], + 'product_status' => 0, + 'action_status' => 0, + ]; + + Db::transaction(function()use($id,$active,$product,$data){ + $product_make = app()->make(ProductRepository::class); + $sku_make = app()->make(ProductGroupSkuRepository::class); + event('product.groupUpdate.before',compact('id','data')); + $resData = $this->dao->get($id); + $res = $this->sltSku($data,$id,$resData['product_id']); + + $active['price'] = $res['price']; + $this->dao->update($id,$active); + + $sku_make->clear($id); + $sku_make->insertAll($res['sku']); + $product['price'] = $res['old_price']; + $product_make->update($resData['product_id'],$product); + $product_make->createContent($resData['product_id'], ['content' => $data['content']]); + $data['price'] = $res['price']; + $data['mer_id'] = $resData['mer_id']; + app()->make(SpuRepository::class)->baseUpdate($data,$resData['product_id'],$id,4); + event('product.groupUpdate',compact('id')); + SwooleTaskService::admin('notice', [ + 'type' => 'new_group', + 'data' => [ + 'title' => '商品审核', + 'message' => '您有一个新的拼团商品待审核', + 'id' => $id + ] + ]); + }); + + } + + /** + * TODO 检测是否每个sku的价格 + * @param array $data + * @param int $presellId + * @param int $productId + * @return array + * @author Qinii + * @day 1/8/21 + */ + public function sltSku(array $data,int $ActiveId) + { + $make = app()->make(ProductAttrValueRepository::class); + $sku = []; + $price = 0; + $old_price = 0; + foreach ($data['attrValue'] as $item){ + $skuData = $make->getWhere(['unique' => $item['unique']]); + if(!$skuData) throw new ValidateException('SKU不存在'); + if(bccomp($item['active_price'],$skuData['price'],2) == 1) + throw new ValidateException('活动价格不得大于原价'); + if(!$item['active_price'] || $item['active_price'] < 0) + throw new ValidateException('请正确填写金额'); + $sku[] = [ + 'product_group_id' => $ActiveId, + 'product_id' => $data['product_id'], + 'unique' => $item['unique'], + 'stock' => $item['stock'], + 'stock_count' => $item['stock'], + 'active_price' => $item['active_price'], + ]; + $price = ($price == 0 ) ? $item['active_price'] : (($price > $item['active_price']) ? $item['active_price']:$price) ; + $old_price = ($old_price == 0 ) ? $item['price'] : (($old_price > $item['price']) ? $item['price']:$old_price) ; + } + return compact('sku','price','old_price'); + } + + public function sltNumber($data) + { + $ficti_status = systemConfig('ficti_status'); + $buying_num = $data['buying_count_num']; + $ficti_num = 0; + if($ficti_status && $data['ficti_status']){ + $ficti_num = (int)round($data['buying_count_num'] * (1 - (systemConfig('group_buying_rate') / 100 ))); + if($data['ficti_num'] > $ficti_num) + throw new ValidateException('最多虚拟人数超出比例范围'); + $ficti_num = $data['ficti_num']; + $buying_num = $data['buying_count_num'] - $ficti_num; + } + + return compact('buying_num','ficti_num'); + } + + /** + * TODO + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 1/9/21 + */ + public function getApiList(array $where,int $page,int $limit) + { + $where = array_merge($where,$this->dao->actionShow()); + $where['order'] = 'api'; + $query = $this->dao->search($where)->with([ + 'product' => function($query){ + $query->field('product_id,store_name,image,price,sales,unit_name'); + }, + 'merchant' => function($query){ + $query->field('mer_id,mer_name,is_trader'); + } + ]); + $count = $query->count(); + $list = $query->page($page,$limit)->hidden(['ficti_status','ficti_num','refusal','is_del'])->select() + ->append(['stock','sales']); + return compact('count','list'); + } + + public function getMerchantList(array $where,int $page,int $limit) + { + $where['order'] = 'sort'; + $query = $this->dao->search($where)->with([ + 'product' => function($query){ + $query->field('product_id,store_name,image,price,sales,sort'); + }, + ]) + ->append(['stock_count','stock','sales','count_take','count_user','us_status']); + $count = $query->count(); + $data = $query->page($page,$limit)->setOption('field', [])->field('ProductGroup.*,U.mer_labels')->select(); + + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + return compact('count','list'); + } + + public function getAdminList(array $where,int $page,int $limit) + { + $where['order'] = 'star'; + $query = $this->dao->search($where)->with([ + 'product' => function($query){ + $query->field('product_id,store_name,image,price,sales,rank'); + }, + 'merchant' => function($query){ + $query->field('mer_id,mer_name,is_trader'); + } + ])->append(['stock_count','stock','sales','count_take','count_user','star','us_status']); + $count = $query->count(); + $data = $query->page($page,$limit)->setOption('field', [])->field('ProductGroup.*,U.sys_labels')->select(); + + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + return compact('count','list'); + } + + /** + * TODO merchant 编辑时详情 + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 1/8/21 + */ + public function detail(?int $merId,int $id) + { + $where[$this->dao->getPk()] = $id; + $where['is_del'] = 0; + $data = $this->dao->getWhere($where,'*',[ + 'product' => ['attr','oldAttrValue','content'], + 'merchant'=> function($query){ + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + }] + ); + if(!$data) throw new ValidateException('数据不存在'); + if(!$data['product']) throw new ValidateException('该商品已不存在'); + + $data['product']['delivery_way'] = empty($data['product']['delivery_way']) ? [] : explode(',',$data['product']['delivery_way']); + + $spu_where = ['activity_id' => $id, 'product_type' => 4, 'product_id' => $data['product']['product_id']]; + $spu = app()->make(SpuRepository::class)->getSearch($spu_where)->find(); + $data['star'] = $spu['star'] ?? ''; + $data['mer_labels'] = $spu['mer_labels'] ?? ''; + + $sku_make = app()->make(ProductGroupSkuRepository::class); + foreach ($data['product']['oldAttrValue'] as $key => $item) { + $sku = explode(',', $item['sku']); + $item['old_stock'] = $item['stock']; + $_sku = $sku_make->getWhere([$this->dao->getPk() => $id,'unique' => $item['unique']]); + if($_sku) $_sku->append(['sales']); + $item['_sku'] = $_sku; + if(!$merId && !$item['_sku']) continue; + + foreach ($sku as $k => $v) { + $item['value' . $k] = $v; + } + $data['product']['attrValue'][$key] = $item; + } + unset($data['product']['oldAttrValue']); + foreach ($data['product']['attr'] as $k => $v) { + $data['product']['attr'][$k] = [ + 'value' => $v['attr_name'], + 'detail' => $v['attr_values'] + ]; + } + $data->append(['stock','sales','count_take','count_user','us_status','stock_count']); + return $data; + } + + /** + * TODO + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 1/9/21 + */ + public function apiDetail($id,$userInfo) + { + $where = $this->dao->actionShow(); + $where[$this->dao->getPk()] = $id ?: 0; + $data = $this->dao->search($where)->with([ + 'groupBuying.initiator' => function($query){ + $query->where('status',0)->where('is_del',0) + ->field('group_buying_id,status,product_group_id,buying_count_num,yet_buying_num,end_time') + ->order('create_time ASC'); + } + ])->hidden(['ficti_status','ficti_num','refusal','is_del'])->find(); + if(!$data) { + app()->make(SpuRepository::class)->changeStatus($id,4); + throw new ValidateException('商品已下架或不在活动时间内'); + } + + $make = app()->make(ProductRepository::class); + $data['successUser'] = app()->make(ProductGroupUserRepository::class)->successUser($id); + $data['product'] = $make->apiProductDetail(['product_id' => $data['product_id']],4,$id,$userInfo); + return $data->append(['sales','stock']); + } + + public function updateProduct(int $id,array $data) + { + $res = $this->dao->get($id); + app()->make(SpuRepository::class)->changRank($id,$res['product_id'],4,$data); + unset($data['star']); + app()->make(ProductRepository::class)->adminUpdate($res['product_id'],$data); + } + + + public function cartCheck(array $data,$userInfo) + { + /** + * 1.是否有团ID + * 1.1 有团,验证团是否满,状态是否可加入 + * 2.购买数量是否超过限制 + * 3.商品的限购库存 + * 4.原商品的库存 + * 5.限购数是否超出 + */ + if(!$data['is_new']) throw new ValidateException('拼团商品不可加入购物车'); + + $where = $this->dao->actionShow(); + $where['product_group_id'] = $data['product_id']; + $res = $this->dao->search($where)->find(); + if(!$res) throw new ValidateException('商品已下架'); + + if($data['cart_num'] > $res['once_pay_count']) throw new ValidateException('购买数量超过单次限制'); + + if($data['group_buying_id']){ + $buging_make = app()->make(ProductGroupBuyingRepository::class); + $group_status = $buging_make->checkGroupStatus($data['group_buying_id'],$userInfo); + if(!$group_status) throw new ValidateException('不可加入此团'); + $isCount = app()->make(StoreOrderProductRepository::class)->getSearch([ + 'product_type' => 4, + 'activity_id' =>$data['group_buying_id'], + 'uid' => $userInfo->uid] + )->count('*'); + if($isCount) throw new ValidateException('您已参加过此团'); + } + + $make = app()->make(ProductAttrValueRepository::class); + $old_sku = $make->getWhere(['unique' => $data['product_attr_unique']]); + if($old_sku['stock'] < $res['cart_num']) throw new ValidateException('原商品库存不足'); + + $sku_make = app()->make(ProductGroupSkuRepository::class); + $sku = $sku_make->getWhere(['product_group_id' => $data['product_id'],'unique' => $data['product_attr_unique']]); + if($sku['stock'] < $data['cart_num']) throw new ValidateException('商品限购数量不足'); + + if($res['pay_count'] !== 0 ) { + if($data['cart_num'] > $res['pay_count']) throw new ValidateException('购买数量超过活动限制'); + $order_make = app()->make(StoreOrderRepository::class); + $where = ['product_id' => $res['product_id'], 'product_type' => 4]; + $count = (int)$order_make->getTattendCount($where, $userInfo->uid)->sum('product_num'); + if(($count + $data['cart_num']) > $res['pay_count']) throw new ValidateException('购买数量超过活动限制'); + } + + $product = $res['product']; + $cart = null; + + return compact('product','sku','cart'); + } + + public function getCategory() + { + $pathArr = $this->dao->category(); + $path = []; + foreach ($pathArr as $item){ + $path[] = explode('/',$item)[1]; + } + $path = array_unique($path); + $cat = app()->make(StoreCategoryRepository::class)->getSearch(['ids' => $path])->field('store_category_id,cate_name')->select(); + return $cat; + } + + public function updateSort(int $id,?int $merId,array $data) + { + $where[$this->dao->getPk()] = $id; + if($merId) $where['mer_id'] = $merId; + $ret = $this->dao->getWhere($where); + if(!$ret) throw new ValidateException('数据不存在'); + app()->make(ProductRepository::class)->update($ret['product_id'],$data); + $make = app()->make(SpuRepository::class); + return $make->updateSort($ret['product_id'],$ret[$this->dao->getPk()],4,$data); + } + + public function switchStatus($id, $data) + { + $data['product_status'] = $data['status']; + $ret = $this->dao->get($id); + if (!$ret) + throw new ValidateException('数据不存在'); + event('product.groupStatus.before', compact('id', 'data')); + $this->dao->update($id, $data); + event('product.groupStatus', compact('id', 'data')); + + $type = ProductRepository::NOTIC_MSG[$data['status']][4]; + $message = '您有1个拼团'. ProductRepository::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $data['status'] == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $id + ] + ], $ret->mer_id); + app()->make(SpuRepository::class)->changeStatus($id,4); + } + +} diff --git a/app/common/repositories/store/product/ProductGroupSkuRepository.php b/app/common/repositories/store/product/ProductGroupSkuRepository.php new file mode 100644 index 00000000..fa0731e8 --- /dev/null +++ b/app/common/repositories/store/product/ProductGroupSkuRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductGroupSkuDao; +use think\exception\ValidateException; +use think\facade\Db; + +/** + * @mixin ProductGroupSkuDao + */ +class ProductGroupSkuRepository extends BaseRepository +{ + protected $dao; + + /** + * ProductGroupRepository constructor. + * @param ProductGroupDao $dao + */ + public function __construct(ProductGroupSkuDao $dao) + { + $this->dao = $dao; + } + +} diff --git a/app/common/repositories/store/product/ProductGroupUserRepository.php b/app/common/repositories/store/product/ProductGroupUserRepository.php new file mode 100644 index 00000000..ebe9c809 --- /dev/null +++ b/app/common/repositories/store/product/ProductGroupUserRepository.php @@ -0,0 +1,114 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductGroupUserDao; +use crmeb\services\LockService; +use think\exception\ValidateException; + +class ProductGroupUserRepository extends BaseRepository +{ + protected $dao; + + /** + * ProductGroupRepository constructor. + * @param ProductGroupUserDao $dao + */ + public function __construct(ProductGroupUserDao $dao) + { + $this->dao = $dao; + } + + public function create($userInfo, $data) + { + $_where = [ + 'product_group_id' => $data['product_group_id'], + 'group_buying_id' => $data['group_buying_id'], + 'uid' => $userInfo->uid, + ]; + $user = $this->getWhere($_where); + if ($user) { + throw new ValidateException('您已经参加过此团'); + } + + $data = [ + 'product_group_id' => $data['product_group_id'], + 'group_buying_id' => $data['group_buying_id'], + 'is_initiator' => $data['is_initiator'], + 'order_id' => $data['order_id'], + 'uid' => $userInfo->uid, + 'nickname' => $userInfo->nickname, + 'avatar' => $userInfo->avatar, + ]; + return app()->make(LockService::class)->exec('order.group_buying', function () use ($data) { + $this->dao->create($data); + }); + } + + /** + * TODO 团员列表 + * @param $id + * @return array + * @author Qinii + * @day 1/12/21 + */ + public function getAdminList($where,$page,$limit) + { + $query = $this->dao->getSearch($where)->where('uid','<>',0)->where('is_del',0)->with([ + 'orderInfo' => function($query){ + $query->field('order_id,order_sn,pay_price,status'); + }, + ])->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + /** + * TODO 团员列表 + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 1/12/21 + */ + public function getApiList($where,$page,$limit) + { + $query = $this->dao->getSearch($where)->where('uid','<>',0)->where('is_del',0)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->hidden(['uid','order_id','is_del'])->select(); + return compact('count','list'); + } + + + /** + * TODO 转移团长 + * @param $groupId + * @return bool + * @author Qinii + * @day 1/13/21 + */ + public function changeInitator(int $groupId,$uid) + { + $user = $this->dao->getSearch(['group_buying_id' => $groupId]) + ->where('uid','<>',0) + ->where('is_del',0) + ->where('uid','<>',$uid) + ->order('create_time ASC')->find(); + if($user) { + $user->is_initiator = 1; + $user->save(); + } + } + +} diff --git a/app/common/repositories/store/product/ProductLabelRepository.php b/app/common/repositories/store/product/ProductLabelRepository.php new file mode 100644 index 00000000..58d5530c --- /dev/null +++ b/app/common/repositories/store/product/ProductLabelRepository.php @@ -0,0 +1,134 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductLabelDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class ProductLabelRepository extends BaseRepository +{ + protected $dao; + + public function __construct(ProductLabelDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 8/17/21 + */ + public function getList(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->getSearch($where)->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + /** + * TODO 添加form + * @param int|null $id + * @param string $route + * @param array $formData + * @return \FormBuilder\Form + * @author Qinii + * @day 8/17/21 + */ + public function form(?int $id, string $route, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl($route)->build() : Route::buildUrl($route, ['id' => $id])->build()); + $form->setRule([ + Elm::input('label_name', '标签名称')->required(), + Elm::input('info', '说明'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]); + return $form->setTitle(is_null($id) ? '添加标签' : '编辑标签')->formData($formData); + } + + + /** + * TODO 编辑form + * @param int $id + * @param string $route + * @param int $merId + * @return \FormBuilder\Form + * @author Qinii + * @day 8/17/21 + */ + public function updateForm(int $id, string $route, int $merId = 0) + { + $data = $this->dao->getWhere(['product_label_id' => $id, 'mer_id' => $merId ]); + if (!$data) throw new ValidateException('数据不存在'); + return $this->form($id, $route, $data->toArray()); + } + + /** + * TODO + * @param int $merId + * @return array + * @author Qinii + * @day 8/18/21 + */ + public function getOptions(int $merId) + { + $where = [ + 'mer_id' => $merId, + 'status' => 1, + 'is_del' => 0 + ]; + return $this->dao->getSearch($where)->field('product_label_id id,label_name name')->order('sort DESC,create_time DESC')->select()->toArray(); + } + + public function checkHas($merId,$data) + { + if (!empty($data)){ + if (!is_array($data)) $data = explode(',', $data); + foreach ($data as $item) { + $data = $this->dao->getSearch(['product_label_id' => $item,'mer_id' => $merId])->find(); + if (!$data) throw new ValidateException( '标签ID:'.$item.',不存在'); + } + } + return true; + } + + /** + * TODO 是否重名 + * @param string $name + * @param int $merId + * @param null $id + * @return bool + * @author Qinii + * @day 9/6/21 + */ + public function check(string $name, int $merId, $id = null) + { + $where['label_name'] = $name; + $where['mer_id'] = $merId; + $data = $this->dao->getWhere($where); + if ($data) { + if (!$id) return false; + if ($id != $data['product_label_id']) return false; + } + return true; + } + +} diff --git a/app/common/repositories/store/product/ProductPresellRepository.php b/app/common/repositories/store/product/ProductPresellRepository.php new file mode 100644 index 00000000..c4fe3a83 --- /dev/null +++ b/app/common/repositories/store/product/ProductPresellRepository.php @@ -0,0 +1,546 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductPresellDao; +use app\common\model\store\product\ProductLabel; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\jobs\ChangeSpuStatusJob; +use crmeb\services\SwooleTaskService; +use think\exception\ValidateException; +use think\facade\Db; + +/** + * @mixin ProductPresellDao + */ +class ProductPresellRepository extends BaseRepository +{ + public function __construct(ProductPresellDao $dao) + { + $this->dao = $dao; + } + + public function create(int $merId, array $data) + { + $product_make = app()->make(ProductRepository::class); + $productRes = $product_make->get($data['product_id']); + if ($productRes['product_type'] !== 0) throw new ValidateException('商品正在参与其他活动,不可添加'); + + $presell = [ + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'presell_type' => $data['presell_type'], + 'final_start_time' => $data['final_start_time'] ?? '', + 'final_end_time' => $data['final_end_time'] ?? '', + 'status' => 0, + 'is_show' => $data['is_show'] ?? 1, + 'pay_count' => $data['pay_count'], + 'delivery_type' => $data['delivery_type'], + 'delivery_day' => $data['delivery_day'], + 'product_id' => $data['product_id'], + 'store_name' => $data['store_name'], + 'store_info' => $data['store_info'], + 'mer_id' => $merId, + 'product_status' => 0, + 'delivery_way' => $data['delivery_way'], + 'delivery_free' => $data['delivery_free'], + ]; + + $product = [ + 'image' => $data['image'], + 'slider_image' => implode(',', $data['slider_image']), + 'temp_id' => $data['temp_id'], + 'is_show' => 0, + 'product_type' => 2, + 'sort' => $data['sort'], + 'delivery_way' => $data['delivery_way'], + 'delivery_free' => $data['delivery_free'], + ]; + Db::transaction(function () use ($presell, $product, $data, $product_make) { + $sku_make = app()->make(ProductPresellSkuRepository::class); + event('product.presellCreate.before',compact('data')); + $productPresell = $this->dao->create($presell); + + $res = $this->sltSku($data, $productPresell->product_presell_id, $data['product_id']); + $sku_make->insertAll($res['sku']); + $product_make->update($presell['product_id'], $product); + $this->dao->update($productPresell->product_presell_id, ['price' => $res['price']]); + + $data['mer_id'] = $presell['mer_id']; + $data['price'] = $res['price']; + app()->make(SpuRepository::class)->create($data, $data['product_id'], $productPresell->product_presell_id, 2); + event('product.presellCreate',compact('productPresell')); + queue(ChangeSpuStatusJob::class, ['id' => $presell['product_id'], 'product_type' => 0]); + SwooleTaskService::admin('notice', [ + 'type' => 'new_presell', + 'data' => [ + 'title' => '商品审核', + 'message' => '您有一个新的预售商品待审核', + 'id' => $productPresell->product_presell_id, + 'type' => $data['presell_type'], + ] + ]); + }); + } + + /** + * TODO 检测是否每个sku的预售价格 + * @param array $data + * @param int $presellType + * @return array + * @author Qinii + * @day 2020-10-12 + */ + public function sltSku(array $data, int $presellId, int $productId) + { + $make = app()->make(ProductAttrValueRepository::class); + $sku = []; + $price = 0; + foreach ($data['attrValue'] as $item) { + if ($item['product_id'] !== $productId) throw new ValidateException('商品ID不一致'); + $skuData = $make->getWhere(['unique' => $item['unique'], 'product_id' => $productId]); + if (!$skuData) throw new ValidateException('SKU不存在'); + if (bccomp($item['presell_price'], $skuData['price'], 2) == 1) throw new ValidateException('预售价格不得大于原价'); + if (!$item['presell_price'] || $item['presell_price'] < 0) throw new ValidateException('请正确填写预售金额'); + if ($data['presell_type'] == 2) { + if (!$item['down_price'] || $item['down_price'] < 0) throw new ValidateException('请正确填写订金金额'); + $_price = bccomp($item['down_price'], bcmul($item['presell_price'], 0.2, 2), 2); + if ($_price == 1) throw new ValidateException('订金金额不得超过预售价20%'); + } + $sku[] = [ + 'product_presell_id' => $presellId, + 'product_id' => $data['product_id'], + 'unique' => $item['unique'], + 'stock' => $item['stock'], + 'stock_count' => $item['stock'], + 'presell_price' => $item['presell_price'], + 'down_price' => $data['presell_type'] == 1 ? $item['presell_price'] : $item['down_price'], + 'final_price' => bcsub($item['presell_price'], $item['down_price'], 2) + ]; + $price = ($price == 0) ? $item['presell_price'] : (($price > $item['presell_price']) ? $item['presell_price'] : $price); + } + return compact('sku', 'price'); + } + + + /** + * TODO 商户后台列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-12 + */ + public function getMerchantList(array $where, int $page, int $limit) + { + $query = $this->dao->search($where) + ->with(['product']) + ->append(['presell_status', 'seles', 'tattend_one', 'tattend_two', 'stock_count', 'stock', 'us_status']) + ->order('Product.sort DESC,Product.create_time DESC'); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field('ProductPresell.*,U.mer_labels') + ->select(); + + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + $stat = $this->stat($where['mer_id']); + return compact('stat', 'count', 'list'); + } + + /** + * TODO 平台列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-19 + */ + public function getAdminList(array $where, int $page, int $limit) + { + $query = $this->dao->search($where)->with([ + 'product', + 'merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + } + ]); + $count = $query->count(); + $data = $query->page($page, $limit)->field('ProductPresell.*,U.star,U.rank,U.sys_labels') + ->select()->append(['presell_status', 'seles', 'tattend_one', 'tattend_two', 'stock', 'stock_count', 'us_status']); + + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + $stat = $this->stat(null); + return compact('stat', 'count', 'list'); + } + + /** + * TODO 移动端列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-10-19 + */ + public function getApiList(array $where, int $page, int $limit) + { + $where = array_merge($where, $this->dao->actionShow()); + $query = $this->dao->search($where)->where('ProductPresell.is_del', 0) + ->with([ + 'product', + 'merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['coupon', 'tattend_one', 'tattend_two', 'seles']); + return compact('count', 'list'); + } + + /** + * TODO merchant / admin 详情 + * @param int $merId + * @param int $id + * @return array + * @author Qinii + * @day 2020-10-13 + */ + public function detail(?int $merId, int $id) + { + $where[$this->dao->getPk()] = $id; + $where['is_del'] = 0; + if ($merId) $where['mer_id'] = $merId; + $data = $this->dao->getWhere($where, '*', [ + 'product' => ['attr', 'attrValue', 'content'], + 'merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + } + ]); + if (!$data) throw new ValidateException('数据不存在'); + $data->append(['presell_status', 'tattend_one', 'tattend_two', 'stock', 'stock_count','us_status']); + if (!$data['product']) throw new ValidateException('该商品已不存在'); + + $spu_where = ['activity_id' => $id, 'product_type' => 2, 'product_id' => $data['product']['product_id']]; + $spu = app()->make(SpuRepository::class)->getSearch($spu_where)->find(); + $data['star'] = $spu['star'] ?? ''; + $data['mer_labels'] = $spu['mer_labels'] ?? ''; + $data['product']['delivery_way'] = empty($data['product']['delivery_way']) ? [] : explode(',',$data['product']['delivery_way']); + $sku_make = app()->make(ProductPresellSkuRepository::class); + foreach ($data['product']['attrValue'] as $key => $item) { + $sku = explode(',', $item['sku']); + $item['old_stock'] = $item['stock']; + $item['presellSku'] = $sku_make->getSearch(['product_presell_id' => $id, 'unique' => $item['unique']])->find(); + if (!$merId && !$item['presellSku']) continue; + foreach ($sku as $k => $v) { + $item['value' . $k] = $v; + } + $data['product']['attrValue'][$key] = $item; + } + foreach ($data['product']['attr'] as $k => $v) { + $data['product']['attr'][$k] = [ + 'value' => $v['attr_name'], + 'detail' => $v['attr_values'] + ]; + } + return $data; + } + + /** + * TODO 移动端 详情 + * @param int $id + * @return array|\think\Model|null + * @author Qinii + * @day 2020-10-19 + */ + public function apiDetail(int $id, $userInfo) + { + $where = $this->dao->actionShow(); + $where['product_presell_id'] = $id; + $data = $this->dao->search($where)->append(['presell_status', 'tattend_one', 'tattend_two', 'seles'])->find(); + if (!$data){ + app()->make(SpuRepository::class)->changeStatus($id,2); + throw new ValidateException('商品已下架'); + } + if ($data['pay_count'] && $userInfo->uid) { + $_count = app()->make(StoreOrderRepository::class)->getTattendCount([ + 'activity_id' => $id, + 'product_type' => 2, + 'type' => 1, + ], $userInfo->uid)->sum('total_num'); + $data['self_count'] = ($_count >= $data['pay_count']) ? 0 : ($data['pay_count'] - $_count); + } + $make = app()->make(ProductRepository::class); + $data['product'] = $make->apiProductDetail(['product_id' => $data['product_id']], 2, $id,$userInfo); + return $data; + } + + /** + * TODO 统计数量 + * @param int|null $merId + * @return array + * @author Qinii + * @day 2020-10-13 + */ + public function stat(?int $merId) + { + $where['product_type'] = 2; + if ($merId) { + $where['mer_id'] = $merId; + }else{ + $where['star'] = ''; + } + $where['presell_type'] = 1; + $all = $this->dao->search($where)->count(); + + $where['presell_type'] = 2; + $down = $this->dao->search($where)->count(); + + return compact('all', 'down'); + } + + /** + * TODO 商户编辑 + * @param int $id + * @param array $data + * @author Qinii + * @day 2020-10-13 + */ + public function edit(int $id, array $data) + { + $presell = [ + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'presell_type' => $data['presell_type'], + 'final_start_time' => $data['final_start_time'] ?? '', + 'final_end_time' => $data['final_end_time'] ?? '', + 'status' => $data['status'], + 'is_show' => $data['is_show'] ?? 1, + 'pay_count' => $data['pay_count'], + 'delivery_type' => $data['delivery_type'], + 'delivery_day' => $data['delivery_day'], + 'store_name' => $data['store_name'], + 'store_info' => $data['store_info'], + 'product_status' => 0, + ]; + $product = [ + 'image' => $data['image'], + 'slider_image' => implode(',', $data['slider_image']), + 'temp_id' => $data['temp_id'], + 'is_show' => 0, + 'product_type' => 2, + 'sort' => $data['sort'], + 'guarantee_template_id'=>$data['guarantee_template_id'], + 'delivery_way' => implode(',',$data['delivery_way']), + 'delivery_free' => $data['delivery_free'], + ]; + Db::transaction(function () use ($id, $presell, $product, $data) { + $product_make = app()->make(ProductRepository::class); + $sku_make = app()->make(ProductPresellSkuRepository::class); + event('product.presellUpdate.before',compact('id','data')); + $resData = $this->dao->get($id); + if ($resData->presell_status !== 0) throw new ValidateException('活动已不可编辑'); + $res = $this->sltSku($data, $id, $resData['product_id']); + + $presell['price'] = $res['price']; + $this->dao->update($id, $presell); + + $sku_make->clear($id); + $sku_make->insertAll($res['sku']); + + $product_make->update($resData['product_id'], $product); + $data['price'] = $res['price']; + app()->make(SpuRepository::class)->baseUpdate($data, $resData['product_id'], $id, 2); + event('product.presellUpdate',compact('id')); + SwooleTaskService::admin('notice', [ + 'type' => 'new_presell', + 'data' => [ + 'title' => '商品审核', + 'message' => '您有一个新的预售商品待审核', + 'id' => $id, + 'type' => $data['presell_type'] + ] + ]); + }); + } + + /** + * TODO 删除预售信息 + * @param array $where + * @author Qinii + * @day 2020-10-17 + */ + public function delete(array $where) + { + $data = $this->dao->getWhere($where, '*', ['product']); + if (!$data) throw new ValidateException('数据不存在'); + Db::transaction(function () use ($data) { + $data->is_del = 1; + $data->action_status = -1; + $data->save(); + $data->product->product_type = 0; + $data->product->save(); + $productPresell = $data; + event('product.presellDelete',compact('productPresell')); + app()->make(SpuRepository::class)->changeStatus($data[$this->getPk()],2); + }); + } + + /** + * TODO 预售商品加入购物车检测 + * @param array $data + * @param $userInfo + * @author Qinii + * @day 2020-10-21 + */ + public function cartCheck(array $data, $userInfo) + { + /** + * 1 查询出商品信息; + * 2 商品是否存在 + * 3 购买是否超过限制 + * 4 库存检测 + */ + if (!$data['is_new']) throw new ValidateException('预购商品不可加入购物车'); + + $where = $this->dao->actionShow(); + $where[$this->dao->getPk()] = $data['product_id']; + $where['product_type'] = 2; + $presell = $this->dao->search($where)->with('product')->find(); + if (!$presell) throw new ValidateException('商品已下架'); + if ($presell['presell_status'] !== 1) throw new ValidateException('请在活动时间内购买'); + if ($presell['pay_count'] !== 0) { + $make = app()->make(StoreOrderRepository::class); + $tattend = [ + 'activity_id' => $data['product_id'], + 'product_type' => 2, + 'type' => 1, + ]; + $count = $make->getTattendCount($tattend, $userInfo->uid)->sum('total_num'); + if ($count >= $presell['pay_count']) throw new ValidateException('您的本次活动购买数量上限'); + if (($presell['pay_count'] - $count) < $data['cart_num']) throw new ValidateException('您的本次活动购买数量不足'); + } + + $sku_make = app()->make(ProductPresellSkuRepository::class); + $_where = ['unique' => $data['product_attr_unique'], $this->dao->getPk() => $data['product_id']]; + $presellSku = $sku_make->getWhere($_where, '*', ['sku']); + + if (($presellSku['stock'] < $data['cart_num']) || ($presellSku['sku']['stock'] < $data['cart_num'])) + throw new ValidateException('库存不足'); + $product = $presell['product']; + $sku = $presellSku['sku']; + $cart = null; + + return compact('product', 'sku', 'cart'); + } + + + public function get(int $id) + { + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $res = app()->make(ProductRepository::class)->getAdminOneProduct($data['product_id'], $id); + $res['store_name'] = $data['store_name']; + $res['store_info'] = $data['store_info']; + $res['presell_type'] = $data['presell_type']; + $res['product_presell_id'] = $data['product_presell_id']; + return $res; + } + + public function updateProduct(int $id, array $data) + { + $this->dao->update($id, ['store_name' => $data['store_name']]); + $res = $this->dao->get($id); + $res->store_name = $data['store_name']; + $res->save(); + app()->make(SpuRepository::class)->changRank($id, $res['product_id'], 2, $data); + unset($data['store_name'], $data['star']); + app()->make(ProductRepository::class)->adminUpdate($res['product_id'], $data); + } + + + /** + * TODO 关闭过期 + * @param array|null $where + * @author Qinii + * @day 2020-11-23 + */ + public function checkStatus(?array $where) + { + $where['action_status'] = 1; + $where['type'] = 3; + $this->dao->search($where)->select()->each(function ($data) { + foreach ($data as $item) { + $item->action_status = -1; + $item->save(); + $item->product->product_type = 0; + $item->product->save(); + queue(ChangeSpuStatusJob::class, ['id' => $item->product_presell_id, 'product_type' => 2]); + } + }); + } + + public function updateSort(int $id, ?int $merId, array $data) + { + $where[$this->dao->getPk()] = $id; + if ($merId) $where['mer_id'] = $merId; + $ret = $this->dao->getWhere($where); + if (!$ret) throw new ValidateException('数据不存在'); + app()->make(ProductRepository::class)->update($ret['product_id'], $data); + $make = app()->make(SpuRepository::class); + return $make->updateSort($ret['product_id'], $id, 2, $data); + } + + public function switchStatus($id, $data) + { + $data['product_status'] = $data['status']; + $ret = $this->dao->get($id); + if (!$ret) + throw new ValidateException('数据不存在'); + event('product.presellStatus.before', compact('id', 'data')); + + $this->dao->update($id, $data); + event('product.presellStatus', compact('id', 'data')); + + $type = ProductRepository::NOTIC_MSG[$data['status']][2]; + $message = '您有1个预售'. ProductRepository::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $data['status'] == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $id + ] + ], $ret->mer_id); + + app()->make(SpuRepository::class)->changeStatus($id,2); + } +} diff --git a/app/common/repositories/store/product/ProductPresellSkuRepository.php b/app/common/repositories/store/product/ProductPresellSkuRepository.php new file mode 100644 index 00000000..0449d823 --- /dev/null +++ b/app/common/repositories/store/product/ProductPresellSkuRepository.php @@ -0,0 +1,25 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductPresellSkuDao; +use app\common\repositories\BaseRepository; +use think\facade\Db; + +class ProductPresellSkuRepository extends BaseRepository +{ + public function __construct(ProductPresellSkuDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/product/ProductReplyRepository.php b/app/common/repositories/store/product/ProductReplyRepository.php new file mode 100644 index 00000000..1f7d8c23 --- /dev/null +++ b/app/common/repositories/store/product/ProductReplyRepository.php @@ -0,0 +1,276 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\product; + + +use app\common\dao\BaseDao; +use app\common\dao\store\product\ProductReplyDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\user\UserBrokerageRepository; +use crmeb\jobs\UpdateProductReplyJob; +use crmeb\services\SwooleTaskService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use function Symfony\Component\String\b; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; +use think\Model; +use think\facade\Queue; + +/** + * Class ProductReplyRepository + * @package app\common\repositories\store\product + * @author xaboy + * @day 2020/5/30 + * @mixin ProductReplyDao + */ +class ProductReplyRepository extends BaseRepository +{ + /** + * ProductReplyRepository constructor. + * @param ProductReplyDao $dao + */ + public function __construct(ProductReplyDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->searchJoinQuery($where)->order('A.sort DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * TODO + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-30 + */ + public function getApiList($where, $page, $limit) + { + if (systemConfig('sys_reply_status') === '0') { + $count = 0; + $list = []; + } else { + $query = $this->dao->search($where)->where('is_del', 0) + ->when($where['type'] !== '', function ($query) use ($where) { + $query->where($this->switchType($where['type'])); + }) + ->with(['orderProduct' => function ($query) { + $query->field('order_product_id,cart_info'); + }]) + ->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->hidden(['is_virtual'])->select()->each(function ($item) { + $item['sku'] = $item['orderProduct']['cart_info']['productAttr']['sku'] ?? ''; + if (mb_strlen($item['nickname']) > 1) { + $str = mb_substr($item['nickname'],0,1) . '*'; + if (mb_strlen($item['nickname']) > 2) { + $str .= mb_substr($item['nickname'], -1,1); + } + $item['nickname'] = $str; + } + unset($item['orderProduct']); + return $item; + }); + } + + $product = ['product_id' => $where['product_id'], 'is_del' => 0]; + $stat = [ + 'count' => $this->dao->search($product)->count(), + 'best' => $this->dao->search($product)->where($this->switchType('best'))->count(), + 'middle' => $this->dao->search($product)->where($this->switchType('middle'))->count(), + 'negative' => $this->dao->search($product)->where($this->switchType('negative'))->count(), + ]; + + $rate = ($stat['count'] > 0) ? bcdiv($stat['best'], $stat['count'], 2) * 100 . '%' : 100 . '%'; + $ret = app()->make(ProductRepository::class)->get($where['product_id']); + $star = (($ret['rate'] == 0) ? 0 : ($ret['rate'] / 5) * 100) . '%'; + return compact('rate', 'star', 'count', 'stat', 'list'); + } + + /** + * TODO + * @param $type + * @author Qinii + * @day 2020-06-30 + */ + public function switchType($type) + { + switch ($type) { + case 'best': + $where = [['rate', '>=', 4], ['rate', '<=', 5]]; + break; + case 'middle': + $where = [['rate', '>=', 2], ['rate', '<', 4]]; + break; + case 'negative': + $where = [['rate', '<', 2]]; + break; + default: + $where = []; + break; + } + return $where; + } + + /** + * @param int $productId + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/5/30 + */ + public function form(?int $productId) + { + $rule = []; + if ($productId) { + $rule[] = Elm::hidden('product_id', [['id' => $productId]]); + } else { + $rule[] = Elm::frameImage('product_id', '商品', '/' . config('admin.admin_prefix') . '/setting/storeProduct?field=product_id')->width('60%')->height('536px')->props(['srcKey' => 'src'])->modal(['modal' => false]); + } + $rule[] = Elm::input('nickname', '用户昵称')->required(); + $rule[] = Elm::input('comment', '评价文字')->type('textarea'); + $rule[] = Elm::rate('product_score', '商品分数', 5)->col(8)->max(5); + $rule[] = Elm::rate('service_score', '服务分数', 5)->col(8)->max(5); + $rule[] = Elm::rate('postage_score', '物流分数', 5)->col(8)->max(5); + $rule[] = Elm::frameImage('avatar', '用户头像', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=avatar&type=1')->width('896px')->height('480px')->props(['footer' => false])->modal(['modal' => false]); + $rule[] = Elm::frameImages('pics', '评价图片', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=pics&type=2')->maxLength(6)->width('896px')->height('480px')->spin(0)->modal(['modal' => false])->props(['footer' => false]); + return Elm::createForm(Route::buildUrl('systemProductReplyCreate')->build(), $rule)->setTitle('添加虚拟评价'); + } + + public function replyForm(int $replyId, $merId = 0) + { + return Elm::createForm(Route::buildUrl($merId ? 'merchantProductReplyReply' : 'systemProductReplyReply', ['id' => $replyId])->build(), [ + Elm::textarea('content', '回复内容')->required() + ])->setTitle('评价回复'); + } + + /** + * @param array $productIds + * @param array $data + * @return int + * @author xaboy + * @day 2020/5/30 + */ + public function createVirtual(array $productIds, array $data) + { + + //todo 虚拟产品 sku + $data['is_virtual'] = 1; + $data['product_type'] = 0; + $data['uid'] = 0; + $data['rate'] = ($data['product_score'] + $data['service_score'] + $data['postage_score']) / 3; + $data['pics'] = implode(',', $data['pics']); + $productRepository = app()->make(ProductRepository::class); + $productIds = $productRepository->intersectionKey($productIds); + $list = []; + foreach ($productIds as $productId) { + $data['product_id'] = $productId; + $data['mer_id'] = $productRepository->productIdByMerId($productId); + $list[] = $data; + } + $this->dao->insertAll($list); + foreach ($productIds as $productId) { + Queue::push(UpdateProductReplyJob::class, $productId); + } + } + + /** + * @Author:Qinii + * @Date: 2020/6/2 + * @param int $productId + * @return array + */ + public function getReplyRate(int $productId) + { + + $res = $this->selectWhere(['product_id' => $productId,'is_del' =>0]); + $best = $res->where('rate', '>=', 4)->where('rate', '<=', 5)->count(); + $count = $res->count(); + $rate = ''; + if ($best && $count) $rate = bcdiv($best, $count, 2) * 100 . '%'; + return compact('best', 'rate', 'count'); + } + + public function reply(array $data) + { + $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class); + $orderProduct = $storeOrderProductRepository->userOrderProduct($data['order_product_id'], $data['uid']); + if (!$orderProduct || !$orderProduct->orderInfo) + throw new ValidateException('订单不存在'); + if ($orderProduct->is_reply) + throw new ValidateException('该商品已评价'); + $data['product_id'] = $orderProduct['product_id']; + $data['unique'] = $orderProduct['cart_info']['productAttr']['unique']; + $data['mer_id'] = $orderProduct->orderInfo['mer_id']; + $data['product_type'] = $orderProduct['cart_info']['product']['product_type']; + $data['rate'] = ($data['product_score'] + $data['service_score'] + $data['postage_score']) / 3; + Db::transaction(function () use ($data, $orderProduct, $storeOrderProductRepository) { + $this->dao->create($data); + $orderProduct->is_reply = 1; + $orderProduct->save(); + if (!$storeOrderProductRepository->noReplyProductCount($orderProduct->orderInfo->order_id)) { + $orderProduct->orderInfo->status = 3; + $orderProduct->orderInfo->save(); + //TODO 交易完成 + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $orderProduct->orderInfo->order_id, + 'order_sn' => $orderProduct->orderInfo->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '交易完成', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_OVER, + ]; + $storeOrderStatusRepository->createSysLog($orderStatus); + } + }); + SwooleTaskService::merchant('notice', [ + 'type' => 'reply', + 'data' => [ + 'title' => '新评价', + 'message' => '您有一条新的商品评价', + 'id' => $data['product_id'] + ] + ], $data['mer_id']); + app()->make(UserBrokerageRepository::class)->incMemberValue($data['uid'], 'member_reply_num', $data['order_product_id']); + Queue::push(UpdateProductReplyJob::class, $orderProduct->product_id); + } + +} diff --git a/app/common/repositories/store/product/ProductRepository.php b/app/common/repositories/store/product/ProductRepository.php new file mode 100644 index 00000000..f7e67b4f --- /dev/null +++ b/app/common/repositories/store/product/ProductRepository.php @@ -0,0 +1,2216 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\product; + +use app\common\model\store\product\ProductLabel; +use app\common\model\user\User; +use app\common\repositories\community\CommunityRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\GuaranteeRepository; +use app\common\repositories\store\GuaranteeTemplateRepository; +use app\common\repositories\store\GuaranteeValueRepository; +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\parameter\ParameterValueRepository; +use app\common\repositories\store\StoreActivityRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\store\StoreSeckillTimeRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserVisitRepository; +use app\validate\merchant\StoreProductValidate; +use crmeb\jobs\ChangeSpuStatusJob; +use crmeb\jobs\SendSmsJob; +use crmeb\services\QrcodeService; +use crmeb\services\RedisCacheService; +use crmeb\services\SwooleTaskService; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductDao as dao; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; +use app\common\repositories\store\StoreBrandRepository; +use think\facade\Queue; +use think\facade\Route; +use think\contract\Arrayable; + +/** + * Class ProductRepository + * @package app\common\repositories\store\product + * @author xaboy + * @mixin dao + */ +class ProductRepository extends BaseRepository +{ + + protected $dao; + const CREATE_PARAMS = [ + "image", "slider_image", "store_name", "store_info", "keyword", "bar_code", "guarantee_template_id", "cate_id", "mer_cate_id", "unit_name", "sort" , "is_show", "is_good", 'is_gift_bag', 'integral_rate', "video_link", "temp_id", "content", "spec_type", "extension_type", "attr", 'mer_labels', 'delivery_way', 'delivery_free','param_temp_id','extend', + ["brand_id",0], + ['once_max_count',0], + ['once_min_count',0], + ['pay_limit', 0], + ["attrValue",[]], + ['give_coupon_ids',[]], + ['type',0], + ['svip_price',0], + ['svip_price_type',0], + ['params',[]], + ]; + protected $admin_filed = 'Product.product_id,Product.mer_id,brand_id,spec_type,unit_name,mer_status,rate,reply_count,store_info,cate_id,Product.image,slider_image,Product.store_name,Product.keyword,Product.sort,U.rank,Product.is_show,Product.sales,Product.price,extension_type,refusal,cost,ot_price,stock,is_gift_bag,Product.care_count,Product.status,is_used,Product.create_time,Product.product_type,old_product_id,star,ficti,integral_total,integral_price_total,sys_labels,param_temp_id,mer_svip_status,svip_price,svip_price_type'; + protected $filed = 'Product.bar_code,Product.product_id,Product.mer_id,brand_id,unit_name,spec_type,mer_status,rate,reply_count,store_info,cate_id,Product.image,slider_image,Product.store_name,Product.keyword,Product.sort,Product.is_show,Product.sales,Product.price,extension_type,refusal,cost,ot_price,stock,is_gift_bag,Product.care_count,Product.status,is_used,Product.create_time,Product.product_type,old_product_id,integral_total,integral_price_total,mer_labels,Product.is_good,Product.is_del,type,param_temp_id,mer_svip_status,svip_price,svip_price_type'; + + const NOTIC_MSG = [ + 1 => [ + '0' => 'product_success', + '1' => 'product_seckill_success', + '2' => 'product_presell_success', + '3' => 'product_assist_success', + '4' => 'product_group_success', + 'msg' => '审核通过' + ], + -1 => [ + '0' => 'product_fail', + '1' => 'product_seckill_fail', + '2' => 'product_presell_fail', + '3' => 'product_assist_fail', + '4' => 'product_group_fail', + 'msg' => '审核失败' + ], + -2 => [ + '0' => 'product_fail', + '1' => 'product_seckill_fail', + '2' => 'product_presell_fail', + '3' => 'product_assist_fail', + '4' => 'product_group_fail', + 'msg' => '被下架' + ], + ]; + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @param int $merId + * @return mixed + */ + public function CatExists(int $id) + { + return (app()->make(StoreCategoryRepository::class))->merExists(0, $id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/20 + * @param $ids + * @param int $merId + * @return bool + */ + public function merCatExists($ids, int $merId) + { + if (!is_array($ids ?? '')) return true; + foreach ($ids as $id) { + if (!(app()->make(StoreCategoryRepository::class))->merExists($merId, $id)) + return false; + } + return true; + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param int $id + * @return mixed + */ + public function merShippingExists(int $merId, int $id) + { + $make = app()->make(ShippingTemplateRepository::class); + return $make->merExists($merId, $id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @return mixed + */ + public function merBrandExists(int $id) + { + $make = app()->make(StoreBrandRepository::class); + return $make->meExists($id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param int $id + * @return bool + */ + public function merExists(?int $merId, int $id) + { + return $this->dao->merFieldExists($merId, $this->getPk(), $id); + } + + public function merDeleteExists(int $merId, int $id) + { + return $this->dao->getDeleteExists($merId, $id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $merId + * @param int $id + * @return bool + */ + public function apiExists(?int $merId, int $id) + { + return $this->dao->apiFieldExists($merId, $this->getPk(), $id); + } + + /** + * @param int $merId + * @param int $tempId + * @return bool + * @author Qinii + */ + public function merTempExists(int $merId, int $tempId) + { + return $this->dao->merFieldExists($merId, 'temp_id', $tempId); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param array $data + */ + public function create(array $data, int $productType = 0, $conType = 0) + { + if (!$data['spec_type']) { + $data['attr'] = []; + if (count($data['attrValue']) > 1) throw new ValidateException('单规格商品属性错误'); + } + $content = [ + 'content' => $conType ? json_encode($data['content']) : $data['content'] , + 'type' => $conType + ]; + $product = $this->setProduct($data); + event('product.create.before', compact('data','productType','conType')); + return Db::transaction(function () use ($data, $productType,$conType,$content,$product) { + $activity_id = 0; + $product['product_type'] = $productType; + $result = $this->dao->create($product); + $settleParams = $this->setAttrValue($data, $result->product_id, $productType, 0,$data['mer_id']); + $settleParams['cate'] = $this->setMerCate($data['mer_cate_id'], $result->product_id, $data['mer_id']); + $settleParams['attr'] = $this->setAttr($data['attr'], $result->product_id); + if (in_array($productType, [0, 98])) app()->make(ParameterValueRepository::class)->create($result->product_id, $data['params'] ?? [],$data['mer_id']); + $this->save($result->product_id, $settleParams, $content,$product,$productType); + if (in_array($productType, [0, 1,98])) { + if ($productType == 1) { //秒杀商品 + $dat = $this->setSeckillProduct($data); + $dat['product_id'] = $result->product_id; + $seckill = app()->make(StoreSeckillActiveRepository::class)->create($dat); + $activity_id = $seckill->seckill_active_id; + } + $product['price'] = $settleParams['data']['price']; + $product['mer_labels'] = $data['mer_labels']; + app()->make(SpuRepository::class)->create($product, $result->product_id, $activity_id, $productType); + } + $product = $result; + event('product.create',compact('product')); + return $result->product_id; + }); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @param array $data + */ + public function edit(int $id, array $data, int $merId, int $productType, $conType = 0) + { + if (!$data['spec_type']) { + $data['attr'] = []; + if (count($data['attrValue']) > 1) throw new ValidateException('单规格商品属性错误'); + } + event('product.update.before', compact('id','data','merId','productType','conType')); + $spuData = $product = $this->setProduct($data); + $settleParams = $this->setAttrValue($data, $id, $productType, 1,$merId); + $settleParams['cate'] = $this->setMerCate($data['mer_cate_id'], $id, $merId); + $settleParams['attr'] = $this->setAttr($data['attr'], $id); + $content = [ + 'content' => $conType ? json_encode($data['content']) : $data['content'] , + 'type' => $conType + ]; + $spuData['price'] = $settleParams['data']['price']; + $spuData['mer_id'] = $merId; + $spuData['mer_labels'] = $data['mer_labels']; + Db::transaction(function () use ($id, $data, $productType, $settleParams,$content,$product,$spuData,$merId) { + $this->save($id, $settleParams, $content, $product, $productType); + if ($productType == 1) { //秒杀商品 + $dat = $this->setSeckillProduct($data); + app()->make(StoreSeckillActiveRepository::class)->updateByProduct($id, $dat); + } + if ($productType == 0) { + $make = app()->make(ParameterValueRepository::class); + $make->clear($id, 'product_id'); + $make->create($id, $data['params'] ?? [], $merId); + } + app()->make(SpuRepository::class)->baseUpdate($spuData, $id, 0, $productType); + event('product.update',compact('id')); + app()->make(SpuRepository::class)->changeStatus($id, $productType); + }); + } + + public function freeTrial(int $id, array $data, int $merId) + { + if (!$data['spec_type']) { + $data['attr'] = []; + if (count($data['attrValue']) > 1) throw new ValidateException('单规格商品属性错误'); + } + $res = $this->dao->get($id); + $data['svip_price_type'] = $res['svip_price_type']; + $settleParams = $this->setAttrValue($data, $id, 0, 1); + $settleParams['cate'] = $this->setMerCate($data['mer_cate_id'], $id, $merId); + $settleParams['attr'] = $this->setAttr($data['attr'], $id); + $data['price'] = $settleParams['data']['price']; + unset($data['attrValue'],$data['attr'],$data['mer_cate_id']); + $ret = app()->make(SpuRepository::class)->getSearch(['product_id' => $id, 'product_type' => 0,])->find(); + Db::transaction(function () use ($id, $data, $settleParams,$ret) { + $this->save($id, $settleParams, null, [], 0); + app()->make(SpuRepository::class)->update($ret->spu_id,['price' => $data['price']]); + Queue(SendSmsJob::class, ['tempId' => 'PRODUCT_INCREASE', 'id' => $id]); + }); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + */ + public function destory($id) + { + (app()->make(ProductAttrRepository::class))->clearAttr($id); + (app()->make(ProductAttrValueRepository::class))->clearAttr($id); + (app()->make(ProductContentRepository::class))->clearAttr($id, null); + (app()->make(ProductCateRepository::class))->clearAttr($id); + $this->dao->delete($id, true); + } + + /** + * @Author:Qinii + * @Date: 2020/5/20 + * @param $id + * @param $spec_type + * @param $settleParams + * @param $content + * @return int + */ + public function save($id, $settleParams, $content, $data = [], $productType = 0) + { + (app()->make(ProductAttrRepository::class))->clearAttr($id); + (app()->make(ProductAttrValueRepository::class))->clearAttr($id); + (app()->make(ProductCateRepository::class))->clearAttr($id); + if (isset($settleParams['cate'])) (app()->make(ProductCateRepository::class)->insert($settleParams['cate'])); + if (isset($settleParams['attr'])) (app()->make(ProductAttrRepository::class))->insert($settleParams['attr']); + + if (isset($settleParams['attrValue'])) { + $arr = array_chunk($settleParams['attrValue'], 30); + foreach ($arr as $item){ + app()->make(ProductAttrValueRepository::class)->insertAll($item); + } + } + if ($content){ + app()->make(ProductContentRepository::class)->clearAttr($id,$content['type']); + $this->dao->createContent($id, $content); + } + + if (isset($settleParams['data'])) { + $data['price'] = $settleParams['data']['price']; + $data['ot_price'] = $settleParams['data']['ot_price']; + $data['cost'] = $settleParams['data']['cost']; + $data['stock'] = $settleParams['data']['stock']; + $data['svip_price'] = $settleParams['data']['svip_price']; + } + $res = $this->dao->update($id, $data); + + if(isset($data['status']) && $data['status'] !== 1 ){ + $message = '您有1个新的'. ($productType ? '秒杀商品' : ($data['is_gift_bag'] ? '礼包商品' :'商品')) . '待审核'; + $type = $productType ? 'new_seckill' : ($data['is_gift_bag'] ? 'new_bag' :'new_product'); + SwooleTaskService::admin('notice', [ + 'type' => $type, + 'data' => [ + 'title' => '商品审核', + 'message' => $message, + 'id' => $id + ] + ]); + } + return $res; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @param array $data + * @return int + */ + public function adminUpdate(int $id, array $data) + { + Db::transaction(function () use ($id, $data) { + app()->make(ProductContentRepository::class)->clearAttr($id, 0); + $this->dao->createContent($id, ['content' => $data['content']]); + unset($data['content']); + $res = $this->dao->getWhere(['product_id' => $id], '*', ['seckillActive']); + $activity_id = $res['seckillActive']['seckill_active_id'] ?? 0; + app()->make(SpuRepository::class)->changRank($activity_id, $id, $res['product_type'], $data); + unset($data['star']); + return $this->dao->update($id, $data); + }); + } + + /** + * 格式化秒杀商品活动时间 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @return array + */ + public function setSeckillProduct(array $data) + { + $dat = [ + 'start_day' => $data['start_day'], + 'end_day' => $data['end_day'], + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'status' => 1, + 'once_pay_count' => $data['once_pay_count'], + 'all_pay_count' => $data['all_pay_count'], + ]; + if (isset($data['mer_id'])) $dat['mer_id'] = $data['mer_id']; + return $dat; + } + + /** + * 格式商品主体信息 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @return array + */ + public function setProduct(array $data) + { + $give_coupon_ids = ''; + if (isset($data['give_coupon_ids']) && !empty($data['give_coupon_ids'])) { + $gcoupon_ids = array_unique($data['give_coupon_ids']); + $give_coupon_ids = implode(',', $gcoupon_ids); + } + + if(isset($data['integral_rate'])){ + $integral_rate = $data['integral_rate']; + if($data['integral_rate'] < 0) $integral_rate = -1; + if($data['integral_rate'] > 100) $integral_rate = 100; + + } + + $result = [ + 'store_name' => $data['store_name'], + 'image' => $data['image'], + 'slider_image' => is_array($data['slider_image']) ? implode(',', $data['slider_image']) : '', + 'store_info' => $data['store_info'] ?? '', + 'keyword' => $data['keyword']??'', + 'brand_id' => $data['brand_id'] ?? 0, + 'cate_id' => $data['cate_id'] ?? 0, + 'unit_name' => $data['unit_name']??'件', + 'sort' => $data['sort'] ?? 0, + 'is_show' => $data['is_show'] ?? 0, + 'is_used' => (isset($data['status']) && $data['status'] == 1) ? 1 : 0, + 'is_good' => $data['is_good'] ?? 0, + 'video_link' => $data['video_link']??'', + 'temp_id' => $data['delivery_free'] ? 0 : ($data['temp_id'] ?? 0), + 'extension_type' => $data['extension_type']??0, + 'spec_type' => $data['spec_type'] ?? 0, + 'status' => $data['status']??0, + 'give_coupon_ids' => $give_coupon_ids, + 'mer_status' => $data['mer_status'], + 'guarantee_template_id' => $data['guarantee_template_id']??0, + 'is_gift_bag' => $data['is_gift_bag'] ?? 0, + 'integral_rate' => $integral_rate ?? 0, + 'delivery_way' => implode(',',$data['delivery_way']), + 'delivery_free' => $data['delivery_free'] ?? 0, + 'once_min_count' => $data['once_min_count'] ?? 0, + 'once_max_count' => $data['once_max_count'] ?? 0, + 'pay_limit' => $data['pay_limit'] ?? 0, + 'svip_price_type' => $data['svip_price_type'] ?? 0, + ]; + if (isset($data['mer_id'])) + $result['mer_id'] = $data['mer_id']; + if (isset($data['old_product_id'])) + $result['old_product_id'] = $data['old_product_id']; + if (isset($data['product_type'])) + $result['product_type'] = $data['product_type']; + if (isset($data['type']) && $data['type']) + $result['type'] = $data['type']; + if (isset($data['param_temp_id'])) + $result['param_temp_id'] = $data['param_temp_id']; + if (isset($data['extend'])) + $result['extend'] = $data['extend'] ? json_encode($data['extend'], JSON_UNESCAPED_UNICODE) :[]; + return $result; + } + + /** + * 格式商品商户分类 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @param int $productId + * @param int $merId + * @return array + */ + public function setMerCate(array $data, int $productId, int $merId) + { + $result = []; + foreach ($data as $value) { + $result[] = [ + 'product_id' => $productId, + 'mer_cate_id' => $value, + 'mer_id' => $merId, + ]; + } + return $result; + } + + /** + * 格式商品规格 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @param int $productId + * @return array + */ + public function setAttr(array $data, int $productId) + { + $result = []; + try{ + foreach ($data as $value) { + $result[] = [ + 'type' => 0, + 'product_id' => $productId, + "attr_name" => $value['value'] ?? $value['attr_name'], + 'attr_values' => implode('-!-', $value['detail']), + ]; + } + } catch (\Exception $exception) { + throw new ValidateException('商品规格格式错误'); + } + + return $result; + } + + /** + * 格式商品SKU + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @param int $productId + * @return mixed + */ + public function setAttrValue(array $data, int $productId, int $productType, int $isUpdate = 0,int $merId = 0) + { + $extension_status = systemConfig('extension_status'); + if ($isUpdate) { + $product = app()->make(ProductAttrValueRepository::class)->search(['product_id' => $productId])->select()->toArray(); + $oldSku = $this->detailAttrValue($product, null); + } + $price = $stock = $ot_price = $cost = $svip_price = 0; + try { + foreach ($data['attrValue'] as $value) { + $_svip_price = 0; + $sku = ''; + if (isset($value['detail']) && !empty($value['detail']) && is_array($value['detail'])) { + $sku = implode(',', $value['detail']); + } + $ot_price_ = $value['price']; + if (isset($value['active_price'])) { + $sprice = $value['active_price'] < 0 ? 0 : $value['active_price']; + } elseif (isset($value['presell_price'])) { + $sprice = $value['presell_price'] < 0 ? 0 : $value['presell_price']; + } elseif (isset($value['assist_price'])) { + $sprice = $value['assist_price'] < 0 ? 0 : $value['assist_price']; + } else { + $ot_price_ = $value['ot_price']; + $sprice = ($value['price'] < 0) ? 0 : $value['price']; + } + if ($data['svip_price_type'] == 2) { + $_svip_price = $value['svip_price']; + $svip_price = !$svip_price ? $value['svip_price'] : (($svip_price > $value['svip_price']) ? $value['svip_price'] : $svip_price); + } + + $cost = !$cost ? $value['cost'] : (($cost > $value['cost']) ?$cost: $value['cost']); + $price = !$price ? $sprice : (($price > $sprice) ? $sprice : $price); + $ot_price = !$ot_price ? $ot_price_ : (($ot_price > $ot_price_) ? $ot_price : $ot_price_); + + $unique = $this->setUnique($productId, $sku, $productType); + $result['attrValue'][] = [ + 'detail' => json_encode($value['detail'] ?? ''), + "bar_code" => $value["bar_code"] ?? '', + "image" => $value["image"] ?? '', + "cost" => $value['cost'] ? (($value['cost'] < 0) ? 0 : $value['cost']) : 0, + "price" => $value['price'] ? (($value['price'] < 0) ? 0 : $value['price']) : 0, + "volume" => isset($value['volume']) ? ($value['volume'] ? (($value['volume'] < 0) ? 0 : $value['volume']) : 0) :0, + "weight" => isset($value['weight']) ? ($value['weight'] ? (($value['weight'] < 0) ? 0 : $value['weight']) : 0) :0, + "stock" => $value['stock'] ? (($value['stock'] < 0) ? 0 : $value['stock']) : 0, + "ot_price" => $value['ot_price'] ? (($value['ot_price'] < 0) ? 0 : $value['ot_price']) : 0, + "extension_one" => $extension_status ? ($value['extension_one'] ?? 0) : 0, + "extension_two" => $extension_status ? ($value['extension_two'] ?? 0) : 0, + "product_id" => $productId, + "type" => 0, + "sku" => $sku, + "unique" => $unique, + 'sales' => $isUpdate ? ($oldSku[$sku]['sales'] ?? 0) : 0, + 'svip_price' => $_svip_price, + 'mer_id' => $merId, + ]; + $stock = $stock + intval($value['stock']); + } + $result['data'] = [ + 'price' => $price , + 'stock' => $stock, + 'ot_price' => $ot_price, + 'cost' => $cost, + 'svip_price' => $svip_price, + ]; + } catch (\Exception $exception) { + throw new ValidateException('规格错误 :'.$exception->getMessage()); + } + return $result; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @param string $sku + * @param int $type + * @return string + */ + public function setUnique(int $id, $sku, int $type) + { + $str = strval($type); + $result=strlen($str); + $length=12-$result; + return $unique = substr(md5($sku . $id), 12, $length) . $type; + // $has = (app()->make(ProductAttrValueRepository::class))->merUniqueExists(null, $unique); + // return $has ? false : $unique; + } + + + /** + * TODO 后台管理需要的商品详情 + * @param int $id + * @param int|null $activeId + * @return array|\think\Model|null + * @author Qinii + * @day 2020-11-24 + */ + public function getAdminOneProduct(int $id, ?int $activeId, $conType = 0) + { + $with = ['attr', 'attrValue', 'oldAttrValue', 'merCateId.category', 'storeCategory', 'brand', 'temp', 'seckillActive', + 'content' => function($query) use($conType){ + $query->where('type',$conType); + }, + 'merchant'=> function($query){ + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + }, + 'guarantee.templateValue.value', + + ]; + + $data = $this->dao->geTrashedtProduct($id)->with($with)->find(); + + $data['delivery_way'] = empty($data['delivery_way']) ? [2] : explode(',',$data['delivery_way']); + $data['extend'] = empty($data['extend']) ? [] : json_decode($data['extend']); + $make_order = app()->make(StoreCouponRepository::class); + $where = [['coupon_id', 'in', $data['give_coupon_ids']]]; + $data['coupon'] = $make_order->selectWhere($where, 'coupon_id,title')->toArray(); + $spu_make = app()->make(SpuRepository::class); + + $append = []; + if ($data['product_type'] == 0) { + $append = ['us_status', 'params']; + $activeId = 0; + } + if ($data['product_type'] == 1){ + $activeId = $data->seckillActive->seckill_active_id; + $make = app()->make(StoreOrderRepository::class); + $append = ['us_status','seckill_status']; + } + if ($data['product_type'] == 2) $make = app()->make(ProductPresellSkuRepository::class); + if ($data['product_type'] == 3) $make = app()->make(ProductAssistSkuRepository::class); + if ($data['product_type'] == 4) $make = app()->make(ProductGroupSkuRepository::class); + + $spu_where = ['activity_id' => $activeId, 'product_type' => $data['product_type'], 'product_id' => $id]; + $spu = $spu_make->getSearch($spu_where)->find(); + $data['star'] = $spu['star'] ?? ''; + $data['mer_labels'] = $spu['mer_labels'] ?? ''; + $data['sys_labels'] = $spu['sys_labels'] ?? ''; + + $data->append($append); + $mer_cat = []; + if (isset($data['merCateId'])) { + foreach ($data['merCateId'] as $i) { + $mer_cat[] = $i['mer_cate_id']; + } + } + $data['mer_cate_id'] = $mer_cat; + + foreach ($data['attr'] as $k => $v) { + $data['attr'][$k] = [ + 'value' => $v['attr_name'], + 'detail' => $v['attr_values'] + ]; + } + $attrValue = (in_array($data['product_type'], [3, 4])) ? $data['oldAttrValue'] : $data['attrValue']; + unset($data['oldAttrValue'], $data['attrValue']); + $arr = []; + if (in_array($data['product_type'], [1, 3])) $value_make = app()->make(ProductAttrValueRepository::class); + foreach ($attrValue as $key => $item) { + + if ($data['product_type'] == 1) { + $value = $value_make->getSearch(['sku' => $item['sku'], 'product_id' => $data['old_product_id']])->find(); + $old_stock = $value['stock']; + $item['sales'] = $make->skuSalesCount($item['unique']); + } + if ($data['product_type'] == 2) { + $item['presellSku'] = $make->getSearch(['product_presell_id' => $activeId, 'unique' => $item['unique']])->find(); + if (is_null($item['presellSku'])) continue; + } + if ($data['product_type'] == 3) { + $item['assistSku'] = $make->getSearch(['product_assist_id' => $activeId, 'unique' => $item['unique']])->find(); + if (is_null($item['assistSku'])) + continue; + } + if ($data['product_type'] == 4) { + $item['_sku'] = $make->getSearch(['product_group_id' => $activeId, 'unique' => $item['unique']])->find(); + if (is_null($item['_sku'])) + continue; + } + $sku = explode(',', $item['sku']); + $item['old_stock'] = $old_stock ?? $item['stock']; + foreach ($sku as $k => $v) { + $item['value' . $k] = $v; + } + $arr[] = $item; + } + + $data['attrValue'] = $arr; + + $content = $data['content']['content'] ?? ''; + if ($conType) $content = json_decode($content); + unset($data['content']); + $data['content'] = $content; + return $data; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $type + * @param int|null $merId + * @return array + */ + public function switchType($type, ?int $merId = 0, $productType = 0) + { + $stock = 0; + if ($merId) $stock = merchantConfig($merId, 'mer_store_stock'); + switch ($type) { + case 1: + $where = ['is_show' => 1, 'status' => 1,]; + break; + case 2: + $where = ['is_show' => 0, 'status' => 1]; + break; + case 3: + $where = ['is_show' => 1, 'stock' => 0, 'status' => 1]; + break; + case 4: + $where = ['stock' => $stock ? $stock : 0, 'status' => 1]; + break; + case 5: + $where = ['soft' => true]; + break; + case 6: + $where = ['status' => 0]; + break; + case 7: + $where = ['status' => -1]; + break; + case 20: + $where = ['status' => 1]; + break; + default: + // $where = ['is_show' => 1, 'status' => 1]; + break; + } + if ($productType == 0) { + $where['product_type'] = $productType; + if (!$merId) $where['is_gift_bag'] = 0; + } + if ($productType == 1||$productType==98) { + $where['product_type'] = $productType; + } + if ($productType == 10) { + $where['is_gift_bag'] = 1; + } + if (!$merId) $where['star'] = ''; + return $where; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int|null $merId + * @return array + */ + public function getFilter(?int $merId, $name = '', $productType = 0) + { + $result = []; + $result[] = [ + 'type' => 1, + 'name' => '出售中' . $name, + 'count' => $this->dao->search($merId, $this->switchType(1, $merId, $productType))->count() + ]; + $result[] = [ + 'type' => 2, + 'name' => '仓库中' . $name, + 'count' => $this->dao->search($merId, $this->switchType(2, $merId, $productType))->count() + ]; + if ($merId) { + $result[] = [ + 'type' => 3, + 'name' => '已售罄' . $name, + 'count' => $this->dao->search($merId, $this->switchType(3, $merId, $productType))->count() + ]; + $result[] = [ + 'type' => 4, + 'name' => '警戒库存', + 'count' => $this->dao->search($merId, $this->switchType(4, $merId, $productType))->count() + ]; + } + $result[] = [ + 'type' => 6, + 'name' => '待审核' . $name, + 'count' => $this->dao->search($merId, $this->switchType(6, $merId, $productType))->count() + ]; + $result[] = [ + 'type' => 7, + 'name' => '审核未通过' . $name, + 'count' => $this->dao->search($merId, $this->switchType(7, $merId, $productType))->count() + ]; + if ($merId) { + $result[] = [ + 'type' => 5, + 'name' => '回收站' . $name, + 'count' => $this->dao->search($merId, $this->switchType(5, $merId, $productType))->count() + ]; + } + return $result; + } + + /** + * TODO 商户商品列表 + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + */ + public function getList(?int $merId, array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where)->with(['merCateId.category', 'storeCategory', 'brand']); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field($this->filed)->select(); + + $data->append(['us_status']); + + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count', 'list'); + } + + /** + * TODO 商户秒杀商品列表 + * @param int|null $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-08-04 + */ + public function getSeckillList(?int $merId, array $where, int $page, int $limit) + { + $make = app()->make(StoreOrderRepository::class); + $query = $this->dao->search($merId, $where)->with(['merCateId.category', 'storeCategory', 'brand', 'attrValue ', 'seckillActive']); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field($this->filed)->order('sort DESC')->select() + ->each(function ($item) use ($make, $where) { + $result = $this->getSeckillAttrValue($item['attrValue'], $item['old_product_id']); + $item['stock'] = $result['stock']; + return $item; + }); + $data->append(['seckill_status', 'us_status']); + + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + + return compact('count', 'list'); + } + + /** + * TODO 平台商品列表 + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + */ + public function getAdminList(?int $merId, array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where)->with([ + 'merCateId.category', + 'storeCategory', + 'brand', + 'merchant', + ]); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field($this->admin_filed)->select(); + $data->append([ 'us_status']); + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count', 'list'); + } + + /** + * TODO 平台秒杀商品列表 + * @param int|null $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-08-04 + */ + public function getAdminSeckillList(?int $merId, array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where)->with([ + 'merCateId.category', + 'storeCategory', + 'brand', + 'merchant', + 'seckillActive', + 'attrValue', + ]); + $count = $query->count(); + $data = $query->page($page, $limit) + ->field('Product.*,U.star,U.rank,U.sys_labels') + ->select() + ->each(function ($item) use ($where) { + $result = $this->getSeckillAttrValue($item['attrValue'], $item['old_product_id']); + $item['stock'] = $result['stock']; + $item['sales'] = app()->make(StoreOrderRepository::class)->seckillOrderCounut($item['product_id']); + return $item; + }); + $data->append(['seckill_status', 'us_status']); + + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @param array $where + * @param int $page + * @param int $limit + * @param $userInfo + * @return array + */ + public function getApiSearch($merId, array $where, int $page, int $limit, $userInfo) + { + $where = array_merge($where, $this->dao->productShow()); + //搜索记录 + if (isset($where['keyword']) && !empty($where['keyword'])) + app()->make(UserVisitRepository::class)->searchProduct( + $userInfo ? $userInfo['uid'] : 0, + $where['keyword'], + (int)($where['mer_id'] ?? 0) + ); + $query = $this->dao->search($merId, $where)->with(['merchant', 'issetCoupon']); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->field($this->admin_filed)->select(); + $append[] = 'max_extension'; + if ($this->getUserIsPromoter($userInfo)) $list->append($append); + return compact('count', 'list'); + } + + /** + * TODO 秒杀列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-08-04 + */ + public function getApiSeckill(array $where, int $page, int $limit) + { + $field = 'Product.product_id,Product.mer_id,is_new,U.keyword,brand_id,U.image,U.product_type,U.store_name,U.sort,U.rank,star,rate,reply_count,sales,U.price,cost,ot_price,stock,extension_type,care_count,unit_name,U.create_time'; + $make = app()->make(StoreOrderRepository::class); + $res = app()->make(StoreSeckillTimeRepository::class)->getBginTime($where); + $count = 0; + $list = []; + + if ($res) { + $where = [ + 'start_time' => $res['start_time'], + 'end_time' => $res['end_time'], + 'day' => date('Y-m-d', time()), + 'star' => '', + 'mer_id' => $where['mer_id'] + ]; + $query = $this->dao->seckillSearch($where)->with(['seckillActive']); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->field($field)->select() + ->each(function ($item) use ($make) { + $item['sales'] = $make->seckillOrderCounut($item['product_id']); + $item['stop'] = $item->end_time; + return $item; + }); + } + return compact('count', 'list'); + } + + /** + * TODO 平台礼包列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-06-01 + */ + public function getBagList(array $where, int $page, int $limit) + { + $query = $this->dao->search(null, $where)->with(['merCateId.category', 'storeCategory', 'brand', 'merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name,product_score,service_score,postage_score,status,care_count,is_trader'); + }]); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->setOption('field', [])->field($this->filed)->select(); + + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @param array $where + * @return mixed + */ + public function getBrandByCategory(array $where) + { + $mer_id = $where['mer_id'] ? $where['mer_id'] : null; + unset($where['mer_id']); + $query = $this->dao->search($mer_id, $where); + return $query->group('brand_id')->column('brand_id'); + } + + /** + * api 获取商品详情 + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @param $userInfo + */ + public function detail(int $id, $userInfo,$product_type) + { + $where = [ + 'is_show' => 1, + 'status' => 1, + 'is_used' => 1, + 'mer_status' => 1, + 'product_id' => $id + ]; + return $this->apiProductDetail($where, $product_type, null, $userInfo); + } + + + /** + * TODO api秒杀商品详情 + * @param int $id + * @author Qinii + * @day 2020-08-05 + */ + public function seckillDetail(int $id,$userInfo) + { + $where = $this->seckillShow(); + $where['product_id'] = $id; + return $this->apiProductDetail($where, 1, null,$userInfo); + } + + public function apiProductDetail(array $where, int $productType, ?int $activityId, $userInfo = null) + { + + $field = 'is_show,product_id,mer_id,image,slider_image,store_name,store_info,unit_name,price,cost,ot_price,stock,sales,video_link,product_type,extension_type,old_product_id,rate,guarantee_template_id,temp_id,once_max_count,pay_limit,once_min_count,integral_rate,delivery_way,delivery_free,type,cate_id,svip_price_type,svip_price,mer_svip_status'; + $with = [ + 'attr', + 'content' => function($query) { + $query->order('type ASC'); + }, + 'attrValue', + 'oldAttrValue', + 'merchant' => function ($query) { + $query->with(['type_name'])->append(['isset_certificate','services_type']); + }, + 'seckillActive' => function ($query) { + $query->field('start_day,end_day,start_time,end_time,product_id'); + }, + 'temp' + ]; + + $append = ['guaranteeTemplate','params']; + $where['product_type'] = $productType; + $res = $this->dao->getWhere($where, $field, $with); + if (!$res) return []; + switch ($res['product_type']) { + case 0: + case 98: + $append[] = 'max_integral'; + $append[] = 'show_svip_info'; + break; + case 1: + $_where = $this->dao->productShow(); + $_where['product_id'] = $res['old_product_id']; + $oldProduct = $this->dao->getWhere($_where); + $result = $this->getSeckillAttrValue($res['attrValue'], $res['old_product_id']); + $res['attrValue'] = $result['item']; + + $res['stock'] = $result['stock']; + $res['stop'] = strtotime(date('Y-m-d', time()) . $res['seckillActive']['end_time'] . ':00:00'); + $res['sales'] = app()->make(StoreOrderRepository::class)->seckillOrderCounut($where['product_id']); + $res['quota'] = $this->seckillStock($where['product_id']); + $res['old_status'] = $oldProduct ? 1 : 0; + $append[] = 'seckill_status'; + break; + default: + break; + } + + if ($userInfo) { + try { + $isRelation = app()->make(UserRelationRepository::class)->getUserRelation(['type_id' => $activityId ?? $where['product_id'], 'type' => $res['product_type']], $userInfo['uid']); + } catch (\Exception $e) { + $isRelation = false; + } + if ($this->getUserIsPromoter($userInfo) && $productType == 0) { + $append[] = 'max_extension'; + $append[] = 'min_extension'; + } + } + + $attr = $this->detailAttr($res['attr']); + $attrValue = (in_array($res['product_type'], [3, 4])) ? $res['oldAttrValue'] : $res['attrValue']; + $sku = $this->detailAttrValue($attrValue, $userInfo, $productType, $activityId); + + $res['isRelation'] = $isRelation ?? false; + $care = false; + if ($userInfo) { + $care = app()->make(MerchantRepository::class)->getCareByUser($res['mer_id'], $userInfo->uid); + } + $res['merchant']['top_banner'] = merchantConfig($res['mer_id'], 'mer_pc_top'); + $res['merchant']['care'] = $care; + $res['replayData'] = null; + if (systemConfig('sys_reply_status')){ + $res['replayData'] = app()->make(ProductReplyRepository::class)->getReplyRate($res['product_id']); + $append[] = 'topReply'; + } + unset($res['attr'], $res['attrValue'], $res['oldAttrValue'], $res['seckillActive']); + if (count($attr) > 0) { + $firstSku = []; + foreach ($attr as $item) { + $firstSku[] = $item['attr_values'][0]; + } + $firstSkuKey = implode(',', $firstSku); + if (isset($sku[$firstSkuKey])) { + $sku = array_merge([$firstSkuKey => $sku[$firstSkuKey]], $sku); + } + } + $res['attr'] = $attr; + $res['sku'] = $sku; + $res->append($append); + + if ($res['content'] && $res['content']['type'] == 1) { + $res['content']['content'] = json_decode($res['content']['content']); + } + + $res['merchant']['recommend'] = $this->getRecommend($res['product_id'], $res['mer_id']); + $spu = app()->make(SpuRepository::class)->getSpuData( + $activityId ?: $res['product_id'], + $productType, + 0 + ); + $res['spu_id'] = $spu->spu_id; + if (systemConfig('community_status')) { + $res['community'] = app()->make(CommunityRepository::class)->getDataBySpu($spu->spu_id); + } + //热卖排行 + if (systemConfig('hot_ranking_switch') && $res['spu_id']) { + $hot = $this->getHotRanking($res['spu_id'], $res['cate_id']); + $res['top_name'] = $hot['top_name'] ?? ''; + $res['top_num'] = $hot['top_num'] ?? 0; + $res['top_pid'] = $hot['top_pid'] ?? 0; + } + //活动氛围图 + if (in_array($res['product_type'],[0,2,4])){ + $active = app()->make(StoreActivityRepository::class)->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_ATMOSPHERE,$res['spu_id'],$res['cate_id'],$res['mer_id']); + if ($active) $res['atmosphere_pic'] = $active['pic']; + } + return $res; + } + + + /** + * TODO 热卖排行 + * @param int $spuId + * @param int $cateId + * @return array + * @author Qinii + */ + public function getHotRanking(int $spuId, int $cateId) + { + $data = []; + //热卖排行 + $lv = systemConfig('hot_ranking_lv') ?:0; + $categoryMake = app()->make(StoreCategoryRepository::class); + $cate = $categoryMake->getWhere(['store_category_id' => $cateId]); + if ($lv != 2 && $cate) $cateId = $lv == 1 ? $cate->pathIds[2] : $cate->pathIds[1]; + $RedisCacheService = app()->make(RedisCacheService::class); + $prefix = env('QUEUE_NAME','merchant').'_hot_ranking_'; + $key = ( $prefix.'top_item_'.$cateId.'_'.$spuId); + $k1 = $RedisCacheService->keys($key); + if ($k1) { + $top = $RedisCacheService->handler()->get($key); + $top = json_decode($top); + $data['top_name'] = $top[0]; + $data['top_num'] = $top[1]; + $data['top_pid'] = $cateId; + } + return $data; + } + + /** + * TODO 商户下的推荐 + * @param $productId + * @param $merId + * @return array + * @author Qinii + * @day 12/7/21 + */ + public function getRecommend($productId,$merId) + { + $make = app()->make(ProductCateRepository::class); + $product_id = []; + if ($productId) { + $catId = $make->getSearch(['product_id' => $productId])->column('mer_cate_id'); + $product_id = $make->getSearch([])->whereIn('mer_cate_id',$catId)->column('product_id'); + } + + $query = $this->dao->getSearch([]) + ->where($this->dao->productShow()) + ->when($productId,function($query) use ($productId) { + $query->where('product_id','<>',$productId); + }) + ->when($product_id,function($query) use ($product_id) { + $query->whereIn('product_id',$product_id); + }) + ->where('mer_id',$merId); + $data = []; + $count = $query->count(); + + if ($count < 3) { + $productIds[] = $productId; + $data = $this->dao->getSearch([]) + ->where($this->dao->productShow()) + ->whereNotIn('product_id',$productIds) + ->where('mer_id', $merId) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,sales,create_time') + ->order('sort DESC,create_time DESC') + ->limit((3 - $count)) + ->select()->toArray(); + } + + if ($count > 0 ){ + $count = $count > 3 ? 3 : $count; + $res = $query->setOption('field',[])->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,sales,create_time') + ->order('sort DESC,create_time DESC') + ->limit($count) + ->select()->toArray(); + $data = array_merge($data, $res); + } + return $data; + } + + + + /** + * TODO 单商品属性 + * @param $data + * @return array + * @author Qinii + * @day 2020-08-05 + */ + public function detailAttr($data, $preview = 0, $user = null) + { + $attr = []; + foreach ($data as $key => $item) { + if ($item instanceof Arrayable) { + $attr[$key] = $item->toArray(); + } + $arr = []; + if ($preview) { + $item['attr_values'] = explode('-!-', $item['attr_values']); + $attr[$key]['attr_values'] = $item['attr_values']; + } + $values = $item['attr_values']; + foreach ($values as $i => $value) { + $arr[] = [ + 'attr' => $value, + 'check' => false + ]; + } + $attr[$key]['product_id'] = $item['product_id']; + $attr[$key]['attr_name'] = $item['attr_name']; + $attr[$key]['attr_value'] = $arr; + $attr[$key]['attr_values'] = $values; + } + return $attr; + } + + /** + * TODO 获取秒杀商品的库存数 + * @param array $data + * @param int $oldProductId + * @return array + * @author Qinii + * @day 2020-11-12 + */ + public function getSeckillAttrValue($data, $oldProductId) + { + /** + * 秒杀商品限购数量 + * 原商品库存 > 限购数 + * 销量 = 订单总数 - 退款退货 - (未发货且仅退款) + * 限购数 = 限购数 - 销量 + * 原商品库存 < 限购数 + * 限购数 = 原商品库存 + */ + $make = app()->make(ProductAttrValueRepository::class); + $order_make = app()->make(StoreOrderRepository::class); + $stock = 0; + $item = []; + foreach ($data as $k => $value) { + $where = [ + 'sku' => $value['sku'], + 'product_id' => $oldProductId + ]; + //愿商品库存信息 + $attr = $make->getWhere($where); + if ($attr) { + $value['stock'] = ($attr['stock'] < $value['stock']) ? + $attr['stock'] : + $value['stock'] - $order_make->seckillSkuOrderCounut($value['unique']); + } + $stock = $stock + $value['stock']; + $item[] = $value; + } + return compact('item', 'stock'); + } + /** + * TODO 单商品sku + * @param $data + * @param $userInfo + * @return array + * @author Qinii + * @day 2020-08-05 + */ + public function detailAttrValue($data, $userInfo, $productType = 0, $artiveId = null, $svipInfo = []) + { + $sku = []; + $make_presll = app()->make(ProductPresellSkuRepository::class); + $make_assist = app()->make(ProductAssistSkuRepository::class); + $make_group = app()->make(ProductGroupSkuRepository::class); + foreach ($data as $value) { + $_value = [ + 'sku' => $value['sku'], + 'price' => $value['price'], + 'stock' => $value['stock'], + 'image' => $value['image'], + 'weight' => $value['weight'], + 'volume' => $value['volume'], + 'sales' => $value['sales'], + 'unique' => $value['unique'], + 'bar_code' => $value['bar_code'], + ]; + if($productType == 0 ){ + $_value['ot_price'] = $value['ot_price']; + $_value['svip_price'] = $value['svip_price']; + } + if ($productType == 2) { + $_sku = $make_presll->getSearch(['product_presell_id' => $artiveId, 'unique' => $value['unique']])->find(); + if (!$_sku) continue; + $_value['price'] = $_sku['presell_price']; + $_value['stock'] = $_sku['stock']; + $_value['down_price'] = $_sku['down_price']; + } + //助力 + if ($productType == 3) { + $_sku = $make_assist->getSearch(['product_assist_id' => $artiveId, 'unique' => $value['unique']])->find(); + if (!$_sku) continue; + $_value['price'] = $_sku['assist_price']; + $_value['stock'] = $_sku['stock']; + } + //拼团 + if ($productType == 4) { + $_sku = $make_group->getSearch(['product_group_id' => $artiveId, 'unique' => $value['unique']])->find(); + if (!$_sku) continue; + $_value['price'] = $_sku['active_price']; + $_value['stock'] = $_sku['stock']; + } + //推广员 + if ($this->getUserIsPromoter($userInfo)) { + $_value['extension_one'] = $value->bc_extension_one; + $_value['extension_two'] = $value->bc_extension_two; + } + $sku[$value['sku']] = $_value; + } + return $sku; + } + + + /** + * TODO 秒杀商品库存检测 + * @param int $productId + * @return bool|int + * @author Qinii + * @day 2020-08-05 + */ + public function seckillStock(int $productId) + { + $product = $this->dao->getWhere(['product_id' => $productId], '*', ['attrValue']); + $count = app()->make(StoreOrderRepository::class)->seckillOrderCounut($productId); + if ($product['stock'] > $count) { + $make = app()->make(ProductAttrValueRepository::class); + foreach ($product['attrValue'] as $item) { + $attr = [ + ['sku', '=', $item['sku']], + ['product_id', '=', $product['old_product_id']], + ['stock', '>', 0], + ]; + if ($make->getWhereCount($attr)) return true; + } + } + return false; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $userInfo + * @return bool + */ + public function getUserIsPromoter($userInfo) + { + return (isset($userInfo['is_promoter']) && $userInfo['is_promoter'] && systemConfig('extension_status')) ? true : false; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $userInfo + * @param int|null $merId + * @param $page + * @param $limit + * @return array + */ + public function recommend($userInfo, ?int $merId, $page, $limit) + { + $where = ['order' => 'sales']; + if (!is_null($userInfo)) { + $cate_ids = app()->make(UserVisitRepository::class)->getRecommend($userInfo['uid']); + if ($cate_ids) $where = ['cate_ids' => $cate_ids]; + } + $where = array_merge($where, $this->switchType(1, $merId, 0), $this->dao->productShow()); + $query = $this->dao->search($merId, $where); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->with(['issetCoupon', 'merchant'])->select(); + + return compact('count', 'list'); + } + + /** + * 检测是否有效 + * @Author:Qinii + * @Date: 2020/6/1 + * @param $id + * @return mixed + */ + public function getOne($id) + { + $data = ($this->dao->getWhere([$this->dao->getPk() => $id])); + if (!is_null($data) && $data->check()) return $data; + return false; + } + + /** + * TODO 上下架 / 显示 + * @param $id + * @param $status + * @author Qinii + * @day 2022/11/12 + */ + public function switchShow($id, $status, $field, $merId = 0) + { + $where['product_id'] = $id; + if ($merId) $where['mer_id'] = $merId; + $product = $this->dao->getWhere($where); + if (!$product) throw new ValidateException('数据不存在'); + if ($status == 1 && $product['product_type'] == 2) + throw new ValidateException('商品正在参与预售活动'); + if ($status == 1 && $product['product_type'] == 3) + throw new ValidateException('商品正在参与助力活动'); + $this->dao->update($id,[$field => $status]); + app()->make(SpuRepository::class)->changeStatus($id,$product->product_type); + } + + public function batchSwitchShow($id, $status, $field, $merId = 0) + { + $where['product_id'] = $id; + if ($merId) $where['mer_id'] = $merId; + $products = $this->dao->getSearch([])->where('product_id','in', $id)->select(); + if (!$products) + throw new ValidateException('数据不存在'); + foreach ($products as $product) { + $product_type = $product['product_type']; + if ($merId && $product['mer_id'] !== $merId) + throw new ValidateException('商品不属于您'); + if ($status == 1 && $product['product_type'] == 2) + throw new ValidateException('ID:'.$product->product_id . ' 商品正在参与预售活动'); + if ($status == 1 && $product['product_type'] == 3) + throw new ValidateException('ID:'.$product->product_id . ' 商品正在参与助力活动'); + } + $this->dao->updates($id,[$field => $status]); + Queue::push(ChangeSpuStatusJob::class,['id' => $id,'product_type'=> $product_type]); + } + + /** + * TODO 商品审核 + * @param $id + * @param $data + * @author Qinii + * @day 2022/11/14 + */ + public function switchStatus($id,$data) + { + $product = $this->getSearch([])->find($id); + $this->dao->update($id, $data); + $status = $data['status']; + $type = self::NOTIC_MSG[$data['status']][$product['product_type']]; + $message = '您有1个' . ($product['product_type'] ? '秒杀商品' : '商品') . self::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $status == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $product['product_id'] + ] + ], $product['mer_id']); + app()->make(SpuRepository::class)->changeStatus($id,$product->product_type); + } + + /** + * TODO 审核操作 + * @param array $id + * @param array $data + * @param $product_type + * @author Qinii + * @day 2022/9/6 + */ + public function batchSwitchStatus(array $id,array $data) + { + $productData = $this->getSearch([])->where('product_id','in', $id)->select(); + foreach ($productData as $product) { + $product_type = $product['product_type']; + $type = self::NOTIC_MSG[$data['status']][$product['product_type']]; + $message = '您有1个' . ($product['product_type'] ? '秒杀商品' : '商品') . self::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $data['status'] == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $product['product_id'] + ] + ], $product['mer_id']); + } + $this->dao->updates($id, $data); + Queue(ChangeSpuStatusJob::class, ['id' => $id, 'product_type' => $product_type]); + event('product.status',compact('id','data')); + } + + + public function wxQrCode(int $productId, int $productType, User $user) + { + $name = md5('pwx' . $productId . $productType . $user->uid . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $make = app()->make(QrcodeService::class); + $link = ''; + switch ($productType) { + case 0: //普通商品 + $link = '/pages/goods_details/index'; + break; + case 1: //秒杀商品 + $link = '/pages/activity/goods_seckill_details/index'; + break; + case 2: //预售商品 + $link = '/pages/activity/presell_details/index'; + break; + case 3: //助力商品 + $link = 'pages/activity/assist_detail/index'; + break; + case 4: //拼团商品 + $link = '/pages/activity/combination_details/index'; + break; + case 40: //拼团商品2 + $link = '/pages/activity/combination_status/index'; + break; + default: + return false; + } + $link = $link . '?id=' . $productId . '&spid=' . $user['uid']; + $key = 'p' . $productType . '_' . $productId . '_' . $user['uid']; + return $make->getWechatQrcodePath($name, $link, false, $key); + } + + public function routineQrCode(int $productId, int $productType, User $user) + { + //小程序 + $name = md5('sprt' . $productId . $productType . $user->uid . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $make = app()->make(QrcodeService::class); + $params = 'id=' . $productId . '&spid=' . $user['uid']; + $link = ''; + switch ($productType) { + case 0: //普通商品 + $link = 'pages/goods_details/index'; + break; + case 1: //秒杀商品 + $link = 'pages/activity/goods_seckill_details/index'; + break; + case 2: //预售商品 + $link = 'pages/activity/presell_details/index'; + break; + case 4: //拼团商品 + $link = 'pages/activity/combination_details/index'; + break; + case 40: //拼团商品2 + $link = 'pages/activity/combination_status/index'; + break; + } + + return $make->getRoutineQrcodePath($name, $link, $params); + } + + /** + * TODO 礼包是否超过数量限制 + * @param $merId + * @return bool + * @author Qinii + * @day 2020-06-25 + */ + public function checkMerchantBagNumber($merId) + { + $where = ['is_gift_bag' => 1]; + $promoter_bag_number = systemConfig('max_bag_number'); + $count = $this->dao->search($merId, $where)->count(); + if (is_null($promoter_bag_number) || ($promoter_bag_number > $count)) return true; + return false; + } + + public function orderProductIncStock($order, $cart, $productNum = null) + { + $productNum = $productNum ?? $cart['product_num']; + Db::transaction(function () use ($order, $cart, $productNum) { + $productAttrValueRepository = app()->make(ProductAttrValueRepository::class); + if ($cart['product_type'] == '1') { + $oldId = $cart['cart_info']['product']['old_product_id']; + $productAttrValueRepository->incSkuStock($oldId, $cart['cart_info']['productAttr']['sku'], $productNum); + $this->dao->incStock($oldId, $productNum); + } else if ($cart['product_type'] == '2') { + $presellSku = app()->make(ProductPresellSkuRepository::class); + $presellSku->incStock($cart['cart_info']['productPresellAttr']['product_presell_id'], $cart['cart_info']['productPresellAttr']['unique'], $productNum); + $productAttrValueRepository->incStock($cart['product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + $this->dao->incStock($cart['product_id'], $productNum); + } else if ($cart['product_type'] == '3') { + app()->make(ProductAssistSkuRepository::class)->incStock($cart['cart_info']['productAssistAttr']['product_assist_id'], $cart['cart_info']['productAssistAttr']['unique'], $productNum); + $productAttrValueRepository->incStock($cart['cart_info']['product']['old_product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + $this->dao->incStock($cart['cart_info']['product']['old_product_id'], $productNum); + } else if ($cart['product_type'] == '4') { + app()->make(ProductGroupSkuRepository::class)->incStock($cart['cart_info']['activeSku']['product_group_id'], $cart['cart_info']['activeSku']['unique'], $productNum); + $this->dao->incStock($cart['cart_info']['product']['old_product_id'], $productNum); + $productAttrValueRepository->incStock($cart['cart_info']['product']['old_product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + } else { + if (isset($cart['cart_info']['product']['old_product_id']) && $cart['cart_info']['product']['old_product_id'] > 0) { + $oldId = $cart['cart_info']['product']['old_product_id']; + $productAttrValueRepository->incSkuStock($oldId, $cart['cart_info']['productAttr']['sku'], $productNum); + $this->dao->incStock($oldId, $productNum); + } else { + $productAttrValueRepository->incStock($cart['product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + $this->dao->incStock($cart['product_id'], $productNum); + } + if ($cart->integral > 0) { + $totalIntegral = bcmul($productNum, $cart->integral, 0); + $this->dao->descIntegral($cart->product_id, $totalIntegral, bcmul(bcdiv($totalIntegral, $order->integral, 2), $order->integral_price, 2)); + } + } + }); + } + + + public function fictiForm(int $id) + { + $form = Elm::createForm(Route::buildUrl('systemStoreProductAddFicti', ['id' => $id])->build()); + $res = $this->dao->getWhere(['product_id' => $id], 'ficti,sales'); + $form->setRule([ + Elm::input('number', '现有已售数量', $res['ficti'])->readonly(true), + Elm::radio('type', '修改类型', 1) + ->setOptions([ + ['value' => 1, 'label' => '增加'], + ['value' => 2, 'label' => '减少'], + ]), + Elm::number('ficti', '修改已售数量', 0), + ]); + return $form->setTitle('修改已售数量'); + } + + /** + * TODO 普通商品加入购物车检测 + * @param int $prodcutId + * @param string $unique + * @param int $cartNum + * @author Qinii + * @day 2020-10-20 + */ + public function cartCheck(array $data, $userInfo) + { + $cart = null; + $where = $this->dao->productShow(); + $where['product_id'] = $data['product_id']; + $where['product_type'] = $data['product_type']; + unset($where['is_gift_bag']); + $product = $this->dao->search(null, $where)->find(); + + if (!$product) throw new ValidateException('商品已下架'); + if ($product['type'] && !$data['is_new']) throw new ValidateException('虚拟商品不可加入购物车'); + $value_make = app()->make(ProductAttrValueRepository::class); + $sku = $value_make->getOptionByUnique($data['product_attr_unique']); + if (!$sku) throw new ValidateException('SKU不存在'); + //分销礼包 + if ($product['is_gift_bag']) { + if (!systemConfig('extension_status')) throw new ValidateException('分销功能未开启'); + if (!$data['is_new']) throw new ValidateException('礼包商品不可加入购物车'); + if ($data['cart_num'] !== 1) throw new ValidateException('礼包商品只能购买一个'); + if ($userInfo->is_promoter) throw new ValidateException('您已经是分销员了'); + } + + //立即购买 限购 + if ($data['is_new']) { + $cart_num = $data['cart_num']; + } else { + //加入购物车 + //购物车现有 + $_num = $this->productOnceCountCart($where['product_id'],$data['product_attr_unique'], $userInfo->uid,$data['product_type']); + $cart_num = $_num + $data['cart_num']; + } + if ($sku['stock'] < $cart_num ) throw new ValidateException('库存不足'); + //添加购物车 + if (!$data['is_new']) { + $cart = app()->make(StoreCartRepository::class)->getCartByProductSku($data['product_attr_unique'], $userInfo->uid,$data['product_type']); + } + return compact('product', 'sku', 'cart'); + } + + /** + * TODO 购物车单商品数量 + * @param $productId + * @param $uid + * @param $num + * @author Qinii + * @day 5/26/21 + */ + public function productOnceCountCart($productId,$product_attr_unique,$uid,$product_type=0) + { + $make = app()->make(StoreCartRepository::class); + $where = [ + 'is_pay' => 0, + 'is_del' => 0, + 'is_new' => 0, + 'is_fail' => 0, + 'product_type' => $product_type, + 'product_id' => $productId, + 'uid' => $uid, + 'product_attr_unique' => $product_attr_unique, + ]; + $cart_num = $make->getSearch($where)->sum('cart_num'); + return $cart_num; + } + + /** + * TODO 秒杀商品加入购物车检测 + * @param array $data + * @param int $userInfo + * @return array + * @author Qinii + * @day 2020-10-21 + */ + public function cartSeckillCheck(array $data, $userInfo) + { + if ($data['is_new'] !== 1) throw new ValidateException('秒杀商品不能加入购物车'); + if ($data['cart_num'] !== 1) throw new ValidateException('秒杀商品只能购买一个'); + + $where = $this->dao->seckillShow(); + $where['product_id'] = $data['product_id']; + $product = $this->dao->search(null, $where)->find(); + if (!$product) throw new ValidateException('商品已下架'); + if ($product->seckill_status !== 1) throw new ValidateException('该商品不在秒杀时间段内'); + $order_make = app()->make(StoreOrderRepository::class); + $count = $order_make->seckillOrderCounut($data['product_id']); + + $value_make = app()->make(ProductAttrValueRepository::class); + $sku = $value_make->getOptionByUnique($data['product_attr_unique']); + + if ($sku['stock'] <= $count) throw new ValidateException('限购数量不足'); + $_sku = $value_make->getWhere(['sku' => $sku['sku'], 'product_id' => $product['old_product_id']]); + if (!$_sku) throw new ValidateException('原商品SKU不存在'); + if ($_sku['stock'] <= 0) throw new ValidateException('原库存不足'); + + if (!$order_make->getDayPayCount($userInfo->uid, $data['product_id'])) + throw new ValidateException('本次活动您购买数量已达到上限'); + if (!$order_make->getPayCount($userInfo->uid, $data['product_id'])) + throw new ValidateException('本次活动您该商品购买数量已达到上限'); + $cart = null; + return compact('product', 'sku', 'cart'); + } + + /** + * TODO 复制一条商品 + * @param int $productId + * @param array $data + * @return mixed + * @author Qinii + * @day 2020-11-19 + */ + public function productCopy(int $productId, array $data, $productType = 0) + { + $product = $this->getAdminOneProduct($productId, null); + $product = $product->toArray(); + if ($data) { + foreach ($data as $k => $v) { + $product[$k] = $v; + } + } + return $this->create($product, $productType); + } + + public function existsProduct(int $id, $productType) + { + switch ($productType) { + case 2: + $make = app()->make(ProductPresellRepository::class); + break; + case 3: + $make = app()->make(ProductAssistSetRepository::class); + break; + case 4: + $make = app()->make(ProductGroupRepository::class); + break; + case 40: + $make = app()->make(ProductGroupBuyingRepository::class); + break; + default: + $make = $this->dao; + break; + } + $where = [ + $make->getPk() => $id, + 'is_del' => 0 + ]; + return $make->getWhereCount($where); + } + + public function updateSort(int $id, ?int $merId, array $data) + { + $where[$this->dao->getPk()] = $id; + if ($merId) $where['mer_id'] = $merId; + $ret = $this->dao->getWhere($where); + if (!$ret) throw new ValidateException('数据不存在'); + app()->make(ProductRepository::class)->update($ret['product_id'], $data); + $make = app()->make(SpuRepository::class); + $activityId = $ret['product_type'] ? $ret->seckillActive->seckill_active_id : 0; + return $make->updateSort($ret['product_id'], $activityId, $ret['product_type'], $data); + } + + /** + * TODO 删除商户所有的 + * @param int $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearMerchantProduct($merId) + { + /** + * 删除商户所有的 + * 商品, + * 分类, + * 品牌 + */ + //普通 秒杀 + $this->dao->clearProduct($merId); + //助理 + app()->make(ProductAssistRepository::class)->clearProduct($merId); + //拼团 + app()->make(ProductGroupRepository::class)->clearProduct($merId); + //预售 + app()->make(ProductPresellRepository::class)->clearProduct($merId); + //spu + app()->make(SpuRepository::class)->clearProduct($merId); + } + + /** + * TODO 保障服务 + * @param $where + * @return mixed + * @author Qinii + * @day 5/20/21 + */ + public function GuaranteeTemplate($where) + { + $data = app()->make(GuaranteeTemplateRepository::class)->getSearch($where)->with( + [ + 'templateValue' => [ + 'value' => function($query){ + $query->field('guarantee_id,guarantee_name,guarantee_info'); + } + ], + ])->find(); + return $data ?? []; + } + + /** + * TODO 添加到货通知 + * @param int $uid + * @param string $unique + * @param int $type + * @author Qinii + * @day 5/24/21 + */ + public function increaseTake(int $uid, string $unique,int $type,int $product_id) + { + $status = systemConfig('procudt_increase_status'); + if(!$status) throw new ValidateException('未开启到货通知'); + $make = app()->make(ProductTakeRepository::class); + $where['product_id'] = $product_id; + if($unique) $where['unique'] = $unique; + $sku = app()->make(ProductAttrValueRepository::class)->getWhere($where); + if(!$sku) throw new ValidateException('商品不存在'); + $data = [ + 'product_id' => $sku['product_id'], + 'unique' => $unique ?: 1, + 'uid' => $uid, + 'status' => 0, + 'type' => $type + ]; + $make->findOrCreate($data); + } + + /** + * TODO 添加 编辑 预览商品 + * @param array $data + * @param int $productType + * @return array + * @author Qinii + * @day 6/15/21 + */ + public function preview(array $data) + { + if (!isset($data['attrValue']) || !$data['attrValue']) { + throw new ValidateException('缺少商品规格'); + } + $productType = 0; + $product = $this->setProduct($data); + if(isset($data['start_day'])){ //秒杀 + $product['stop'] = time() + 3600; + $productType = 1; + } + if(isset($data['presell_type'])){ //预售 + $product['start_time'] = $data['start_time']; + $product['end_time'] = $data['end_time']; + $product['presell_type'] = $data['presell_type']; + $product['delivery_type'] = $data['delivery_type']; + $product['delivery_day'] = $data['delivery_day']; + $product['p_end_time'] = $data['end_time']; + $product['final_start_time'] = $data['final_start_time']; + $product['final_end_time'] = $data['final_end_time']; + $productType = 2; + } + + if(isset($data['assist_count'])){ + //助力 + $product['assist_count'] = $data['assist_count']; + $product['assist_user_count'] = $data['assist_user_count']; + $product['price'] = $data['attrValue'][0]['assist_price']; + $productType = 3; + } + + if(isset($data['buying_count_num'])) { + // + $product['buying_count_num'] = $data['buying_count_num']; + $product['pay_count'] = $data['pay_count']; + $productType = 4; + } + + $product['slider_image'] = explode(',',$product['slider_image']); + $product['merchant'] = $data['merchant']; + $product['content'] = ['content' => $data['content']]; + $settleParams = $this->setAttrValue($data, 0, $productType, 0); + $settleParams['attr'] = $this->setAttr($data['attr'], 0); + + $product['price'] = $settleParams['data']['price']; + $product['stock'] = $settleParams['data']['stock']; + $product['cost'] = $settleParams['data']['cost']; + $product['ot_price'] = $settleParams['data']['ot_price']; + $product['product_type'] = $productType; + foreach ($settleParams['attrValue'] as $k => $value) { + $_value = [ + 'sku' => $value['sku'], + 'price' => $value['price'], + 'stock' => $value['stock'], + 'image' => $value['image'], + 'weight' => $value['weight'], + 'volume' => $value['volume'], + 'sales' => $value['sales'], + 'unique' => $value['unique'], + 'bar_code' => $value['bar_code'], + ]; + $sku[$value['sku']] = $_value; + } + $preview_key = 'preview'.$data['mer_id'].$productType.'_'.time(); + unset($settleParams['data'],$settleParams['attrValue']); + $settleParams['sku'] = $sku; + $settleParams['attr'] = $this->detailAttr($settleParams['attr'],1); + + if(isset($data['guarantee_template_id'])) { + $guarantee_id = app()->make(GuaranteeValueRepository::class)->getSearch(['guarantee_template_id' => $data['guarantee_template_id']])->column('guarantee_id'); + $product['guaranteeTemplate'] = app()->make(GuaranteeRepository::class)->getSearch(['status' => 1, 'is_del' => 0])->where('guarantee_id', 'in', $guarantee_id)->select(); + } + if(isset($data['temp_id'])) { + $product['temp'] = app()->make(ShippingTemplateRepository::class)->getSearch(['shipping_template_id' => $data['temp_id']])->find(); + } + + $ret = array_merge($product,$settleParams); + + Cache::set($preview_key,$ret); + + return compact('preview_key','ret'); + } + + + /** + * TODO 列表查看预览 + * @param array $data + * @return array|\think\Model|null + * @author Qinii + * @day 7/9/21 + */ + public function getPreview(array $data) + { + switch($data['product_type']) + { + case 0: + case 98: + return $this->apiProductDetail(['product_id' => $data['id']], $data['product_type'], 0); + break; + case 1: + $ret = $this->apiProductDetail(['product_id' => $data['id']], 1, 0); + $ret['stop'] = time() + 3600; + break; + case 2: + $make = app()->make(ProductPresellRepository::class); + $res = $make->getWhere([$make->getPk()=> $data['id']])->toArray(); + $ret = $this->apiProductDetail(['product_id' => $res['product_id']], 2, $data['id'])->toArray(); + $ret['ot_price'] = $ret['price']; + $ret['start_time'] = $res['start_time']; + $ret['p_end_time'] = $res['end_time']; + $ret = array_merge($ret,$res); + break; + case 3: + $make = app()->make(ProductAssistRepository::class); + $res = $make->getWhere([$make->getPk()=> $data['id']])->toArray(); + $ret = $this->apiProductDetail(['product_id' => $res['product_id']], 3, $data['id'])->toArray(); + + $ret = array_merge($ret,$res); + foreach ($ret['sku'] as $value){ + $ret['price'] = $value['price']; + $ret['stock'] = $value['stock']; + } + break; + case 4: + $make = app()->make(ProductGroupRepository::class); + $res = $make->get($data['id'])->toArray(); + $ret = $this->apiProductDetail(['product_id' => $res['product_id']], 4, $data['id'])->toArray(); + $ret['ot_price'] = $ret['price']; + $ret = array_merge($ret,$res); + break; + default: + break; + } + return $ret; + } + + public function setLabels($id, $data, $merId = 0) + { + $where['product_id'] = $id; + $field = isset($data['sys_labels']) ? 'sys_labels' : 'mer_labels'; + if ($merId) $where['mer_id'] = $merId; + app()->make(ProductLabelRepository::class)->checkHas($merId,$data[$field]); + $ret = $this->dao->getWhere($where); + + $activeId = $ret->seckillActive->seckill_active_id ?? 0; + + $spu = ['activity_id' => $activeId, 'product_type' => $ret['product_type'], 'product_id' => $id]; + $ret = app()->make(SpuRepository::class)->getWhere($spu); + if (!$ret) throw new ValidateException('数据不存在'); + $ret->$field = $data[$field]; + $ret->save(); + } + + public function getAttrValue(int $id, int $merId) + { + $data = $this->dao->getWhere(['product_id' => $id, 'mer_id' => $merId]); + if (!$data) throw new ValidateException('数据不存在'); + return app()->make(ProductAttrValueRepository::class)->getSearch(['product_id' => $id])->select()->append(['is_svip_price']); + } + + public function checkParams($data,$merId,$id = null) + { + if (!$data['pay_limit']) $data['once_max_count'] = 0; + if ($data['brand_id'] > 0 && !$this->merBrandExists($data['brand_id'])) + throw new ValidateException('品牌不存在'); + if (!$this->CatExists($data['cate_id'])) + throw new ValidateException('平台分类不存在'); + if (isset($data['mer_cate_id']) && !$this->merCatExists($data['mer_cate_id'], $merId)) + throw new ValidateException('不存在的商户分类'); + if ($data['delivery_way'] == 2 && !$this->merShippingExists($merId, $data['temp_id'])) + throw new ValidateException('运费模板不存在'); + if (isset($data['type']) && $data['type'] && $data['extend']) { + $key = ['email','text','number','date','time','idCard','mobile','image']; + if (count($data['extend']) > 10) throw new ValidateException('附加表单不能超过10条'); + $title = []; + foreach ($data['extend'] as $item) { + if (empty($item['title']) ) + throw new ValidateException('表单名称不能为空:'.$item['key']); + if (in_array($item['title'],$title)) + throw new ValidateException('表单名称不能重复:'.$item['title']); + $title[] = $item['title']; + if (!in_array($item['key'], $key)) + throw new ValidateException('表单类型错误:'.$item['key']); + $extend[] = [ + 'title' => $item['title'], + 'key' => $item['key'] , + 'require' => $item['require'], + ]; + } + } + app()->make(ProductLabelRepository::class)->checkHas($merId,$data['mer_labels']); + $count = app()->make(StoreCategoryRepository::class)->getWhereCount(['store_category_id' => $data['cate_id'],'is_show' => 1]); + if (!$count) throw new ValidateException('平台分类不存在或不可用'); + app()->make(StoreProductValidate::class)->check($data); + if ($id) unset($data['type']); + $data['extend'] = $extend ?? []; + //单次限购 + return $data; + } +} diff --git a/app/common/repositories/store/product/ProductRepository.php.bak b/app/common/repositories/store/product/ProductRepository.php.bak new file mode 100644 index 00000000..0aa8041f --- /dev/null +++ b/app/common/repositories/store/product/ProductRepository.php.bak @@ -0,0 +1,2215 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\product; + +use app\common\model\store\product\ProductLabel; +use app\common\model\user\User; +use app\common\repositories\community\CommunityRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\GuaranteeRepository; +use app\common\repositories\store\GuaranteeTemplateRepository; +use app\common\repositories\store\GuaranteeValueRepository; +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\parameter\ParameterValueRepository; +use app\common\repositories\store\StoreActivityRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\store\StoreSeckillTimeRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserVisitRepository; +use app\validate\merchant\StoreProductValidate; +use crmeb\jobs\ChangeSpuStatusJob; +use crmeb\jobs\SendSmsJob; +use crmeb\services\QrcodeService; +use crmeb\services\RedisCacheService; +use crmeb\services\SwooleTaskService; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\ProductDao as dao; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; +use app\common\repositories\store\StoreBrandRepository; +use think\facade\Queue; +use think\facade\Route; +use think\contract\Arrayable; + +/** + * Class ProductRepository + * @package app\common\repositories\store\product + * @author xaboy + * @mixin dao + */ +class ProductRepository extends BaseRepository +{ + + protected $dao; + const CREATE_PARAMS = [ + "image", "slider_image", "store_name", "store_info", "keyword", "bar_code", "guarantee_template_id", "cate_id", "mer_cate_id", "unit_name", "sort" , "is_show", "is_good", 'is_gift_bag', 'integral_rate', "video_link", "temp_id", "content", "spec_type", "extension_type", "attr", 'mer_labels', 'delivery_way', 'delivery_free','param_temp_id','extend', + ["brand_id",0], + ['once_max_count',0], + ['once_min_count',0], + ['pay_limit', 0], + ["attrValue",[]], + ['give_coupon_ids',[]], + ['type',0], + ['svip_price',0], + ['svip_price_type',0], + ['params',[]], + ]; + protected $admin_filed = 'Product.product_id,Product.mer_id,brand_id,spec_type,unit_name,mer_status,rate,reply_count,store_info,cate_id,Product.image,slider_image,Product.store_name,Product.keyword,Product.sort,U.rank,Product.is_show,Product.sales,Product.price,extension_type,refusal,cost,ot_price,stock,is_gift_bag,Product.care_count,Product.status,is_used,Product.create_time,Product.product_type,old_product_id,star,ficti,integral_total,integral_price_total,sys_labels,param_temp_id,mer_svip_status,svip_price,svip_price_type'; + protected $filed = 'Product.bar_code,Product.product_id,Product.mer_id,brand_id,unit_name,spec_type,mer_status,rate,reply_count,store_info,cate_id,Product.image,slider_image,Product.store_name,Product.keyword,Product.sort,Product.is_show,Product.sales,Product.price,extension_type,refusal,cost,ot_price,stock,is_gift_bag,Product.care_count,Product.status,is_used,Product.create_time,Product.product_type,old_product_id,integral_total,integral_price_total,mer_labels,Product.is_good,Product.is_del,type,param_temp_id,mer_svip_status,svip_price,svip_price_type'; + + const NOTIC_MSG = [ + 1 => [ + '0' => 'product_success', + '1' => 'product_seckill_success', + '2' => 'product_presell_success', + '3' => 'product_assist_success', + '4' => 'product_group_success', + 'msg' => '审核通过' + ], + -1 => [ + '0' => 'product_fail', + '1' => 'product_seckill_fail', + '2' => 'product_presell_fail', + '3' => 'product_assist_fail', + '4' => 'product_group_fail', + 'msg' => '审核失败' + ], + -2 => [ + '0' => 'product_fail', + '1' => 'product_seckill_fail', + '2' => 'product_presell_fail', + '3' => 'product_assist_fail', + '4' => 'product_group_fail', + 'msg' => '被下架' + ], + ]; + /** + * ProductRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @param int $merId + * @return mixed + */ + public function CatExists(int $id) + { + return (app()->make(StoreCategoryRepository::class))->merExists(0, $id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/20 + * @param $ids + * @param int $merId + * @return bool + */ + public function merCatExists($ids, int $merId) + { + if (!is_array($ids ?? '')) return true; + foreach ($ids as $id) { + if (!(app()->make(StoreCategoryRepository::class))->merExists($merId, $id)) + return false; + } + return true; + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param int $id + * @return mixed + */ + public function merShippingExists(int $merId, int $id) + { + $make = app()->make(ShippingTemplateRepository::class); + return $make->merExists($merId, $id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @return mixed + */ + public function merBrandExists(int $id) + { + $make = app()->make(StoreBrandRepository::class); + return $make->meExists($id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param int $id + * @return bool + */ + public function merExists(?int $merId, int $id) + { + return $this->dao->merFieldExists($merId, $this->getPk(), $id); + } + + public function merDeleteExists(int $merId, int $id) + { + return $this->dao->getDeleteExists($merId, $id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $merId + * @param int $id + * @return bool + */ + public function apiExists(?int $merId, int $id) + { + return $this->dao->apiFieldExists($merId, $this->getPk(), $id); + } + + /** + * @param int $merId + * @param int $tempId + * @return bool + * @author Qinii + */ + public function merTempExists(int $merId, int $tempId) + { + return $this->dao->merFieldExists($merId, 'temp_id', $tempId); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param array $data + */ + public function create(array $data, int $productType = 0, $conType = 0) + { + if (!$data['spec_type']) { + $data['attr'] = []; + if (count($data['attrValue']) > 1) throw new ValidateException('单规格商品属性错误'); + } + $content = [ + 'content' => $conType ? json_encode($data['content']) : $data['content'] , + 'type' => $conType + ]; + $product = $this->setProduct($data); + event('product.create.before', compact('data','productType','conType')); + return Db::transaction(function () use ($data, $productType,$conType,$content,$product) { + $activity_id = 0; + $product['product_type'] = $productType; + $result = $this->dao->create($product); + $settleParams = $this->setAttrValue($data, $result->product_id, $productType, 0,$data['mer_id']); + $settleParams['cate'] = $this->setMerCate($data['mer_cate_id'], $result->product_id, $data['mer_id']); + $settleParams['attr'] = $this->setAttr($data['attr'], $result->product_id); + if (in_array($productType, [0, 98])) app()->make(ParameterValueRepository::class)->create($result->product_id, $data['params'] ?? [],$data['mer_id']); + $this->save($result->product_id, $settleParams, $content,$product,$productType); + if (in_array($productType, [0, 1,98])) { + if ($productType == 1) { //秒杀商品 + $dat = $this->setSeckillProduct($data); + $dat['product_id'] = $result->product_id; + $seckill = app()->make(StoreSeckillActiveRepository::class)->create($dat); + $activity_id = $seckill->seckill_active_id; + } + $product['price'] = $settleParams['data']['price']; + $product['mer_labels'] = $data['mer_labels']; + app()->make(SpuRepository::class)->create($product, $result->product_id, $activity_id, $productType); + } + $product = $result; + event('product.create',compact('product')); + return $result->product_id; + }); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @param array $data + */ + public function edit(int $id, array $data, int $merId, int $productType, $conType = 0) + { + if (!$data['spec_type']) { + $data['attr'] = []; + if (count($data['attrValue']) > 1) throw new ValidateException('单规格商品属性错误'); + } + event('product.update.before', compact('id','data','merId','productType','conType')); + $spuData = $product = $this->setProduct($data); + $settleParams = $this->setAttrValue($data, $id, $productType, 1,$merId); + $settleParams['cate'] = $this->setMerCate($data['mer_cate_id'], $id, $merId); + $settleParams['attr'] = $this->setAttr($data['attr'], $id); + $content = [ + 'content' => $conType ? json_encode($data['content']) : $data['content'] , + 'type' => $conType + ]; + $spuData['price'] = $settleParams['data']['price']; + $spuData['mer_id'] = $merId; + $spuData['mer_labels'] = $data['mer_labels']; + Db::transaction(function () use ($id, $data, $productType, $settleParams,$content,$product,$spuData,$merId) { + $this->save($id, $settleParams, $content, $product, $productType); + if ($productType == 1) { //秒杀商品 + $dat = $this->setSeckillProduct($data); + app()->make(StoreSeckillActiveRepository::class)->updateByProduct($id, $dat); + } + if ($productType == 0) { + $make = app()->make(ParameterValueRepository::class); + $make->clear($id, 'product_id'); + $make->create($id, $data['params'] ?? [], $merId); + } + app()->make(SpuRepository::class)->baseUpdate($spuData, $id, 0, $productType); + event('product.update',compact('id')); + app()->make(SpuRepository::class)->changeStatus($id, $productType); + }); + } + + public function freeTrial(int $id, array $data, int $merId) + { + if (!$data['spec_type']) { + $data['attr'] = []; + if (count($data['attrValue']) > 1) throw new ValidateException('单规格商品属性错误'); + } + $res = $this->dao->get($id); + $data['svip_price_type'] = $res['svip_price_type']; + $settleParams = $this->setAttrValue($data, $id, 0, 1); + $settleParams['cate'] = $this->setMerCate($data['mer_cate_id'], $id, $merId); + $settleParams['attr'] = $this->setAttr($data['attr'], $id); + $data['price'] = $settleParams['data']['price']; + unset($data['attrValue'],$data['attr'],$data['mer_cate_id']); + $ret = app()->make(SpuRepository::class)->getSearch(['product_id' => $id, 'product_type' => 0,])->find(); + Db::transaction(function () use ($id, $data, $settleParams,$ret) { + $this->save($id, $settleParams, null, [], 0); + app()->make(SpuRepository::class)->update($ret->spu_id,['price' => $data['price']]); + Queue(SendSmsJob::class, ['tempId' => 'PRODUCT_INCREASE', 'id' => $id]); + }); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + */ + public function destory($id) + { + (app()->make(ProductAttrRepository::class))->clearAttr($id); + (app()->make(ProductAttrValueRepository::class))->clearAttr($id); + (app()->make(ProductContentRepository::class))->clearAttr($id, null); + (app()->make(ProductCateRepository::class))->clearAttr($id); + $this->dao->delete($id, true); + } + + /** + * @Author:Qinii + * @Date: 2020/5/20 + * @param $id + * @param $spec_type + * @param $settleParams + * @param $content + * @return int + */ + public function save($id, $settleParams, $content, $data = [], $productType = 0) + { + (app()->make(ProductAttrRepository::class))->clearAttr($id); + (app()->make(ProductAttrValueRepository::class))->clearAttr($id); + (app()->make(ProductCateRepository::class))->clearAttr($id); + if (isset($settleParams['cate'])) (app()->make(ProductCateRepository::class)->insert($settleParams['cate'])); + if (isset($settleParams['attr'])) (app()->make(ProductAttrRepository::class))->insert($settleParams['attr']); + + if (isset($settleParams['attrValue'])) { + $arr = array_chunk($settleParams['attrValue'], 30); + foreach ($arr as $item){ + app()->make(ProductAttrValueRepository::class)->insertAll($item); + } + } + if ($content){ + app()->make(ProductContentRepository::class)->clearAttr($id,$content['type']); + $this->dao->createContent($id, $content); + } + + if (isset($settleParams['data'])) { + $data['price'] = $settleParams['data']['price']; + $data['ot_price'] = $settleParams['data']['ot_price']; + $data['cost'] = $settleParams['data']['cost']; + $data['stock'] = $settleParams['data']['stock']; + $data['svip_price'] = $settleParams['data']['svip_price']; + } + $res = $this->dao->update($id, $data); + + if(isset($data['status']) && $data['status'] !== 1 ){ + $message = '您有1个新的'. ($productType ? '秒杀商品' : ($data['is_gift_bag'] ? '礼包商品' :'商品')) . '待审核'; + $type = $productType ? 'new_seckill' : ($data['is_gift_bag'] ? 'new_bag' :'new_product'); + SwooleTaskService::admin('notice', [ + 'type' => $type, + 'data' => [ + 'title' => '商品审核', + 'message' => $message, + 'id' => $id + ] + ]); + } + return $res; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @param array $data + * @return int + */ + public function adminUpdate(int $id, array $data) + { + Db::transaction(function () use ($id, $data) { + app()->make(ProductContentRepository::class)->clearAttr($id, 0); + $this->dao->createContent($id, ['content' => $data['content']]); + unset($data['content']); + $res = $this->dao->getWhere(['product_id' => $id], '*', ['seckillActive']); + $activity_id = $res['seckillActive']['seckill_active_id'] ?? 0; + app()->make(SpuRepository::class)->changRank($activity_id, $id, $res['product_type'], $data); + unset($data['star']); + return $this->dao->update($id, $data); + }); + } + + /** + * 格式化秒杀商品活动时间 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @return array + */ + public function setSeckillProduct(array $data) + { + $dat = [ + 'start_day' => $data['start_day'], + 'end_day' => $data['end_day'], + 'start_time' => $data['start_time'], + 'end_time' => $data['end_time'], + 'status' => 1, + 'once_pay_count' => $data['once_pay_count'], + 'all_pay_count' => $data['all_pay_count'], + ]; + if (isset($data['mer_id'])) $dat['mer_id'] = $data['mer_id']; + return $dat; + } + + /** + * 格式商品主体信息 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @return array + */ + public function setProduct(array $data) + { + $give_coupon_ids = ''; + if (isset($data['give_coupon_ids']) && !empty($data['give_coupon_ids'])) { + $gcoupon_ids = array_unique($data['give_coupon_ids']); + $give_coupon_ids = implode(',', $gcoupon_ids); + } + + if(isset($data['integral_rate'])){ + $integral_rate = $data['integral_rate']; + if($data['integral_rate'] < 0) $integral_rate = -1; + if($data['integral_rate'] > 100) $integral_rate = 100; + + } + + $result = [ + 'store_name' => $data['store_name'], + 'image' => $data['image'], + 'slider_image' => is_array($data['slider_image']) ? implode(',', $data['slider_image']) : '', + 'store_info' => $data['store_info'] ?? '', + 'keyword' => $data['keyword']??'', + 'brand_id' => $data['brand_id'] ?? 0, + 'cate_id' => $data['cate_id'] ?? 0, + 'unit_name' => $data['unit_name']??'件', + 'sort' => $data['sort'] ?? 0, + 'is_show' => $data['is_show'] ?? 0, + 'is_used' => (isset($data['status']) && $data['status'] == 1) ? 1 : 0, + 'is_good' => $data['is_good'] ?? 0, + 'video_link' => $data['video_link']??'', + 'temp_id' => $data['delivery_free'] ? 0 : ($data['temp_id'] ?? 0), + 'extension_type' => $data['extension_type']??0, + 'spec_type' => $data['spec_type'] ?? 0, + 'status' => $data['status']??0, + 'give_coupon_ids' => $give_coupon_ids, + 'mer_status' => $data['mer_status'], + 'guarantee_template_id' => $data['guarantee_template_id']??0, + 'is_gift_bag' => $data['is_gift_bag'] ?? 0, + 'integral_rate' => $integral_rate ?? 0, + 'delivery_way' => implode(',',$data['delivery_way']), + 'delivery_free' => $data['delivery_free'] ?? 0, + 'once_min_count' => $data['once_min_count'] ?? 0, + 'once_max_count' => $data['once_max_count'] ?? 0, + 'pay_limit' => $data['pay_limit'] ?? 0, + 'svip_price_type' => $data['svip_price_type'] ?? 0, + ]; + if (isset($data['mer_id'])) + $result['mer_id'] = $data['mer_id']; + if (isset($data['old_product_id'])) + $result['old_product_id'] = $data['old_product_id']; + if (isset($data['product_type'])) + $result['product_type'] = $data['product_type']; + if (isset($data['type']) && $data['type']) + $result['type'] = $data['type']; + if (isset($data['param_temp_id'])) + $result['param_temp_id'] = $data['param_temp_id']; + if (isset($data['extend'])) + $result['extend'] = $data['extend'] ? json_encode($data['extend'], JSON_UNESCAPED_UNICODE) :[]; + return $result; + } + + /** + * 格式商品商户分类 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @param int $productId + * @param int $merId + * @return array + */ + public function setMerCate(array $data, int $productId, int $merId) + { + $result = []; + foreach ($data as $value) { + $result[] = [ + 'product_id' => $productId, + 'mer_cate_id' => $value, + 'mer_id' => $merId, + ]; + } + return $result; + } + + /** + * 格式商品规格 + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @param int $productId + * @return array + */ + public function setAttr(array $data, int $productId) + { + $result = []; + try{ + foreach ($data as $value) { + $result[] = [ + 'type' => 0, + 'product_id' => $productId, + "attr_name" => $value['value'] ?? $value['attr_name'], + 'attr_values' => implode('-!-', $value['detail']), + ]; + } + } catch (\Exception $exception) { + throw new ValidateException('商品规格格式错误'); + } + + return $result; + } + + /** + * 格式商品SKU + * @Author:Qinii + * @Date: 2020/9/15 + * @param array $data + * @param int $productId + * @return mixed + */ + public function setAttrValue(array $data, int $productId, int $productType, int $isUpdate = 0,int $merId = 0) + { + $extension_status = systemConfig('extension_status'); + if ($isUpdate) { + $product = app()->make(ProductAttrValueRepository::class)->search(['product_id' => $productId])->select()->toArray(); + $oldSku = $this->detailAttrValue($product, null); + } + $price = $stock = $ot_price = $cost = $svip_price = 0; + try { + foreach ($data['attrValue'] as $value) { + $_svip_price = 0; + $sku = ''; + if (isset($value['detail']) && !empty($value['detail']) && is_array($value['detail'])) { + $sku = implode(',', $value['detail']); + } + $ot_price_ = $value['price']; + if (isset($value['active_price'])) { + $sprice = $value['active_price'] < 0 ? 0 : $value['active_price']; + } elseif (isset($value['presell_price'])) { + $sprice = $value['presell_price'] < 0 ? 0 : $value['presell_price']; + } elseif (isset($value['assist_price'])) { + $sprice = $value['assist_price'] < 0 ? 0 : $value['assist_price']; + } else { + $ot_price_ = $value['ot_price']; + $sprice = ($value['price'] < 0) ? 0 : $value['price']; + } + if ($data['svip_price_type'] == 2) { + $_svip_price = $value['svip_price']; + $svip_price = !$svip_price ? $value['svip_price'] : (($svip_price > $value['svip_price']) ? $value['svip_price'] : $svip_price); + } + + $cost = !$cost ? $value['cost'] : (($cost > $value['cost']) ?$cost: $value['cost']); + $price = !$price ? $sprice : (($price > $sprice) ? $sprice : $price); + $ot_price = !$ot_price ? $ot_price_ : (($ot_price > $ot_price_) ? $ot_price : $ot_price_); + + $unique = $this->setUnique($productId, $sku, $productType); + $result['attrValue'][] = [ + 'detail' => json_encode($value['detail'] ?? ''), + "bar_code" => $value["bar_code"] ?? '', + "image" => $value["image"] ?? '', + "cost" => $value['cost'] ? (($value['cost'] < 0) ? 0 : $value['cost']) : 0, + "price" => $value['price'] ? (($value['price'] < 0) ? 0 : $value['price']) : 0, + "volume" => isset($value['volume']) ? ($value['volume'] ? (($value['volume'] < 0) ? 0 : $value['volume']) : 0) :0, + "weight" => isset($value['weight']) ? ($value['weight'] ? (($value['weight'] < 0) ? 0 : $value['weight']) : 0) :0, + "stock" => $value['stock'] ? (($value['stock'] < 0) ? 0 : $value['stock']) : 0, + "ot_price" => $value['ot_price'] ? (($value['ot_price'] < 0) ? 0 : $value['ot_price']) : 0, + "extension_one" => $extension_status ? ($value['extension_one'] ?? 0) : 0, + "extension_two" => $extension_status ? ($value['extension_two'] ?? 0) : 0, + "product_id" => $productId, + "type" => 0, + "sku" => $sku, + "unique" => $unique, + 'sales' => $isUpdate ? ($oldSku[$sku]['sales'] ?? 0) : 0, + 'svip_price' => $_svip_price, + 'mer_id' => $merId, + ]; + $stock = $stock + intval($value['stock']); + } + $result['data'] = [ + 'price' => $price , + 'stock' => $stock, + 'ot_price' => $ot_price, + 'cost' => $cost, + 'svip_price' => $svip_price, + ]; + } catch (\Exception $exception) { + throw new ValidateException('规格错误 :'.$exception->getMessage()); + } + return $result; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $id + * @param string $sku + * @param int $type + * @return string + */ + public function setUnique(int $id, $sku, int $type) + { + $str = strval($type); + $result=strlen($str); + $length=12-$result; + return $unique = substr(md5($sku . $id), 12, $length) . $type; + // $has = (app()->make(ProductAttrValueRepository::class))->merUniqueExists(null, $unique); + // return $has ? false : $unique; + } + + + /** + * TODO 后台管理需要的商品详情 + * @param int $id + * @param int|null $activeId + * @return array|\think\Model|null + * @author Qinii + * @day 2020-11-24 + */ + public function getAdminOneProduct(int $id, ?int $activeId, $conType = 0) + { + $with = ['attr', 'attrValue', 'oldAttrValue', 'merCateId.category', 'storeCategory', 'brand', 'temp', 'seckillActive', + 'content' => function($query) use($conType){ + $query->where('type',$conType); + }, + 'merchant'=> function($query){ + $query->field('mer_id,mer_avatar,mer_name,is_trader'); + }, + 'guarantee.templateValue.value', + + ]; + + $data = $this->dao->geTrashedtProduct($id)->with($with)->find(); + + $data['delivery_way'] = empty($data['delivery_way']) ? [2] : explode(',',$data['delivery_way']); + $data['extend'] = empty($data['extend']) ? [] : json_decode($data['extend']); + $make_order = app()->make(StoreCouponRepository::class); + $where = [['coupon_id', 'in', $data['give_coupon_ids']]]; + $data['coupon'] = $make_order->selectWhere($where, 'coupon_id,title')->toArray(); + $spu_make = app()->make(SpuRepository::class); + + $append = []; + if ($data['product_type'] == 0) { + $append = ['us_status', 'params']; + $activeId = 0; + } + if ($data['product_type'] == 1){ + $activeId = $data->seckillActive->seckill_active_id; + $make = app()->make(StoreOrderRepository::class); + $append = ['us_status','seckill_status']; + } + if ($data['product_type'] == 2) $make = app()->make(ProductPresellSkuRepository::class); + if ($data['product_type'] == 3) $make = app()->make(ProductAssistSkuRepository::class); + if ($data['product_type'] == 4) $make = app()->make(ProductGroupSkuRepository::class); + + $spu_where = ['activity_id' => $activeId, 'product_type' => $data['product_type'], 'product_id' => $id]; + $spu = $spu_make->getSearch($spu_where)->find(); + $data['star'] = $spu['star'] ?? ''; + $data['mer_labels'] = $spu['mer_labels'] ?? ''; + $data['sys_labels'] = $spu['sys_labels'] ?? ''; + + $data->append($append); + $mer_cat = []; + if (isset($data['merCateId'])) { + foreach ($data['merCateId'] as $i) { + $mer_cat[] = $i['mer_cate_id']; + } + } + $data['mer_cate_id'] = $mer_cat; + + foreach ($data['attr'] as $k => $v) { + $data['attr'][$k] = [ + 'value' => $v['attr_name'], + 'detail' => $v['attr_values'] + ]; + } + $attrValue = (in_array($data['product_type'], [3, 4])) ? $data['oldAttrValue'] : $data['attrValue']; + unset($data['oldAttrValue'], $data['attrValue']); + $arr = []; + if (in_array($data['product_type'], [1, 3])) $value_make = app()->make(ProductAttrValueRepository::class); + foreach ($attrValue as $key => $item) { + + if ($data['product_type'] == 1) { + $value = $value_make->getSearch(['sku' => $item['sku'], 'product_id' => $data['old_product_id']])->find(); + $old_stock = $value['stock']; + $item['sales'] = $make->skuSalesCount($item['unique']); + } + if ($data['product_type'] == 2) { + $item['presellSku'] = $make->getSearch(['product_presell_id' => $activeId, 'unique' => $item['unique']])->find(); + if (is_null($item['presellSku'])) continue; + } + if ($data['product_type'] == 3) { + $item['assistSku'] = $make->getSearch(['product_assist_id' => $activeId, 'unique' => $item['unique']])->find(); + if (is_null($item['assistSku'])) + continue; + } + if ($data['product_type'] == 4) { + $item['_sku'] = $make->getSearch(['product_group_id' => $activeId, 'unique' => $item['unique']])->find(); + if (is_null($item['_sku'])) + continue; + } + $sku = explode(',', $item['sku']); + $item['old_stock'] = $old_stock ?? $item['stock']; + foreach ($sku as $k => $v) { + $item['value' . $k] = $v; + } + $arr[] = $item; + } + + $data['attrValue'] = $arr; + + $content = $data['content']['content'] ?? ''; + if ($conType) $content = json_decode($content); + unset($data['content']); + $data['content'] = $content; + return $data; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $type + * @param int|null $merId + * @return array + */ + public function switchType($type, ?int $merId = 0, $productType = 0) + { + $stock = 0; + if ($merId) $stock = merchantConfig($merId, 'mer_store_stock'); + switch ($type) { + case 1: + $where = ['is_show' => 1, 'status' => 1,]; + break; + case 2: + $where = ['is_show' => 0, 'status' => 1]; + break; + case 3: + $where = ['is_show' => 1, 'stock' => 0, 'status' => 1]; + break; + case 4: + $where = ['stock' => $stock ? $stock : 0, 'status' => 1]; + break; + case 5: + $where = ['soft' => true]; + break; + case 6: + $where = ['status' => 0]; + break; + case 7: + $where = ['status' => -1]; + break; + case 20: + $where = ['status' => 1]; + break; + default: + // $where = ['is_show' => 1, 'status' => 1]; + break; + } + if ($productType == 0) { + $where['product_type'] = $productType; + if (!$merId) $where['is_gift_bag'] = 0; + } + if ($productType == 1||$productType==98) { + $where['product_type'] = $productType; + } + if ($productType == 10) { + $where['is_gift_bag'] = 1; + } + if (!$merId) $where['star'] = ''; + return $where; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int|null $merId + * @return array + */ + public function getFilter(?int $merId, $name = '', $productType = 0) + { + $result = []; + $result[] = [ + 'type' => 1, + 'name' => '出售中' . $name, + 'count' => $this->dao->search($merId, $this->switchType(1, $merId, $productType))->count() + ]; + $result[] = [ + 'type' => 2, + 'name' => '仓库中' . $name, + 'count' => $this->dao->search($merId, $this->switchType(2, $merId, $productType))->count() + ]; + if ($merId) { + $result[] = [ + 'type' => 3, + 'name' => '已售罄' . $name, + 'count' => $this->dao->search($merId, $this->switchType(3, $merId, $productType))->count() + ]; + $result[] = [ + 'type' => 4, + 'name' => '警戒库存', + 'count' => $this->dao->search($merId, $this->switchType(4, $merId, $productType))->count() + ]; + } + $result[] = [ + 'type' => 6, + 'name' => '待审核' . $name, + 'count' => $this->dao->search($merId, $this->switchType(6, $merId, $productType))->count() + ]; + $result[] = [ + 'type' => 7, + 'name' => '审核未通过' . $name, + 'count' => $this->dao->search($merId, $this->switchType(7, $merId, $productType))->count() + ]; + if ($merId) { + $result[] = [ + 'type' => 5, + 'name' => '回收站' . $name, + 'count' => $this->dao->search($merId, $this->switchType(5, $merId, $productType))->count() + ]; + } + return $result; + } + + /** + * TODO 商户商品列表 + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + */ + public function getList(?int $merId, array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where)->with(['merCateId.category', 'storeCategory', 'brand']); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field($this->filed)->select(); + + $data->append(['us_status']); + + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count', 'list'); + } + + /** + * TODO 商户秒杀商品列表 + * @param int|null $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-08-04 + */ + public function getSeckillList(?int $merId, array $where, int $page, int $limit) + { + $make = app()->make(StoreOrderRepository::class); + $query = $this->dao->search($merId, $where)->with(['merCateId.category', 'storeCategory', 'brand', 'attrValue ', 'seckillActive']); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field($this->filed)->order('sort DESC')->select() + ->each(function ($item) use ($make, $where) { + $result = $this->getSeckillAttrValue($item['attrValue'], $item['old_product_id']); + $item['stock'] = $result['stock']; + return $item; + }); + $data->append(['seckill_status', 'us_status']); + + $list = hasMany( + $data , + 'mer_labels', + ProductLabel::class, + 'product_label_id', + 'mer_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + + return compact('count', 'list'); + } + + /** + * TODO 平台商品列表 + * @Author:Qinii + * @Date: 2020/5/11 + * @param int $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + */ + public function getAdminList(?int $merId, array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where)->with([ + 'merCateId.category', + 'storeCategory', + 'brand', + 'merchant', + ]); + $count = $query->count(); + $data = $query->page($page, $limit)->setOption('field', [])->field($this->admin_filed)->select(); + $data->append([ 'us_status']); + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count', 'list'); + } + + /** + * TODO 平台秒杀商品列表 + * @param int|null $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-08-04 + */ + public function getAdminSeckillList(?int $merId, array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where)->with([ + 'merCateId.category', + 'storeCategory', + 'brand', + 'merchant', + 'seckillActive', + 'attrValue', + ]); + $count = $query->count(); + $data = $query->page($page, $limit) + ->field('Product.*,U.star,U.rank,U.sys_labels') + ->select() + ->each(function ($item) use ($where) { + $result = $this->getSeckillAttrValue($item['attrValue'], $item['old_product_id']); + $item['stock'] = $result['stock']; + $item['sales'] = app()->make(StoreOrderRepository::class)->seckillOrderCounut($item['product_id']); + return $item; + }); + $data->append(['seckill_status', 'us_status']); + + $list = hasMany( + $data , + 'sys_labels', + ProductLabel::class, + 'product_label_id', + 'sys_labels', + ['status' => 1], + 'product_label_id,product_label_id id,label_name name' + ); + + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @param array $where + * @param int $page + * @param int $limit + * @param $userInfo + * @return array + */ + public function getApiSearch($merId, array $where, int $page, int $limit, $userInfo) + { + $where = array_merge($where, $this->dao->productShow()); + //搜索记录 + if (isset($where['keyword']) && !empty($where['keyword'])) + app()->make(UserVisitRepository::class)->searchProduct( + $userInfo ? $userInfo['uid'] : 0, + $where['keyword'], + (int)($where['mer_id'] ?? 0) + ); + $query = $this->dao->search($merId, $where)->with(['merchant', 'issetCoupon']); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->field($this->admin_filed)->select(); + $append[] = 'max_extension'; + if ($this->getUserIsPromoter($userInfo)) $list->append($append); + return compact('count', 'list'); + } + + /** + * TODO 秒杀列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-08-04 + */ + public function getApiSeckill(array $where, int $page, int $limit) + { + $field = 'Product.product_id,Product.mer_id,is_new,U.keyword,brand_id,U.image,U.product_type,U.store_name,U.sort,U.rank,star,rate,reply_count,sales,U.price,cost,ot_price,stock,extension_type,care_count,unit_name,U.create_time'; + $make = app()->make(StoreOrderRepository::class); + $res = app()->make(StoreSeckillTimeRepository::class)->getBginTime($where); + $count = 0; + $list = []; + + if ($res) { + $where = [ + 'start_time' => $res['start_time'], + 'end_time' => $res['end_time'], + 'day' => date('Y-m-d', time()), + 'star' => '', + 'mer_id' => $where['mer_id'] + ]; + $query = $this->dao->seckillSearch($where)->with(['seckillActive']); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->field($field)->select() + ->each(function ($item) use ($make) { + $item['sales'] = $make->seckillOrderCounut($item['product_id']); + $item['stop'] = $item->end_time; + return $item; + }); + } + return compact('count', 'list'); + } + + /** + * TODO 平台礼包列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 2020-06-01 + */ + public function getBagList(array $where, int $page, int $limit) + { + $query = $this->dao->search(null, $where)->with(['merCateId.category', 'storeCategory', 'brand', 'merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name,product_score,service_score,postage_score,status,care_count,is_trader'); + }]); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->setOption('field', [])->field($this->filed)->select(); + + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @param array $where + * @return mixed + */ + public function getBrandByCategory(array $where) + { + $mer_id = $where['mer_id'] ? $where['mer_id'] : null; + unset($where['mer_id']); + $query = $this->dao->search($mer_id, $where); + return $query->group('brand_id')->column('brand_id'); + } + + /** + * api 获取商品详情 + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @param $userInfo + */ + public function detail(int $id, $userInfo,$product_type) + { + $where = [ + 'is_show' => 1, + 'status' => 1, + 'is_used' => 1, + 'mer_status' => 1, + 'product_id' => $id + ]; + return $this->apiProductDetail($where, $product_type, null, $userInfo); + } + + + /** + * TODO api秒杀商品详情 + * @param int $id + * @author Qinii + * @day 2020-08-05 + */ + public function seckillDetail(int $id,$userInfo) + { + $where = $this->seckillShow(); + $where['product_id'] = $id; + return $this->apiProductDetail($where, 1, null,$userInfo); + } + + public function apiProductDetail(array $where, int $productType, ?int $activityId, $userInfo = null) + { + + $field = 'is_show,product_id,mer_id,image,slider_image,store_name,store_info,unit_name,price,cost,ot_price,stock,sales,video_link,product_type,extension_type,old_product_id,rate,guarantee_template_id,temp_id,once_max_count,pay_limit,once_min_count,integral_rate,delivery_way,delivery_free,type,cate_id,svip_price_type,svip_price,mer_svip_status'; + $with = [ + 'attr', + 'content' => function($query) { + $query->order('type ASC'); + }, + 'attrValue', + 'oldAttrValue', + 'merchant' => function ($query) { + $query->with(['type_name'])->append(['isset_certificate','services_type']); + }, + 'seckillActive' => function ($query) { + $query->field('start_day,end_day,start_time,end_time,product_id'); + }, + 'temp' + ]; + + $append = ['guaranteeTemplate','params']; + $where['product_type'] = $productType; + $res = $this->dao->getWhere($where, $field, $with); + if (!$res) return []; + switch ($res['product_type']) { + case 0: + case 98: + $append[] = 'max_integral'; + $append[] = 'show_svip_info'; + break; + case 1: + $_where = $this->dao->productShow(); + $_where['product_id'] = $res['old_product_id']; + $oldProduct = $this->dao->getWhere($_where); + $result = $this->getSeckillAttrValue($res['attrValue'], $res['old_product_id']); + $res['attrValue'] = $result['item']; + + $res['stock'] = $result['stock']; + $res['stop'] = strtotime(date('Y-m-d', time()) . $res['seckillActive']['end_time'] . ':00:00'); + $res['sales'] = app()->make(StoreOrderRepository::class)->seckillOrderCounut($where['product_id']); + $res['quota'] = $this->seckillStock($where['product_id']); + $res['old_status'] = $oldProduct ? 1 : 0; + $append[] = 'seckill_status'; + break; + default: + break; + } + + if ($userInfo) { + try { + $isRelation = app()->make(UserRelationRepository::class)->getUserRelation(['type_id' => $activityId ?? $where['product_id'], 'type' => $res['product_type']], $userInfo['uid']); + } catch (\Exception $e) { + $isRelation = false; + } + if ($this->getUserIsPromoter($userInfo) && $productType == 0) { + $append[] = 'max_extension'; + $append[] = 'min_extension'; + } + } + + $attr = $this->detailAttr($res['attr']); + $attrValue = (in_array($res['product_type'], [3, 4])) ? $res['oldAttrValue'] : $res['attrValue']; + $sku = $this->detailAttrValue($attrValue, $userInfo, $productType, $activityId); + + $res['isRelation'] = $isRelation ?? false; + $care = false; + if ($userInfo) { + $care = app()->make(MerchantRepository::class)->getCareByUser($res['mer_id'], $userInfo->uid); + } + $res['merchant']['top_banner'] = merchantConfig($res['mer_id'], 'mer_pc_top'); + $res['merchant']['care'] = $care; + $res['replayData'] = null; + if (systemConfig('sys_reply_status')){ + $res['replayData'] = app()->make(ProductReplyRepository::class)->getReplyRate($res['product_id']); + $append[] = 'topReply'; + } + unset($res['attr'], $res['attrValue'], $res['oldAttrValue'], $res['seckillActive']); + if (count($attr) > 0) { + $firstSku = []; + foreach ($attr as $item) { + $firstSku[] = $item['attr_values'][0]; + } + $firstSkuKey = implode(',', $firstSku); + if (isset($sku[$firstSkuKey])) { + $sku = array_merge([$firstSkuKey => $sku[$firstSkuKey]], $sku); + } + } + $res['attr'] = $attr; + $res['sku'] = $sku; + $res->append($append); + + if ($res['content'] && $res['content']['type'] == 1) { + $res['content']['content'] = json_decode($res['content']['content']); + } + + $res['merchant']['recommend'] = $this->getRecommend($res['product_id'], $res['mer_id']); + $spu = app()->make(SpuRepository::class)->getSpuData( + $activityId ?: $res['product_id'], + $productType, + 0 + ); + $res['spu_id'] = $spu->spu_id; + if (systemConfig('community_status')) { + $res['community'] = app()->make(CommunityRepository::class)->getDataBySpu($spu->spu_id); + } + //热卖排行 + if (systemConfig('hot_ranking_switch') && $res['spu_id']) { + $hot = $this->getHotRanking($res['spu_id'], $res['cate_id']); + $res['top_name'] = $hot['top_name'] ?? ''; + $res['top_num'] = $hot['top_num'] ?? 0; + $res['top_pid'] = $hot['top_pid'] ?? 0; + } + //活动氛围图 + if (in_array($res['product_type'],[0,2,4])){ + $active = app()->make(StoreActivityRepository::class)->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_ATMOSPHERE,$res['spu_id'],$res['cate_id'],$res['mer_id']); + if ($active) $res['atmosphere_pic'] = $active['pic']; + } + return $res; + } + + + /** + * TODO 热卖排行 + * @param int $spuId + * @param int $cateId + * @return array + * @author Qinii + */ + public function getHotRanking(int $spuId, int $cateId) + { + $data = []; + //热卖排行 + $lv = systemConfig('hot_ranking_lv') ?:0; + $categoryMake = app()->make(StoreCategoryRepository::class); + $cate = $categoryMake->getWhere(['store_category_id' => $cateId]); + if ($lv != 2 && $cate) $cateId = $lv == 1 ? $cate->pathIds[2] : $cate->pathIds[1]; + $RedisCacheService = app()->make(RedisCacheService::class); + $prefix = env('QUEUE_NAME','merchant').'_hot_ranking_'; + $key = ( $prefix.'top_item_'.$cateId.'_'.$spuId); + $k1 = $RedisCacheService->keys($key); + if ($k1) { + $top = $RedisCacheService->handler()->get($key); + $top = json_decode($top); + $data['top_name'] = $top[0]; + $data['top_num'] = $top[1]; + $data['top_pid'] = $cateId; + } + return $data; + } + + /** + * TODO 商户下的推荐 + * @param $productId + * @param $merId + * @return array + * @author Qinii + * @day 12/7/21 + */ + public function getRecommend($productId,$merId) + { + $make = app()->make(ProductCateRepository::class); + $product_id = []; + if ($productId) { + $catId = $make->getSearch(['product_id' => $productId])->column('mer_cate_id'); + $product_id = $make->getSearch([])->whereIn('mer_cate_id',$catId)->column('product_id'); + } + + $query = $this->dao->getSearch([]) + ->where($this->dao->productShow()) + ->when($productId,function($query) use ($productId) { + $query->where('product_id','<>',$productId); + }) + ->when($product_id,function($query) use ($product_id) { + $query->whereIn('product_id',$product_id); + }) + ->where('mer_id',$merId); + $data = []; + $count = $query->count(); + + if ($count < 3) { + $productIds[] = $productId; + $data = $this->dao->getSearch([]) + ->where($this->dao->productShow()) + ->whereNotIn('product_id',$productIds) + ->where('mer_id', $merId) + ->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,sales,create_time') + ->order('sort DESC,create_time DESC') + ->limit((3 - $count)) + ->select()->toArray(); + } + + if ($count > 0 ){ + $count = $count > 3 ? 3 : $count; + $res = $query->setOption('field',[])->field('mer_id,product_id,store_name,image,price,is_show,status,is_gift_bag,is_good,sales,create_time') + ->order('sort DESC,create_time DESC') + ->limit($count) + ->select()->toArray(); + $data = array_merge($data, $res); + } + return $data; + } + + + + /** + * TODO 单商品属性 + * @param $data + * @return array + * @author Qinii + * @day 2020-08-05 + */ + public function detailAttr($data, $preview = 0, $user = null) + { + $attr = []; + foreach ($data as $key => $item) { + if ($item instanceof Arrayable) { + $attr[$key] = $item->toArray(); + } + $arr = []; + if ($preview) { + $item['attr_values'] = explode('-!-', $item['attr_values']); + $attr[$key]['attr_values'] = $item['attr_values']; + } + $values = $item['attr_values']; + foreach ($values as $i => $value) { + $arr[] = [ + 'attr' => $value, + 'check' => false + ]; + } + $attr[$key]['product_id'] = $item['product_id']; + $attr[$key]['attr_name'] = $item['attr_name']; + $attr[$key]['attr_value'] = $arr; + $attr[$key]['attr_values'] = $values; + } + return $attr; + } + + /** + * TODO 获取秒杀商品的库存数 + * @param array $data + * @param int $oldProductId + * @return array + * @author Qinii + * @day 2020-11-12 + */ + public function getSeckillAttrValue($data, $oldProductId) + { + /** + * 秒杀商品限购数量 + * 原商品库存 > 限购数 + * 销量 = 订单总数 - 退款退货 - (未发货且仅退款) + * 限购数 = 限购数 - 销量 + * 原商品库存 < 限购数 + * 限购数 = 原商品库存 + */ + $make = app()->make(ProductAttrValueRepository::class); + $order_make = app()->make(StoreOrderRepository::class); + $stock = 0; + $item = []; + foreach ($data as $k => $value) { + $where = [ + 'sku' => $value['sku'], + 'product_id' => $oldProductId + ]; + //愿商品库存信息 + $attr = $make->getWhere($where); + if ($attr) { + $value['stock'] = ($attr['stock'] < $value['stock']) ? + $attr['stock'] : + $value['stock'] - $order_make->seckillSkuOrderCounut($value['unique']); + } + $stock = $stock + $value['stock']; + $item[] = $value; + } + return compact('item', 'stock'); + } + /** + * TODO 单商品sku + * @param $data + * @param $userInfo + * @return array + * @author Qinii + * @day 2020-08-05 + */ + public function detailAttrValue($data, $userInfo, $productType = 0, $artiveId = null, $svipInfo = []) + { + $sku = []; + $make_presll = app()->make(ProductPresellSkuRepository::class); + $make_assist = app()->make(ProductAssistSkuRepository::class); + $make_group = app()->make(ProductGroupSkuRepository::class); + foreach ($data as $value) { + $_value = [ + 'sku' => $value['sku'], + 'price' => $value['price'], + 'stock' => $value['stock'], + 'image' => $value['image'], + 'weight' => $value['weight'], + 'volume' => $value['volume'], + 'sales' => $value['sales'], + 'unique' => $value['unique'], + 'bar_code' => $value['bar_code'], + ]; + if($productType == 0 ){ + $_value['ot_price'] = $value['ot_price']; + $_value['svip_price'] = $value['svip_price']; + } + if ($productType == 2) { + $_sku = $make_presll->getSearch(['product_presell_id' => $artiveId, 'unique' => $value['unique']])->find(); + if (!$_sku) continue; + $_value['price'] = $_sku['presell_price']; + $_value['stock'] = $_sku['stock']; + $_value['down_price'] = $_sku['down_price']; + } + //助力 + if ($productType == 3) { + $_sku = $make_assist->getSearch(['product_assist_id' => $artiveId, 'unique' => $value['unique']])->find(); + if (!$_sku) continue; + $_value['price'] = $_sku['assist_price']; + $_value['stock'] = $_sku['stock']; + } + //拼团 + if ($productType == 4) { + $_sku = $make_group->getSearch(['product_group_id' => $artiveId, 'unique' => $value['unique']])->find(); + if (!$_sku) continue; + $_value['price'] = $_sku['active_price']; + $_value['stock'] = $_sku['stock']; + } + //推广员 + if ($this->getUserIsPromoter($userInfo)) { + $_value['extension_one'] = $value->bc_extension_one; + $_value['extension_two'] = $value->bc_extension_two; + } + $sku[$value['sku']] = $_value; + } + return $sku; + } + + + /** + * TODO 秒杀商品库存检测 + * @param int $productId + * @return bool|int + * @author Qinii + * @day 2020-08-05 + */ + public function seckillStock(int $productId) + { + $product = $this->dao->getWhere(['product_id' => $productId], '*', ['attrValue']); + $count = app()->make(StoreOrderRepository::class)->seckillOrderCounut($productId); + if ($product['stock'] > $count) { + $make = app()->make(ProductAttrValueRepository::class); + foreach ($product['attrValue'] as $item) { + $attr = [ + ['sku', '=', $item['sku']], + ['product_id', '=', $product['old_product_id']], + ['stock', '>', 0], + ]; + if ($make->getWhereCount($attr)) return true; + } + } + return false; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $userInfo + * @return bool + */ + public function getUserIsPromoter($userInfo) + { + return (isset($userInfo['is_promoter']) && $userInfo['is_promoter'] && systemConfig('extension_status')) ? true : false; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $userInfo + * @param int|null $merId + * @param $page + * @param $limit + * @return array + */ + public function recommend($userInfo, ?int $merId, $page, $limit) + { + $where = ['order' => 'sales']; + if (!is_null($userInfo)) { + $cate_ids = app()->make(UserVisitRepository::class)->getRecommend($userInfo['uid']); + if ($cate_ids) $where = ['cate_ids' => $cate_ids]; + } + $where = array_merge($where, $this->switchType(1, $merId, 0), $this->dao->productShow()); + $query = $this->dao->search($merId, $where); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->with(['issetCoupon', 'merchant'])->select(); + + return compact('count', 'list'); + } + + /** + * 检测是否有效 + * @Author:Qinii + * @Date: 2020/6/1 + * @param $id + * @return mixed + */ + public function getOne($id) + { + $data = ($this->dao->getWhere([$this->dao->getPk() => $id])); + if (!is_null($data) && $data->check()) return $data; + return false; + } + + /** + * TODO 上下架 / 显示 + * @param $id + * @param $status + * @author Qinii + * @day 2022/11/12 + */ + public function switchShow($id, $status, $field, $merId = 0) + { + $where['product_id'] = $id; + if ($merId) $where['mer_id'] = $merId; + $product = $this->dao->getWhere($where); + if (!$product) throw new ValidateException('数据不存在'); + if ($status == 1 && $product['product_type'] == 2) + throw new ValidateException('商品正在参与预售活动'); + if ($status == 1 && $product['product_type'] == 3) + throw new ValidateException('商品正在参与助力活动'); + $this->dao->update($id,[$field => $status]); + app()->make(SpuRepository::class)->changeStatus($id,$product->product_type); + } + + public function batchSwitchShow($id, $status, $field, $merId = 0) + { + $where['product_id'] = $id; + if ($merId) $where['mer_id'] = $merId; + $products = $this->dao->getSearch([])->where('product_id','in', $id)->select(); + if (!$products) + throw new ValidateException('数据不存在'); + foreach ($products as $product) { + $product_type = $product['product_type']; + if ($merId && $product['mer_id'] !== $merId) + throw new ValidateException('商品不属于您'); + if ($status == 1 && $product['product_type'] == 2) + throw new ValidateException('ID:'.$product->product_id . ' 商品正在参与预售活动'); + if ($status == 1 && $product['product_type'] == 3) + throw new ValidateException('ID:'.$product->product_id . ' 商品正在参与助力活动'); + } + $this->dao->updates($id,[$field => $status]); + Queue::push(ChangeSpuStatusJob::class,['id' => $id,'product_type'=> $product_type]); + } + + /** + * TODO 商品审核 + * @param $id + * @param $data + * @author Qinii + * @day 2022/11/14 + */ + public function switchStatus($id,$data) + { + $product = $this->getSearch([])->find($id); + $this->dao->update($id, $data); + $status = $data['status']; + $type = self::NOTIC_MSG[$data['status']][$product['product_type']]; + $message = '您有1个' . ($product['product_type'] ? '秒杀商品' : '商品') . self::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $status == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $product['product_id'] + ] + ], $product['mer_id']); + app()->make(SpuRepository::class)->changeStatus($id,$product->product_type); + } + + /** + * TODO 审核操作 + * @param array $id + * @param array $data + * @param $product_type + * @author Qinii + * @day 2022/9/6 + */ + public function batchSwitchStatus(array $id,array $data) + { + $productData = $this->getSearch([])->where('product_id','in', $id)->select(); + foreach ($productData as $product) { + $product_type = $product['product_type']; + $type = self::NOTIC_MSG[$data['status']][$product['product_type']]; + $message = '您有1个' . ($product['product_type'] ? '秒杀商品' : '商品') . self::NOTIC_MSG[$data['status']]['msg']; + SwooleTaskService::merchant('notice', [ + 'type' => $type, + 'data' => [ + 'title' => $data['status'] == -2 ? '下架提醒' : '审核结果', + 'message' => $message, + 'id' => $product['product_id'] + ] + ], $product['mer_id']); + } + $this->dao->updates($id, $data); + Queue(ChangeSpuStatusJob::class, ['id' => $id, 'product_type' => $product_type]); + event('product.status',compact('id','data')); + } + + + public function wxQrCode(int $productId, int $productType, User $user) + { + $name = md5('pwx' . $productId . $productType . $user->uid . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $make = app()->make(QrcodeService::class); + $link = ''; + switch ($productType) { + case 0: //普通商品 + $link = '/pages/goods_details/index'; + break; + case 1: //秒杀商品 + $link = '/pages/activity/goods_seckill_details/index'; + break; + case 2: //预售商品 + $link = '/pages/activity/presell_details/index'; + break; + case 3: //助力商品 + $link = 'pages/activity/assist_detail/index'; + break; + case 4: //拼团商品 + $link = '/pages/activity/combination_details/index'; + break; + case 40: //拼团商品2 + $link = '/pages/activity/combination_status/index'; + break; + default: + return false; + } + $link = $link . '?id=' . $productId . '&spid=' . $user['uid']; + $key = 'p' . $productType . '_' . $productId . '_' . $user['uid']; + return $make->getWechatQrcodePath($name, $link, false, $key); + } + + public function routineQrCode(int $productId, int $productType, User $user) + { + //小程序 + $name = md5('sprt' . $productId . $productType . $user->uid . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $make = app()->make(QrcodeService::class); + $params = 'id=' . $productId . '&spid=' . $user['uid']; + $link = ''; + switch ($productType) { + case 0: //普通商品 + $link = 'pages/goods_details/index'; + break; + case 1: //秒杀商品 + $link = 'pages/activity/goods_seckill_details/index'; + break; + case 2: //预售商品 + $link = 'pages/activity/presell_details/index'; + break; + case 4: //拼团商品 + $link = 'pages/activity/combination_details/index'; + break; + case 40: //拼团商品2 + $link = 'pages/activity/combination_status/index'; + break; + } + + return $make->getRoutineQrcodePath($name, $link, $params); + } + + /** + * TODO 礼包是否超过数量限制 + * @param $merId + * @return bool + * @author Qinii + * @day 2020-06-25 + */ + public function checkMerchantBagNumber($merId) + { + $where = ['is_gift_bag' => 1]; + $promoter_bag_number = systemConfig('max_bag_number'); + $count = $this->dao->search($merId, $where)->count(); + if (is_null($promoter_bag_number) || ($promoter_bag_number > $count)) return true; + return false; + } + + public function orderProductIncStock($order, $cart, $productNum = null) + { + $productNum = $productNum ?? $cart['product_num']; + Db::transaction(function () use ($order, $cart, $productNum) { + $productAttrValueRepository = app()->make(ProductAttrValueRepository::class); + if ($cart['product_type'] == '1') { + $oldId = $cart['cart_info']['product']['old_product_id']; + $productAttrValueRepository->incSkuStock($oldId, $cart['cart_info']['productAttr']['sku'], $productNum); + $this->dao->incStock($oldId, $productNum); + } else if ($cart['product_type'] == '2') { + $presellSku = app()->make(ProductPresellSkuRepository::class); + $presellSku->incStock($cart['cart_info']['productPresellAttr']['product_presell_id'], $cart['cart_info']['productPresellAttr']['unique'], $productNum); + $productAttrValueRepository->incStock($cart['product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + $this->dao->incStock($cart['product_id'], $productNum); + } else if ($cart['product_type'] == '3') { + app()->make(ProductAssistSkuRepository::class)->incStock($cart['cart_info']['productAssistAttr']['product_assist_id'], $cart['cart_info']['productAssistAttr']['unique'], $productNum); + $productAttrValueRepository->incStock($cart['cart_info']['product']['old_product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + $this->dao->incStock($cart['cart_info']['product']['old_product_id'], $productNum); + } else if ($cart['product_type'] == '4') { + app()->make(ProductGroupSkuRepository::class)->incStock($cart['cart_info']['activeSku']['product_group_id'], $cart['cart_info']['activeSku']['unique'], $productNum); + $this->dao->incStock($cart['cart_info']['product']['old_product_id'], $productNum); + $productAttrValueRepository->incStock($cart['cart_info']['product']['old_product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + } else { + if (isset($cart['cart_info']['product']['old_product_id']) && $cart['cart_info']['product']['old_product_id'] > 0) { + $oldId = $cart['cart_info']['product']['old_product_id']; + $productAttrValueRepository->incSkuStock($oldId, $cart['cart_info']['productAttr']['sku'], $productNum); + $this->dao->incStock($oldId, $productNum); + } else { + $productAttrValueRepository->incStock($cart['product_id'], $cart['cart_info']['productAttr']['unique'], $productNum); + $this->dao->incStock($cart['product_id'], $productNum); + } + if ($cart->integral > 0) { + $totalIntegral = bcmul($productNum, $cart->integral, 0); + $this->dao->descIntegral($cart->product_id, $totalIntegral, bcmul(bcdiv($totalIntegral, $order->integral, 2), $order->integral_price, 2)); + } + } + }); + } + + + public function fictiForm(int $id) + { + $form = Elm::createForm(Route::buildUrl('systemStoreProductAddFicti', ['id' => $id])->build()); + $res = $this->dao->getWhere(['product_id' => $id], 'ficti,sales'); + $form->setRule([ + Elm::input('number', '现有已售数量', $res['ficti'])->readonly(true), + Elm::radio('type', '修改类型', 1) + ->setOptions([ + ['value' => 1, 'label' => '增加'], + ['value' => 2, 'label' => '减少'], + ]), + Elm::number('ficti', '修改已售数量', 0), + ]); + return $form->setTitle('修改已售数量'); + } + + /** + * TODO 普通商品加入购物车检测 + * @param int $prodcutId + * @param string $unique + * @param int $cartNum + * @author Qinii + * @day 2020-10-20 + */ + public function cartCheck(array $data, $userInfo) + { + $cart = null; + $where = $this->dao->productShow(); + $where['product_id'] = $data['product_id']; + $where['product_type'] = $data['product_type']; + unset($where['is_gift_bag']); + $product = $this->dao->search(null, $where)->find(); + + if (!$product) throw new ValidateException('商品已下架'); + if ($product['type'] && !$data['is_new']) throw new ValidateException('虚拟商品不可加入购物车'); + $value_make = app()->make(ProductAttrValueRepository::class); + $sku = $value_make->getOptionByUnique($data['product_attr_unique']); + if (!$sku) throw new ValidateException('SKU不存在'); + //分销礼包 + if ($product['is_gift_bag']) { + if (!systemConfig('extension_status')) throw new ValidateException('分销功能未开启'); + if (!$data['is_new']) throw new ValidateException('礼包商品不可加入购物车'); + if ($data['cart_num'] !== 1) throw new ValidateException('礼包商品只能购买一个'); + if ($userInfo->is_promoter) throw new ValidateException('您已经是分销员了'); + } + + //立即购买 限购 + if ($data['is_new']) { + $cart_num = $data['cart_num']; + } else { + //加入购物车 + //购物车现有 + $_num = $this->productOnceCountCart($where['product_id'],$data['product_attr_unique'], $userInfo->uid,$data['product_type']); + $cart_num = $_num + $data['cart_num']; + } + if ($sku['stock'] < $cart_num ) throw new ValidateException('库存不足'); + //添加购物车 + if (!$data['is_new']) { + $cart = app()->make(StoreCartRepository::class)->getCartByProductSku($data['product_attr_unique'], $userInfo->uid,$data['product_type']); + } + return compact('product', 'sku', 'cart'); + } + + /** + * TODO 购物车单商品数量 + * @param $productId + * @param $uid + * @param $num + * @author Qinii + * @day 5/26/21 + */ + public function productOnceCountCart($productId,$product_attr_unique,$uid,$product_type=0) + { + $make = app()->make(StoreCartRepository::class); + $where = [ + 'is_pay' => 0, + 'is_del' => 0, + 'is_new' => 0, + 'is_fail' => 0, + 'product_type' => $product_type, + 'product_id' => $productId, + 'uid' => $uid, + 'product_attr_unique' => $product_attr_unique, + ]; + $cart_num = $make->getSearch($where)->sum('cart_num'); + return $cart_num; + } + + /** + * TODO 秒杀商品加入购物车检测 + * @param array $data + * @param int $userInfo + * @return array + * @author Qinii + * @day 2020-10-21 + */ + public function cartSeckillCheck(array $data, $userInfo) + { + if ($data['is_new'] !== 1) throw new ValidateException('秒杀商品不能加入购物车'); + if ($data['cart_num'] !== 1) throw new ValidateException('秒杀商品只能购买一个'); + + $where = $this->dao->seckillShow(); + $where['product_id'] = $data['product_id']; + $product = $this->dao->search(null, $where)->find(); + if (!$product) throw new ValidateException('商品已下架'); + if ($product->seckill_status !== 1) throw new ValidateException('该商品不在秒杀时间段内'); + $order_make = app()->make(StoreOrderRepository::class); + $count = $order_make->seckillOrderCounut($data['product_id']); + + $value_make = app()->make(ProductAttrValueRepository::class); + $sku = $value_make->getOptionByUnique($data['product_attr_unique']); + + if ($sku['stock'] <= $count) throw new ValidateException('限购数量不足'); + $_sku = $value_make->getWhere(['sku' => $sku['sku'], 'product_id' => $product['old_product_id']]); + if (!$_sku) throw new ValidateException('原商品SKU不存在'); + if ($_sku['stock'] <= 0) throw new ValidateException('原库存不足'); + + if (!$order_make->getDayPayCount($userInfo->uid, $data['product_id'])) + throw new ValidateException('本次活动您购买数量已达到上限'); + if (!$order_make->getPayCount($userInfo->uid, $data['product_id'])) + throw new ValidateException('本次活动您该商品购买数量已达到上限'); + $cart = null; + return compact('product', 'sku', 'cart'); + } + + /** + * TODO 复制一条商品 + * @param int $productId + * @param array $data + * @return mixed + * @author Qinii + * @day 2020-11-19 + */ + public function productCopy(int $productId, array $data, $productType = 0) + { + $product = $this->getAdminOneProduct($productId, null); + $product = $product->toArray(); + if ($data) { + foreach ($data as $k => $v) { + $product[$k] = $v; + } + } + return $this->create($product, $productType); + } + + public function existsProduct(int $id, $productType) + { + switch ($productType) { + case 2: + $make = app()->make(ProductPresellRepository::class); + break; + case 3: + $make = app()->make(ProductAssistSetRepository::class); + break; + case 4: + $make = app()->make(ProductGroupRepository::class); + break; + case 40: + $make = app()->make(ProductGroupBuyingRepository::class); + break; + default: + $make = $this->dao; + break; + } + $where = [ + $make->getPk() => $id, + 'is_del' => 0 + ]; + return $make->getWhereCount($where); + } + + public function updateSort(int $id, ?int $merId, array $data) + { + $where[$this->dao->getPk()] = $id; + if ($merId) $where['mer_id'] = $merId; + $ret = $this->dao->getWhere($where); + if (!$ret) throw new ValidateException('数据不存在'); + app()->make(ProductRepository::class)->update($ret['product_id'], $data); + $make = app()->make(SpuRepository::class); + $activityId = $ret['product_type'] ? $ret->seckillActive->seckill_active_id : 0; + return $make->updateSort($ret['product_id'], $activityId, $ret['product_type'], $data); + } + + /** + * TODO 删除商户所有的 + * @param int $merId + * @author Qinii + * @day 5/15/21 + */ + public function clearMerchantProduct($merId) + { + /** + * 删除商户所有的 + * 商品, + * 分类, + * 品牌 + */ + //普通 秒杀 + $this->dao->clearProduct($merId); + //助理 + app()->make(ProductAssistRepository::class)->clearProduct($merId); + //拼团 + app()->make(ProductGroupRepository::class)->clearProduct($merId); + //预售 + app()->make(ProductPresellRepository::class)->clearProduct($merId); + //spu + app()->make(SpuRepository::class)->clearProduct($merId); + } + + /** + * TODO 保障服务 + * @param $where + * @return mixed + * @author Qinii + * @day 5/20/21 + */ + public function GuaranteeTemplate($where) + { + $data = app()->make(GuaranteeTemplateRepository::class)->getSearch($where)->with( + [ + 'templateValue' => [ + 'value' => function($query){ + $query->field('guarantee_id,guarantee_name,guarantee_info'); + } + ], + ])->find(); + return $data ?? []; + } + + /** + * TODO 添加到货通知 + * @param int $uid + * @param string $unique + * @param int $type + * @author Qinii + * @day 5/24/21 + */ + public function increaseTake(int $uid, string $unique,int $type,int $product_id) + { + $status = systemConfig('procudt_increase_status'); + if(!$status) throw new ValidateException('未开启到货通知'); + $make = app()->make(ProductTakeRepository::class); + $where['product_id'] = $product_id; + if($unique) $where['unique'] = $unique; + $sku = app()->make(ProductAttrValueRepository::class)->getWhere($where); + if(!$sku) throw new ValidateException('商品不存在'); + $data = [ + 'product_id' => $sku['product_id'], + 'unique' => $unique ?: 1, + 'uid' => $uid, + 'status' => 0, + 'type' => $type + ]; + $make->findOrCreate($data); + } + + /** + * TODO 添加 编辑 预览商品 + * @param array $data + * @param int $productType + * @return array + * @author Qinii + * @day 6/15/21 + */ + public function preview(array $data) + { + if (!isset($data['attrValue']) || !$data['attrValue']) { + throw new ValidateException('缺少商品规格'); + } + $productType = 0; + $product = $this->setProduct($data); + if(isset($data['start_day'])){ //秒杀 + $product['stop'] = time() + 3600; + $productType = 1; + } + if(isset($data['presell_type'])){ //预售 + $product['start_time'] = $data['start_time']; + $product['end_time'] = $data['end_time']; + $product['presell_type'] = $data['presell_type']; + $product['delivery_type'] = $data['delivery_type']; + $product['delivery_day'] = $data['delivery_day']; + $product['p_end_time'] = $data['end_time']; + $product['final_start_time'] = $data['final_start_time']; + $product['final_end_time'] = $data['final_end_time']; + $productType = 2; + } + + if(isset($data['assist_count'])){ + //助力 + $product['assist_count'] = $data['assist_count']; + $product['assist_user_count'] = $data['assist_user_count']; + $product['price'] = $data['attrValue'][0]['assist_price']; + $productType = 3; + } + + if(isset($data['buying_count_num'])) { + // + $product['buying_count_num'] = $data['buying_count_num']; + $product['pay_count'] = $data['pay_count']; + $productType = 4; + } + + $product['slider_image'] = explode(',',$product['slider_image']); + $product['merchant'] = $data['merchant']; + $product['content'] = ['content' => $data['content']]; + $settleParams = $this->setAttrValue($data, 0, $productType, 0); + $settleParams['attr'] = $this->setAttr($data['attr'], 0); + + $product['price'] = $settleParams['data']['price']; + $product['stock'] = $settleParams['data']['stock']; + $product['cost'] = $settleParams['data']['cost']; + $product['ot_price'] = $settleParams['data']['ot_price']; + $product['product_type'] = $productType; + foreach ($settleParams['attrValue'] as $k => $value) { + $_value = [ + 'sku' => $value['sku'], + 'price' => $value['price'], + 'stock' => $value['stock'], + 'image' => $value['image'], + 'weight' => $value['weight'], + 'volume' => $value['volume'], + 'sales' => $value['sales'], + 'unique' => $value['unique'], + 'bar_code' => $value['bar_code'], + ]; + $sku[$value['sku']] = $_value; + } + $preview_key = 'preview'.$data['mer_id'].$productType.'_'.time(); + unset($settleParams['data'],$settleParams['attrValue']); + $settleParams['sku'] = $sku; + $settleParams['attr'] = $this->detailAttr($settleParams['attr'],1); + + if(isset($data['guarantee_template_id'])) { + $guarantee_id = app()->make(GuaranteeValueRepository::class)->getSearch(['guarantee_template_id' => $data['guarantee_template_id']])->column('guarantee_id'); + $product['guaranteeTemplate'] = app()->make(GuaranteeRepository::class)->getSearch(['status' => 1, 'is_del' => 0])->where('guarantee_id', 'in', $guarantee_id)->select(); + } + if(isset($data['temp_id'])) { + $product['temp'] = app()->make(ShippingTemplateRepository::class)->getSearch(['shipping_template_id' => $data['temp_id']])->find(); + } + + $ret = array_merge($product,$settleParams); + + Cache::set($preview_key,$ret); + + return compact('preview_key','ret'); + } + + + /** + * TODO 列表查看预览 + * @param array $data + * @return array|\think\Model|null + * @author Qinii + * @day 7/9/21 + */ + public function getPreview(array $data) + { + switch($data['product_type']) + { + case 0: + return $this->apiProductDetail(['product_id' => $data['id']], 0, 0); + break; + case 1: + $ret = $this->apiProductDetail(['product_id' => $data['id']], 1, 0); + $ret['stop'] = time() + 3600; + break; + case 2: + $make = app()->make(ProductPresellRepository::class); + $res = $make->getWhere([$make->getPk()=> $data['id']])->toArray(); + $ret = $this->apiProductDetail(['product_id' => $res['product_id']], 2, $data['id'])->toArray(); + $ret['ot_price'] = $ret['price']; + $ret['start_time'] = $res['start_time']; + $ret['p_end_time'] = $res['end_time']; + $ret = array_merge($ret,$res); + break; + case 3: + $make = app()->make(ProductAssistRepository::class); + $res = $make->getWhere([$make->getPk()=> $data['id']])->toArray(); + $ret = $this->apiProductDetail(['product_id' => $res['product_id']], 3, $data['id'])->toArray(); + + $ret = array_merge($ret,$res); + foreach ($ret['sku'] as $value){ + $ret['price'] = $value['price']; + $ret['stock'] = $value['stock']; + } + break; + case 4: + $make = app()->make(ProductGroupRepository::class); + $res = $make->get($data['id'])->toArray(); + $ret = $this->apiProductDetail(['product_id' => $res['product_id']], 4, $data['id'])->toArray(); + $ret['ot_price'] = $ret['price']; + $ret = array_merge($ret,$res); + break; + default: + break; + } + return $ret; + } + + public function setLabels($id, $data, $merId = 0) + { + $where['product_id'] = $id; + $field = isset($data['sys_labels']) ? 'sys_labels' : 'mer_labels'; + if ($merId) $where['mer_id'] = $merId; + app()->make(ProductLabelRepository::class)->checkHas($merId,$data[$field]); + $ret = $this->dao->getWhere($where); + + $activeId = $ret->seckillActive->seckill_active_id ?? 0; + + $spu = ['activity_id' => $activeId, 'product_type' => $ret['product_type'], 'product_id' => $id]; + $ret = app()->make(SpuRepository::class)->getWhere($spu); + if (!$ret) throw new ValidateException('数据不存在'); + $ret->$field = $data[$field]; + $ret->save(); + } + + public function getAttrValue(int $id, int $merId) + { + $data = $this->dao->getWhere(['product_id' => $id, 'mer_id' => $merId]); + if (!$data) throw new ValidateException('数据不存在'); + return app()->make(ProductAttrValueRepository::class)->getSearch(['product_id' => $id])->select()->append(['is_svip_price']); + } + + public function checkParams($data,$merId,$id = null) + { + if (!$data['pay_limit']) $data['once_max_count'] = 0; + if ($data['brand_id'] > 0 && !$this->merBrandExists($data['brand_id'])) + throw new ValidateException('品牌不存在'); + if (!$this->CatExists($data['cate_id'])) + throw new ValidateException('平台分类不存在'); + if (isset($data['mer_cate_id']) && !$this->merCatExists($data['mer_cate_id'], $merId)) + throw new ValidateException('不存在的商户分类'); + if ($data['delivery_way'] == 2 && !$this->merShippingExists($merId, $data['temp_id'])) + throw new ValidateException('运费模板不存在'); + if (isset($data['type']) && $data['type'] && $data['extend']) { + $key = ['email','text','number','date','time','idCard','mobile','image']; + if (count($data['extend']) > 10) throw new ValidateException('附加表单不能超过10条'); + $title = []; + foreach ($data['extend'] as $item) { + if (empty($item['title']) ) + throw new ValidateException('表单名称不能为空:'.$item['key']); + if (in_array($item['title'],$title)) + throw new ValidateException('表单名称不能重复:'.$item['title']); + $title[] = $item['title']; + if (!in_array($item['key'], $key)) + throw new ValidateException('表单类型错误:'.$item['key']); + $extend[] = [ + 'title' => $item['title'], + 'key' => $item['key'] , + 'require' => $item['require'], + ]; + } + } + app()->make(ProductLabelRepository::class)->checkHas($merId,$data['mer_labels']); + $count = app()->make(StoreCategoryRepository::class)->getWhereCount(['store_category_id' => $data['cate_id'],'is_show' => 1]); + if (!$count) throw new ValidateException('平台分类不存在或不可用'); + app()->make(StoreProductValidate::class)->check($data); + if ($id) unset($data['type']); + $data['extend'] = $extend ?? []; + //单次限购 + return $data; + } +} diff --git a/app/common/repositories/store/product/ProductSkuRepository.php b/app/common/repositories/store/product/ProductSkuRepository.php new file mode 100644 index 00000000..80a49914 --- /dev/null +++ b/app/common/repositories/store/product/ProductSkuRepository.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductSkuDao; +use app\common\repositories\BaseRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class ProductSkuRepository extends BaseRepository +{ + public function __construct(ProductSkuDao $dao) + { + $this->dao = $dao; + } + + const ACTIVE_TYPE_DISCOUNTS = 10; + public function save(int $id, int $productId, array $data, $activeProductId = 0) + { + $storeProductServices = app()->make(ProductAttrValueRepository::class); + foreach ($data as $item) { + $skuData = $storeProductServices->search(['unique' => $item['unique']])->find(); + if (!$skuData) throw new ValidateException('属性规格不存在'); + $activeSku[] = [ + 'active_id' => $id, + 'active_product_id' => $activeProductId, + 'product_id' => $productId, + 'active_type' => self::ACTIVE_TYPE_DISCOUNTS, + 'price' => $skuData['price'], + 'active_price' => $item['active_price'] ?? $skuData['price'], + 'unique' => $item['unique'], + ]; + } + $this->dao->insertAll($activeSku); + } +} diff --git a/app/common/repositories/store/product/ProductTakeRepository.php b/app/common/repositories/store/product/ProductTakeRepository.php new file mode 100644 index 00000000..d1604e31 --- /dev/null +++ b/app/common/repositories/store/product/ProductTakeRepository.php @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\ProductTakeDao; +use app\common\repositories\BaseRepository; + +class ProductTakeRepository extends BaseRepository +{ + protected $dao; + + public function __construct(ProductTakeDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/product/SpuRepository.php b/app/common/repositories/store/product/SpuRepository.php new file mode 100644 index 00000000..af50800b --- /dev/null +++ b/app/common/repositories/store/product/SpuRepository.php @@ -0,0 +1,532 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\repositories\store\coupon\StoreCouponProductRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\StoreActivityRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\jobs\SyncProductTopJob; +use crmeb\services\CopyCommand; +use crmeb\services\RedisCacheService; +use think\exception\ValidateException; +use think\facade\Log; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\SpuDao; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\user\UserVisitRepository; +use think\facade\Queue; + +class SpuRepository extends BaseRepository +{ + public $dao; + public $merchantFiled = 'mer_id,mer_name,mer_avatar,is_trader,mer_info,mer_keyword,type_id'; + public $productFiled = 'P.bar_code,S.product_id,S.store_name,S.image,activity_id,S.keyword,S.price,S.mer_id,spu_id,S.status,store_info,brand_id,cate_id,unit_name,S.star,S.rank,S.sort,sales,S.product_type,rate,reply_count,extension_type,S.sys_labels,S.mer_labels,P.delivery_way,P.delivery_free,P.ot_price,svip_price_type,stock,mer_svip_status'; + public function __construct(SpuDao $dao) + { + $this->dao = $dao; + } + + public function create(array $param, int $productId, int $activityId, $productType = 0) + { + $data = $this->setparam($param, $productId, $activityId, $productType); + return $this->dao->create($data); + } + + public function baseUpdate(array $param, int $productId, int $activityId, $productType = 0) + { + if ($productType == 1) { + $make = app()->make(StoreSeckillActiveRepository::class); + $activityId = $make->getSearch(['product_id' => $productId])->value('seckill_active_id'); + } + $where = [ + 'product_id' => $productId, + 'activity_id' => $activityId, + 'product_type' => $productType, + ]; + $ret = $this->dao->getSearch($where)->find(); + if (!$ret) { + return $this->create($param, $productId, $activityId, $productType); + } else { + $data = $this->setparam($param, $productId, $activityId, $productType); + + $value = $data['mer_labels']; + if (!empty($value)) { + if (!is_array($value)) { + $data['mer_labels'] = ',' . $value . ','; + } else { + $data['mer_labels'] = ',' . implode(',', $value) . ','; + } + } + return $this->dao->update($ret->spu_id, $data); + } + } + + public function setparam(array $param, $productId, $activityId, $productType) + { + + $data = [ + 'product_id' => $productId, + 'product_type' => $productType ?? 0, + 'activity_id' => $activityId, + 'store_name' => $param['store_name'], + 'keyword' => $param['keyword'] ?? '', + 'image' => $param['image'], + 'price' => $param['price'], + 'status' => 0, + 'rank' => $param['rank'] ?? 0, + 'temp_id' => $param['temp_id'], + 'sort' => $param['sort'] ?? 0, + 'mer_labels' => $param['mer_labels'] ?? '', + ]; + if (isset($param['mer_id'])) $data['mer_id'] = $param['mer_id']; + return $data; + } + + /** + * TODO 修改排序 + * @param $productId + * @param $activityId + * @param $productType + * @param $data + * @author Qinii + * @day 1/19/21 + */ + public function updateSort($productId, $activityId, $productType, $data) + { + $where = [ + 'product_id' => $productId, + 'activity_id' => $activityId, + 'product_type' => $productType, + ]; + $ret = $this->dao->getSearch($where)->find(); + if ($ret) $this->dao->update($ret['spu_id'], $data); + } + /** + * TODO 移动端列表 + * @param $where + * @param $page + * @param $limit + * @param $userInfo + * @return array + * @author Qinii + * @day 12/18/20 + */ + public function getApiSearch($where, $page, $limit, $userInfo = null) + { + if (isset($where['keyword']) && !empty($where['keyword'])) { + if (preg_match('/^(\/@[1-9]{1}).*\*\//', $where['keyword'])) { + $command = app()->make(CopyCommand::class)->getMassage($where['keyword']); + if (!$command || in_array($command['type'], [30, 40])) return ['count' => 0, 'list' => []]; + if ($userInfo && $command['uid']) app()->make(UserRepository::class)->bindSpread($userInfo, $command['uid']); + $where['spu_id'] = $command['id']; + unset($where['keyword']); + } else { + app()->make(UserVisitRepository::class)->searchProduct($userInfo ? $userInfo['uid'] : 0, $where['keyword'], (int)($where['mer_id'] ?? 0)); + } + } + $where['spu_status'] = 1; + $where['mer_status'] = 1; + $query = $this->dao->search($where); + + $query->with([ + 'merchant' => function ($query) { + $query->field($this->merchantFiled)->with(['type_name']); + }, + 'issetCoupon', + ]); + $productMake = app()->make(ProductRepository::class); + $count = $query->count(); + + $list = $query->page($page, $limit)->setOption('field', [])->field($this->productFiled)->select(); + $append = ['stop_time','svip_price','show_svip_info','is_svip_price']; + if ($productMake->getUserIsPromoter($userInfo)) + $append[] = 'max_extension'; + $list->append($append); + $list = $this->getBorderList($list); + return compact('count', 'list'); + } + + public function getBorderList($list) + { + $make = app()->make(StoreActivityRepository::class); + foreach ($list as $item) { + $act = $make->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_BORDER,$item['spu_id'],$item['cate_id'],$item['mer_id']); + $item['border_pic'] = $act['pic'] ?? ''; + } + return $list; + } + + + /** + * TODO 修改状态 + * @param array $data + * @author Qinii + * @day 12/18/20 + */ + public function changeStatus(int $id, int $productType) + { + $make = app()->make(ProductRepository::class); + $where = []; + $status = 1; + try { + switch ($productType) { + case 0: + $where = [ + 'activity_id' => 0, + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 1: + $_make = app()->make(StoreSeckillActiveRepository::class); + $res = $_make->getSearch(['product_id' => $id])->find(); + $endday = strtotime($res['end_day']); + if ($res['status'] == -1 || $endday < time()) $status = 0; + $where = [ + 'activity_id' => $res['seckill_active_id'], + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 2: + $_make = app()->make(ProductPresellRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + + $endttime = strtotime($res['end_time']); + if ($endttime <= time()) { + $status = 0; + } else { + if ( + $res['product_status'] !== 1 || + $res['status'] !== 1 || + $res['action_status'] !== 1 || + $res['is_del'] !== 0 || + $res['is_show'] !== 1 + ) { + $status = 0; + } + } + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 3: + $_make = app()->make(ProductAssistRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + + $endttime = strtotime($res['end_time']); + if ($endttime <= time()) { + $status = 0; + } else { + if ( + $res['product_status'] !== 1 || + $res['status'] !== 1 || + $res['is_show'] !== 1 || + $res['action_status'] !== 1 || + $res['is_del'] !== 0 + ) { + $status = 0; + } + } + + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 4: + $_make = app()->make(ProductGroupRepository::class); + $wher = $_make->actionShow(); + $wher[$_make->getPk()] = $id; + + $res = $_make->getWhere([$_make->getPk() => $id]); + $endttime = strtotime($res['end_time']); + if ($endttime <= time()) { + $status = 0; + } else { + if ( + $res['product_status'] !== 1 || + $res['status'] !== 1 || + $res['is_show'] !== 1 || + $res['action_status'] !== 1 || + $res['is_del'] !== 0 + ) { + $status = 0; + } + } + + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + default: + break; + } + $ret = $make->getWhere(['product_id' => $where['product_id']]); + if (!$ret || $ret['status'] !== 1 || $ret['mer_status'] !== 1 || $ret['is_del']) $status = 0; + if (in_array($productType, [0, 1]) && ($ret['is_show'] !== 1 || $ret['is_used'] !== 1)) $status = 0; + $result = $this->dao->getSearch($where)->find(); + if (!$result && $ret) $result = $this->create($ret->toArray(), $where['product_id'], $where['activity_id'], $productType); + if ($result) $this->dao->update($result['spu_id'], ['status' => $status]); + if ($status == 1 && $productType == 0) { + Queue(SendSmsJob::class, ['tempId' => 'PRODUCT_INCREASE', 'id' => $id]); + } + if ($productType == 0) Queue::push(SyncProductTopJob::class,[]); + } catch (\Exception $exception) { + Log::info($exception->getMessage()); + } + } + + /** + * TODO 平台编辑商品同步修改 + * @param int $id + * @param int $productId + * @param int $productType + * @param array $data + * @author Qinii + * @day 12/18/20 + */ + public function changRank(int $id, int $productId, int $productType, array $data) + { + $where = [ + 'product_id' => $productId, + 'product_type' => $productType, + 'activity_id' => $id, + ]; + $res = $this->dao->getWhere($where); + if (!$res && $id) $this->changeStatus($id, $productType); + $res = $this->dao->getWhere($where); + if ($res) { + $res->store_name = $data['store_name']; + $res->rank = $data['rank']; + $res->star = $data['star'] ?? 1; + $res->save(); + } + } + + /** + * TODO 同步各类商品到spu表 + * @param array|null $productType + * @author Qinii + * @day 12/25/20 + */ + public function updateSpu(?array $productType) + { + if (!$productType) $productType = [0, 1, 2, 3, 4]; + $_product_make = app()->make(ProductRepository::class); + $data = []; + foreach ($productType as $value) { + $ret = $_product_make->activitSearch($value); + $data = array_merge($data, $ret); + } + $this->dao->findOrCreateAll($data); + } + + /** + * TODO 获取活动商品的一级分类 + * @param $type + * @return mixed + * @author Qinii +0 + * @day 1/12/21 + */ + public function getActiveCategory($type) + { + $pathArr = $this->dao->getActivecategory($type); + $path = []; + foreach ($pathArr as $item) { + $path[] = explode('/', $item)[1]; + } + $path = array_unique($path); + $cat = app()->make(StoreCategoryRepository::class)->getSearch(['ids' => $path])->field('store_category_id,cate_name')->select(); + return $cat; + } + + public function getSpuData($id, $productType, $merId) + { + try { + switch ($productType) { + case 0: + case 98: + $where = [ + 'activity_id' => 0, + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 1: + $_make = app()->make(StoreSeckillActiveRepository::class); + $res = $_make->getSearch(['product_id' => $id])->find(); + $where = [ + 'activity_id' => $res['seckill_active_id'], + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 2: + $_make = app()->make(ProductPresellRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 3: + $_make = app()->make(ProductAssistRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 4: + $_make = app()->make(ProductGroupRepository::class); + $where[$_make->getPk()] = $id; + $res = $_make->getWhere([$_make->getPk() => $id]); + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + default: + $where = [ + 'activity_id' => 0, + 'product_id' => $id, + 'product_type' => 0, + ]; + break; + } + } catch (\Exception $e) { + throw new ValidateException('数据不存在'); + } + if ($merId) $where['mer_id'] = $merId; + $result = $this->dao->getSearch($where)->find(); + if (!$result) throw new ValidateException('数据不存在'); + return $result; + } + + public function setLabels($id, $productType, $data, $merId = 0) + { + $field = isset($data['sys_labels']) ? 'sys_labels' : 'mer_labels'; + if ($data[$field]) app()->make(ProductLabelRepository::class)->checkHas($merId, $data[$field]); + $ret = $this->getSpuData($id, $productType, $merId); + $value = $data[$field] ? $data[$field] : ''; + $ret->$field = $value; + $ret->save(); + } + + public function batchLabels($ids, $data,$merId) + { + $ids = is_array($ids) ? $ids : explode(',',$ids); + foreach ($ids as $id) { + $this->setLabels($id,0,$data,$merId); + } + } + + + public function getApiSearchByCoupon($where, $page, $limit, $userInfo) + { + $coupon = app()->make(StoreCouponRepository::class)->search(null, [ + 'status' => 1, + 'coupon_id' => $where['coupon_id'] + ])->find(); + $data['coupon'] = $coupon; + if ($coupon) { + switch ($coupon['type']) { + case 0: + $where['mer_id'] = $coupon['mer_id']; + break; + case 1: + $where['product_ids'] = app()->make(StoreCouponProductRepository::class)->search([ + 'coupon_id' => $where['coupon_id'] + ])->column('product_id'); + break; + case 11: + $ids = app()->make(StoreCouponProductRepository::class)->search([ + 'coupon_id' => $where['coupon_id'] + ])->column('product_id'); + $where['cate_pid'] = $ids; + break; + case 10: + break; + case 12: + $ids = app()->make(StoreCouponProductRepository::class)->search([ + 'coupon_id' => $where['coupon_id'] + ])->column('product_id'); + $where['mer_ids'] = $ids; + break; + } + $where['is_coupon'] = 1; + $where['order'] = 'star'; + $where['common'] = 1; + $where['svip'] = ($coupon['send_type'] == StoreCouponRepository::GET_COUPON_TYPE_SVIP) ? 1 : ''; + $product = $this->getApiSearch($where, $page, $limit, $userInfo); + } + + $data['count'] = $product['count'] ?? 0; + $data['list'] = $product['list'] ?? []; + return $data; + } + + public function getHotRanking(int $cateId) + { + $RedisCacheService = app()->make(RedisCacheService::class); + $prefix = env('queue_name','merchant').'_hot_ranking_'; + $ids = $RedisCacheService->handler()->get($prefix.'top_' . intval($cateId)); + $ids = $ids ? explode(',', $ids) : []; + if (!count($ids)) { + return []; + } + $ids = array_map('intval', $ids); + $where['mer_status'] = 1; + $where['status'] = 1; + $where['is_del'] = 0; + $where['product_type'] = 0; + $where['order'] = 'sales'; + $where['spu_ids'] = $ids; + $list = $this->dao->search($where)->setOption('field',[])->field('spu_id,S.image,S.price,S.product_type,P.product_id,P.sales,S.status,S.store_name,P.ot_price,P.cost')->select(); + if ($list) $list = $list->toArray(); + return $list; + } + + /** + * TODO + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2022/9/22 + */ + public function makinList($where,$page, $limit) + { + $where['spu_status'] = 1; + $where['mer_status'] = 1; + $query = $this->dao->search($where); + $query->with([ + 'merchant' , + 'issetCoupon', + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->field($this->productFiled)->select(); + return compact('count','list'); + } +} diff --git a/app/common/repositories/store/product/SpuRepository.php.bak b/app/common/repositories/store/product/SpuRepository.php.bak new file mode 100644 index 00000000..e4144c5f --- /dev/null +++ b/app/common/repositories/store/product/SpuRepository.php.bak @@ -0,0 +1,531 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\store\product; + +use app\common\repositories\store\coupon\StoreCouponProductRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\StoreActivityRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\jobs\SyncProductTopJob; +use crmeb\services\CopyCommand; +use crmeb\services\RedisCacheService; +use think\exception\ValidateException; +use think\facade\Log; +use app\common\repositories\BaseRepository; +use app\common\dao\store\product\SpuDao; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\user\UserVisitRepository; +use think\facade\Queue; + +class SpuRepository extends BaseRepository +{ + public $dao; + public $merchantFiled = 'mer_id,mer_name,mer_avatar,is_trader,mer_info,mer_keyword,type_id'; + public $productFiled = 'S.product_id,S.store_name,S.image,activity_id,S.keyword,S.price,S.mer_id,spu_id,S.status,store_info,brand_id,cate_id,unit_name,S.star,S.rank,S.sort,sales,S.product_type,rate,reply_count,extension_type,S.sys_labels,S.mer_labels,P.delivery_way,P.delivery_free,P.ot_price,svip_price_type,stock,mer_svip_status'; + public function __construct(SpuDao $dao) + { + $this->dao = $dao; + } + + public function create(array $param, int $productId, int $activityId, $productType = 0) + { + $data = $this->setparam($param, $productId, $activityId, $productType); + return $this->dao->create($data); + } + + public function baseUpdate(array $param, int $productId, int $activityId, $productType = 0) + { + if ($productType == 1) { + $make = app()->make(StoreSeckillActiveRepository::class); + $activityId = $make->getSearch(['product_id' => $productId])->value('seckill_active_id'); + } + $where = [ + 'product_id' => $productId, + 'activity_id' => $activityId, + 'product_type' => $productType, + ]; + $ret = $this->dao->getSearch($where)->find(); + if (!$ret) { + return $this->create($param, $productId, $activityId, $productType); + } else { + $data = $this->setparam($param, $productId, $activityId, $productType); + + $value = $data['mer_labels']; + if (!empty($value)) { + if (!is_array($value)) { + $data['mer_labels'] = ',' . $value . ','; + } else { + $data['mer_labels'] = ',' . implode(',', $value) . ','; + } + } + return $this->dao->update($ret->spu_id, $data); + } + } + + public function setparam(array $param, $productId, $activityId, $productType) + { + + $data = [ + 'product_id' => $productId, + 'product_type' => $productType ?? 0, + 'activity_id' => $activityId, + 'store_name' => $param['store_name'], + 'keyword' => $param['keyword'] ?? '', + 'image' => $param['image'], + 'price' => $param['price'], + 'status' => 0, + 'rank' => $param['rank'] ?? 0, + 'temp_id' => $param['temp_id'], + 'sort' => $param['sort'] ?? 0, + 'mer_labels' => $param['mer_labels'] ?? '', + ]; + if (isset($param['mer_id'])) $data['mer_id'] = $param['mer_id']; + return $data; + } + + /** + * TODO 修改排序 + * @param $productId + * @param $activityId + * @param $productType + * @param $data + * @author Qinii + * @day 1/19/21 + */ + public function updateSort($productId, $activityId, $productType, $data) + { + $where = [ + 'product_id' => $productId, + 'activity_id' => $activityId, + 'product_type' => $productType, + ]; + $ret = $this->dao->getSearch($where)->find(); + if ($ret) $this->dao->update($ret['spu_id'], $data); + } + /** + * TODO 移动端列表 + * @param $where + * @param $page + * @param $limit + * @param $userInfo + * @return array + * @author Qinii + * @day 12/18/20 + */ + public function getApiSearch($where, $page, $limit, $userInfo = null) + { + if (isset($where['keyword']) && !empty($where['keyword'])) { + if (preg_match('/^(\/@[1-9]{1}).*\*\//', $where['keyword'])) { + $command = app()->make(CopyCommand::class)->getMassage($where['keyword']); + if (!$command || in_array($command['type'], [30, 40])) return ['count' => 0, 'list' => []]; + if ($userInfo && $command['uid']) app()->make(UserRepository::class)->bindSpread($userInfo, $command['uid']); + $where['spu_id'] = $command['id']; + unset($where['keyword']); + } else { + app()->make(UserVisitRepository::class)->searchProduct($userInfo ? $userInfo['uid'] : 0, $where['keyword'], (int)($where['mer_id'] ?? 0)); + } + } + $where['spu_status'] = 1; + $where['mer_status'] = 1; + $query = $this->dao->search($where); + + $query->with([ + 'merchant' => function ($query) { + $query->field($this->merchantFiled)->with(['type_name']); + }, + 'issetCoupon', + ]); + $productMake = app()->make(ProductRepository::class); + $count = $query->count(); + + $list = $query->page($page, $limit)->setOption('field', [])->field($this->productFiled)->select(); + $append = ['stop_time','svip_price','show_svip_info','is_svip_price']; + if ($productMake->getUserIsPromoter($userInfo)) + $append[] = 'max_extension'; + $list->append($append); + $list = $this->getBorderList($list); + return compact('count', 'list'); + } + + public function getBorderList($list) + { + $make = app()->make(StoreActivityRepository::class); + foreach ($list as $item) { + $act = $make->getActivityBySpu(StoreActivityRepository::ACTIVITY_TYPE_BORDER,$item['spu_id'],$item['cate_id'],$item['mer_id']); + $item['border_pic'] = $act['pic'] ?? ''; + } + return $list; + } + + + /** + * TODO 修改状态 + * @param array $data + * @author Qinii + * @day 12/18/20 + */ + public function changeStatus(int $id, int $productType) + { + $make = app()->make(ProductRepository::class); + $where = []; + $status = 1; + try { + switch ($productType) { + case 0: + $where = [ + 'activity_id' => 0, + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 1: + $_make = app()->make(StoreSeckillActiveRepository::class); + $res = $_make->getSearch(['product_id' => $id])->find(); + $endday = strtotime($res['end_day']); + if ($res['status'] == -1 || $endday < time()) $status = 0; + $where = [ + 'activity_id' => $res['seckill_active_id'], + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 2: + $_make = app()->make(ProductPresellRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + + $endttime = strtotime($res['end_time']); + if ($endttime <= time()) { + $status = 0; + } else { + if ( + $res['product_status'] !== 1 || + $res['status'] !== 1 || + $res['action_status'] !== 1 || + $res['is_del'] !== 0 || + $res['is_show'] !== 1 + ) { + $status = 0; + } + } + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 3: + $_make = app()->make(ProductAssistRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + + $endttime = strtotime($res['end_time']); + if ($endttime <= time()) { + $status = 0; + } else { + if ( + $res['product_status'] !== 1 || + $res['status'] !== 1 || + $res['is_show'] !== 1 || + $res['action_status'] !== 1 || + $res['is_del'] !== 0 + ) { + $status = 0; + } + } + + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 4: + $_make = app()->make(ProductGroupRepository::class); + $wher = $_make->actionShow(); + $wher[$_make->getPk()] = $id; + + $res = $_make->getWhere([$_make->getPk() => $id]); + $endttime = strtotime($res['end_time']); + if ($endttime <= time()) { + $status = 0; + } else { + if ( + $res['product_status'] !== 1 || + $res['status'] !== 1 || + $res['is_show'] !== 1 || + $res['action_status'] !== 1 || + $res['is_del'] !== 0 + ) { + $status = 0; + } + } + + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + default: + break; + } + $ret = $make->getWhere(['product_id' => $where['product_id']]); + if (!$ret || $ret['status'] !== 1 || $ret['mer_status'] !== 1 || $ret['is_del']) $status = 0; + if (in_array($productType, [0, 1]) && ($ret['is_show'] !== 1 || $ret['is_used'] !== 1)) $status = 0; + $result = $this->dao->getSearch($where)->find(); + if (!$result && $ret) $result = $this->create($ret->toArray(), $where['product_id'], $where['activity_id'], $productType); + if ($result) $this->dao->update($result['spu_id'], ['status' => $status]); + if ($status == 1 && $productType == 0) { + Queue(SendSmsJob::class, ['tempId' => 'PRODUCT_INCREASE', 'id' => $id]); + } + if ($productType == 0) Queue::push(SyncProductTopJob::class,[]); + } catch (\Exception $exception) { + Log::info($exception->getMessage()); + } + } + + /** + * TODO 平台编辑商品同步修改 + * @param int $id + * @param int $productId + * @param int $productType + * @param array $data + * @author Qinii + * @day 12/18/20 + */ + public function changRank(int $id, int $productId, int $productType, array $data) + { + $where = [ + 'product_id' => $productId, + 'product_type' => $productType, + 'activity_id' => $id, + ]; + $res = $this->dao->getWhere($where); + if (!$res && $id) $this->changeStatus($id, $productType); + $res = $this->dao->getWhere($where); + if ($res) { + $res->store_name = $data['store_name']; + $res->rank = $data['rank']; + $res->star = $data['star'] ?? 1; + $res->save(); + } + } + + /** + * TODO 同步各类商品到spu表 + * @param array|null $productType + * @author Qinii + * @day 12/25/20 + */ + public function updateSpu(?array $productType) + { + if (!$productType) $productType = [0, 1, 2, 3, 4]; + $_product_make = app()->make(ProductRepository::class); + $data = []; + foreach ($productType as $value) { + $ret = $_product_make->activitSearch($value); + $data = array_merge($data, $ret); + } + $this->dao->findOrCreateAll($data); + } + + /** + * TODO 获取活动商品的一级分类 + * @param $type + * @return mixed + * @author Qinii +0 + * @day 1/12/21 + */ + public function getActiveCategory($type) + { + $pathArr = $this->dao->getActivecategory($type); + $path = []; + foreach ($pathArr as $item) { + $path[] = explode('/', $item)[1]; + } + $path = array_unique($path); + $cat = app()->make(StoreCategoryRepository::class)->getSearch(['ids' => $path])->field('store_category_id,cate_name')->select(); + return $cat; + } + + public function getSpuData($id, $productType, $merId) + { + try { + switch ($productType) { + case 0: + $where = [ + 'activity_id' => 0, + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 1: + $_make = app()->make(StoreSeckillActiveRepository::class); + $res = $_make->getSearch(['product_id' => $id])->find(); + $where = [ + 'activity_id' => $res['seckill_active_id'], + 'product_id' => $id, + 'product_type' => $productType, + ]; + break; + case 2: + $_make = app()->make(ProductPresellRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 3: + $_make = app()->make(ProductAssistRepository::class); + $res = $_make->getWhere([$_make->getPk() => $id]); + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + case 4: + $_make = app()->make(ProductGroupRepository::class); + $where[$_make->getPk()] = $id; + $res = $_make->getWhere([$_make->getPk() => $id]); + $where = [ + 'activity_id' => $id, + 'product_id' => $res['product_id'], + 'product_type' => $productType, + ]; + break; + default: + $where = [ + 'activity_id' => 0, + 'product_id' => $id, + 'product_type' => 0, + ]; + break; + } + } catch (\Exception $e) { + throw new ValidateException('数据不存在'); + } + if ($merId) $where['mer_id'] = $merId; + $result = $this->dao->getSearch($where)->find(); + if (!$result) throw new ValidateException('数据不存在'); + return $result; + } + + public function setLabels($id, $productType, $data, $merId = 0) + { + $field = isset($data['sys_labels']) ? 'sys_labels' : 'mer_labels'; + if ($data[$field]) app()->make(ProductLabelRepository::class)->checkHas($merId, $data[$field]); + $ret = $this->getSpuData($id, $productType, $merId); + $value = $data[$field] ? $data[$field] : ''; + $ret->$field = $value; + $ret->save(); + } + + public function batchLabels($ids, $data,$merId) + { + $ids = is_array($ids) ? $ids : explode(',',$ids); + foreach ($ids as $id) { + $this->setLabels($id,0,$data,$merId); + } + } + + + public function getApiSearchByCoupon($where, $page, $limit, $userInfo) + { + $coupon = app()->make(StoreCouponRepository::class)->search(null, [ + 'status' => 1, + 'coupon_id' => $where['coupon_id'] + ])->find(); + $data['coupon'] = $coupon; + if ($coupon) { + switch ($coupon['type']) { + case 0: + $where['mer_id'] = $coupon['mer_id']; + break; + case 1: + $where['product_ids'] = app()->make(StoreCouponProductRepository::class)->search([ + 'coupon_id' => $where['coupon_id'] + ])->column('product_id'); + break; + case 11: + $ids = app()->make(StoreCouponProductRepository::class)->search([ + 'coupon_id' => $where['coupon_id'] + ])->column('product_id'); + $where['cate_pid'] = $ids; + break; + case 10: + break; + case 12: + $ids = app()->make(StoreCouponProductRepository::class)->search([ + 'coupon_id' => $where['coupon_id'] + ])->column('product_id'); + $where['mer_ids'] = $ids; + break; + } + $where['is_coupon'] = 1; + $where['order'] = 'star'; + $where['common'] = 1; + $where['svip'] = ($coupon['send_type'] == StoreCouponRepository::GET_COUPON_TYPE_SVIP) ? 1 : ''; + $product = $this->getApiSearch($where, $page, $limit, $userInfo); + } + + $data['count'] = $product['count'] ?? 0; + $data['list'] = $product['list'] ?? []; + return $data; + } + + public function getHotRanking(int $cateId) + { + $RedisCacheService = app()->make(RedisCacheService::class); + $prefix = env('queue_name','merchant').'_hot_ranking_'; + $ids = $RedisCacheService->handler()->get($prefix.'top_' . intval($cateId)); + $ids = $ids ? explode(',', $ids) : []; + if (!count($ids)) { + return []; + } + $ids = array_map('intval', $ids); + $where['mer_status'] = 1; + $where['status'] = 1; + $where['is_del'] = 0; + $where['product_type'] = 0; + $where['order'] = 'sales'; + $where['spu_ids'] = $ids; + $list = $this->dao->search($where)->setOption('field',[])->field('spu_id,S.image,S.price,S.product_type,P.product_id,P.sales,S.status,S.store_name,P.ot_price,P.cost')->select(); + if ($list) $list = $list->toArray(); + return $list; + } + + /** + * TODO + * @param $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2022/9/22 + */ + public function makinList($where,$page, $limit) + { + $where['spu_status'] = 1; + $where['mer_status'] = 1; + $query = $this->dao->search($where); + $query->with([ + 'merchant' , + 'issetCoupon', + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field', [])->field($this->productFiled)->select(); + return compact('count','list'); + } +} diff --git a/app/common/repositories/store/product/StoreDiscountProductRepository.php b/app/common/repositories/store/product/StoreDiscountProductRepository.php new file mode 100644 index 00000000..5ad124ff --- /dev/null +++ b/app/common/repositories/store/product/StoreDiscountProductRepository.php @@ -0,0 +1,25 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\StoreDiscountProductDao; +use app\common\repositories\BaseRepository; +use think\facade\Db; + +class StoreDiscountProductRepository extends BaseRepository +{ + public function __construct(StoreDiscountProductDao $dao) + { + $this->dao = $dao; + } +} diff --git a/app/common/repositories/store/product/StoreDiscountRepository.php b/app/common/repositories/store/product/StoreDiscountRepository.php new file mode 100644 index 00000000..27aef010 --- /dev/null +++ b/app/common/repositories/store/product/StoreDiscountRepository.php @@ -0,0 +1,285 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\product; + +use app\common\dao\store\product\StoreDiscountDao; +use app\common\repositories\BaseRepository; +use think\exception\ValidateException; +use think\facade\Db; + +/** + * @mixin StoreDiscountDao + */ +class StoreDiscountRepository extends BaseRepository +{ + public function __construct(StoreDiscountDao $dao) + { + $this->dao = $dao; + } + + public function getApilist($where) + { + $query = $this->dao->getSearch($where) + ->with([ + 'discountsProduct' => [ + 'product' => function($query){ + $query->where('status',1)->where('is_show',1)->where('mer_status',1)->where('is_used',1)->with([ + 'attr', + 'attrValue', + ]); + }, + 'productSku' => function($query) { + $query->where('active_type', 10); + }, + ] + ])->order('sort DESC,create_time DESC'); + $data = $query->select(); + $list = []; + if ($data) { + foreach ($data->toArray() as $item) { + if ($item['is_time']) { + $start_time = date('Y-m-d H:i:s',$item['start_time']); + $end_time = date('Y-m-d H:i:s', $item['stop_time']); + unset($item['start_time'], $item['stop_time']); + $item['start_time'] = $start_time; + $item['end_time'] = $end_time; + } + $discountsProduct = $item['discountsProduct']; + unset($item['discountsProduct']); + $res = activeProductSku($discountsProduct, 'discounts'); + $item['count'] = count($res['data']); + $count = count(explode(',',$item['product_ids'])); + if ((!$item['type'] && $count == $item['count']) || ($item['type'] && $count > 0)) { + $item['max_price'] = $res['price']; + $item['discountsProduct'] = $res['data']; + $list[] = $item; + } + } + } + $count = count($list); + return compact('count', 'list'); + } + + public function getMerlist(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->getSearch($where)->with(['discountsProduct'])->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->each(function ($item){ + if ($item['is_time']) { + $start_time = date('Y-m-d H:i:s', $item['start_time']); + $stop_time = date('Y-m-d H:i:s', $item['stop_time']); + unset($item['start_time'],$item['stop_time']); + $item['start_time'] = $start_time; + $item['stop_time'] = $stop_time; + } + }); + return compact('count', 'list'); + } + + public function getAdminlist(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->getSearch($where)->with(['discountsProduct','merchant'])->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->each(function ($item){ + if ($item['is_time']) { + $start_time = date('Y-m-d H:i:s', $item['start_time']); + $stop_time = date('Y-m-d H:i:s', $item['stop_time']); + unset($item['start_time'],$item['stop_time']); + $item['start_time'] = $start_time; + $item['stop_time'] = $stop_time; + } + }); + return compact('count', 'list'); + } + + public function save($data) + { + $discountsData['title'] = $data['title']; + $discountsData['image'] = $data['image']; + $discountsData['type'] = $data['type']; + $discountsData['is_limit'] = $data['is_limit']; + $discountsData['limit_num'] = $data['is_limit'] ? $data['limit_num'] : 0; + $discountsData['is_time'] = $data['is_time']; + $discountsData['start_time'] = $data['is_time'] ? strtotime($data['time'][0]) : 0; + $discountsData['stop_time'] = $data['is_time'] ? strtotime($data['time'][1]) : 0; + $discountsData['sort'] = $data['sort']; + $discountsData['free_shipping'] = $data['free_shipping']; + $discountsData['status'] = $data['status']; + $discountsData['is_show'] = $data['is_show']; + $discountsData['mer_id'] = $data['mer_id']; + $product_ids = []; + $productRepository = app()->make(ProductRepository::class); + + foreach ($data['products'] as $product) { + $productData = $productRepository->getSearch([]) + ->where('mer_id', $data['mer_id']) + ->where('product_id', $product['product_id']) + ->where('status', 1) + ->find(); + if (!$productData) throw new ValidateException('商品「 '.$product['store_name'].' 」不存在或未审核'); + if ($productData['is_gift_bag']) throw new ValidateException('商品「 '.$product['store_name'].' 」分销礼包不能参与'); + if (in_array($product['product_id'], $product_ids)) + throw new ValidateException('商品「 '.$product['store_name'].' 」重复选择'); + + if ($product['type']) { + $product_ids = []; + $product_ids[] = $product['product_id']; + break; + } else { + $product_ids[] = $product['product_id']; + } + } + + $discountsData['product_ids'] = implode(',', $product_ids); + return Db::transaction(function () use($data, $discountsData){ + if (isset($data['discount_id'])) { + $discountsId = $data['discount_id']; + $this->dao->update($discountsId, $discountsData); + app()->make(StoreDiscountProductRepository::class)->clear($discountsId); + app()->make(ProductSkuRepository::class)->clear($discountsId, ProductSkuRepository::ACTIVE_TYPE_DISCOUNTS); + } else { + $res = $this->dao->create($discountsData); + $discountsId = $res['discount_id']; + } + return $this->saveProduct($discountsId, $data['products'], $data['mer_id']); + }); + } + + + /** + * TODO 添加套餐商品 + * @param int $discountsId + * @param array $data + * @param int $merId + * @author Qinii + * @day 12/31/21 + */ + public function saveProduct(int $discountsId, array $data, int $merId) + { + $storeDiscountsProductsServices = app()->make(StoreDiscountProductRepository::class); + $productSkuRepository = app()->make(ProductSkuRepository::class); + foreach ($data as $item) { + $productData = []; + $productData['discount_id'] = $discountsId; + $productData['product_id'] = $item['product_id']; + $productData['store_name'] = $item['store_name']; + $productData['image'] = $item['image']; + $productData['type'] = $item['type']; + $productData['temp_id'] = $item['temp_id']; + $productData['mer_id'] = $merId; + $discountProduct = $storeDiscountsProductsServices->create($productData); + $productSkuRepository->save($discountsId, $item['product_id'], $item['items'],$discountProduct->discount_product_id); + } + return ; + } + + /** + * TODO 详情 + * @param int $id + * @param int $merId + * @return array|\think\Model|null + * @author Qinii + * @day 12/31/21 + */ + public function detail(int $id, int $merId) + { + $where[$this->dao->getPk()] = $id; + + if ($merId) { + $where['mer_id'] = $merId; + } + $res = $this->dao->getSearch($where) + ->with([ + 'discountsProduct' => function($query){ + $query->with([ + 'product.attrValue', + 'productSku' => function($query) { + $query->where('active_type', 10); + } + ]); + } + ]) + ->find(); + if (!$res) throw new ValidateException('数据不存在'); + $res->append(['time']); + $ret = activeProductSku($res['discountsProduct']); + $res['discountsProduct'] = $ret['data']; + return $res; + } + + public function check($discountId, $products, $userInfo) + { + $discountData = $this->dao->get($discountId); + if (!$discountData) throw new ValidateException('套餐活动已下架'); + if ($discountData['status'] !== 1 || $discountData['is_show'] !== 1 || $discountData['is_del']) + throw new ValidateException('套餐活动已下架'); + if ($discountData['is_limit'] && $discountData['limit_num'] < 1) { + throw new ValidateException('套餐已售罄'); + } + if ($discountData['is_time']) { + if ($discountData['start_time'] > time()) throw new ValidateException('套餐活动未开启'); + if ($discountData['stop_time'] < time()) throw new ValidateException('套餐活动已结束'); + } + $make = app()->make(StoreDiscountProductRepository::class); + $productSkuRepository = app()->make(ProductSkuRepository::class); + $productId = []; + $cartData = []; + + foreach ($products as $item) { + if (in_array($item['product_id'], $productId)) + throw new ValidateException('套餐商品不能重复'); + if (!$item['product_id']) + throw new ValidateException('商品ID不能为空'); + if (!$item['product_attr_unique']) + throw new ValidateException('ID: '. $item['product_id'] .',商品SKU不能为空'); + if ($item['cart_num'] != 1) + throw new ValidateException('套餐商品每单只能购买1件'); + if ($item['cart_num'] <= 0) + throw new ValidateException('购买数量有误'); + + $ret = $make->getWhere(['discount_id' => $discountId, 'product_id' => $item['product_id']]); + if (!$ret) throw new ValidateException('商品ID:'.$item['product_id'].',不在套餐内'); + $sku = $productSkuRepository->getWhere( + [ + 'unique' => $item['product_attr_unique'], + 'active_product_id' => $ret['discount_product_id'], + ], + '*', + ['attrValue'] + ); + + if (!$sku) + throw new ValidateException('商品ID:'.$item['product_id'].'的SKU不在套餐内'); + if (!$sku['attrValue']['stock']) + throw new ValidateException('商品ID:'.$item['product_id'].'的库存不足'); + $productId[] = $item['product_id']; + + $item['uid'] = $userInfo->uid; + $item['mer_id'] = $discountData['mer_id']; + $item['product_type'] = 10; + $item['source'] = 10; + $item['source_id'] = $discountId; + + $cartData[] = $item; + } + + if ($discountData['type'] == 1){ + if (!in_array($discountData['product_ids'], $productId)) + throw new ValidateException('此套餐必须包含主商品'); + } + return $cartData; + } + +} diff --git a/app/common/repositories/store/service/StoreServiceLogRepository.php b/app/common/repositories/store/service/StoreServiceLogRepository.php new file mode 100644 index 00000000..ac9571d8 --- /dev/null +++ b/app/common/repositories/store/service/StoreServiceLogRepository.php @@ -0,0 +1,251 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\service; + + +use app\common\dao\store\service\StoreServiceLogDao; +use app\common\model\store\service\StoreServiceLog; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use think\exception\ValidateException; +use think\facade\Cache; + +/** + * Class StoreServiceLogRepository + * @package app\common\repositories\store\service + * @author xaboy + * @day 2020/5/29 + * @mixin StoreServiceLogDao + */ +class StoreServiceLogRepository extends BaseRepository +{ + /** + * StoreServiceLogRepository constructor. + * @param StoreServiceLogDao $dao + */ + public function __construct(StoreServiceLogDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $merId + * @param $uid + * @param $page + * @param $limit + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/15 + */ + public function userList($merId, $uid, $page, $limit) + { + $query = $this->search(['mer_id' => $merId, 'uid' => $uid])->order('service_log_id DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->with(['user', 'service'])->select()->append(['send_time', 'send_date']); + if ($page == 1) { + $this->dao->userRead($merId, $uid); + app()->make(StoreServiceUserRepository::class)->read($merId, $uid); + } + $list = array_reverse($this->getSendDataList($list)->toArray()); + return compact('count', 'list'); + } + + /** + * @param $merId + * @param $toUid + * @param $uid + * @param $page + * @param $limit + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/15 + */ + public function merList($merId, $toUid, $uid, $page, $limit) + { + $service = app()->make(StoreServiceRepository::class)->getService($uid, $merId); + if (!$service || !$service['status']) + throw new ValidateException('没有权限'); + return $this->serviceList($merId, $service->service_id, $toUid, $page, $limit); + } + + public function serviceList($merId, $service_id, $toUid, $page, $limit, $last_id = '') + { + $query = $this->search(['mer_id' => $merId, 'uid' => $toUid, 'last_id' => $last_id])->order('service_log_id DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->with(['user', 'service'])->select()->append(['send_time', 'send_date']); + if ($page == 1) { + $this->dao->serviceRead($merId, $toUid, $service_id); + app()->make(StoreServiceUserRepository::class)->read($merId, $toUid, true); + } + $list = array_reverse($this->getSendDataList($list)->toArray()); + return compact('count', 'list'); + } + + /** + * @param $merId + * @param $uid + * @param $type + * @param $msn + * @author xaboy + * @day 2020/6/13 + */ + public function checkMsn($merId, $uid, $type, $msn) + { + if ($type == 4 && !app()->make(ProductRepository::class)->merExists($merId, $msn)) + throw new ValidateException('商品不存在'); + else if ($type == 5 && !app()->make(StoreOrderRepository::class)->existsWhere(['uid' => $uid, 'mer_id' => $merId, 'order_id' => $msn])) + throw new ValidateException('订单不存在'); + else if ($type == 6 && !app()->make(StoreRefundOrderRepository::class)->existsWhere(['uid' => $uid, 'mer_id' => $merId, 'refund_order_id' => $msn])) + throw new ValidateException('退款单不存在'); + else if ($type == 7 && !app()->make(ProductPresellRepository::class)->existsWhere(['product_presell_id' => $msn, 'mer_id' => $merId])) + throw new ValidateException('商品不存在'); + else if ($type == 8 && !app()->make(ProductGroupRepository::class)->existsWhere(['product_group_id' => $msn, 'mer_id' => $merId])) + throw new ValidateException('商品不存在'); + } + + /** + * @param StoreServiceLog $log + * @return StoreServiceLog + * @author xaboy + * @day 2020/6/15 + */ + public function getSendData(StoreServiceLog $log) + { + if ($log->msn_type == 4) + $log->product; + else if ($log->msn_type == 5) + $log->orderInfo; + else if ($log->msn_type == 6) + $log->refundOrder; + else if ($log->msn_type == 7) + $log->presell; + else if ($log->msn_type == 8) + $log->productGroup; + return $log; + } + + public function getSendDataList($list) + { + $cache = []; + foreach ($list as $log) { + if (!in_array($log->msn_type, [4, 5, 6, 7, 8])) continue; + $key = $log->msn_type . $log->msn; + if (isset($cache[$key])) { + if ($log->msn_type == 4) + $log->set('product', $cache[$key]); + else if ($log->msn_type == 5) + $log->set('orderInfo', $cache[$key]); + else if ($log->msn_type == 6) + $log->set('refundOrder', $cache[$key]); + else if ($log->msn_type == 8) + $log->set('productGroup', $cache[$key]); + else + $log->set('presell', $cache[$key]); + } else { + if ($log->msn_type == 4) + $cache[$key] = $log->product; + else if ($log->msn_type == 5) + $cache[$key] = $log->orderInfo; + else if ($log->msn_type == 6) + $cache[$key] = $log->refundOrder; + else if ($log->msn_type == 8) + $cache[$key] = $log->productGroup; + else + $cache[$key] = $log->presell; + } + } + return $list; + } + + /** + * @param $uid + * @param bool $isService + * @author xaboy + * @day 2020/6/15 + */ + public function getChat($uid, $isService = false) + { + $key = ($isService ? 's_chat' : 'u_chat') . $uid; + return Cache::get($key); + } + + /** + * TODO 获取某个客服的用户列表 + * @param $service_id + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-18 + */ + public function getServiceUserList($service_id, $page, $limit) + { + $query = $this->dao->getUserListQuery($service_id)->with(['user'])->group('uid'); + $count = $query->count(); + + $list = $query->setOption('field', [])->field('uid,mer_id,create_time,type') + ->page($page, $limit) + ->select(); + + return compact('count', 'list'); + } + + /** + * TODO 获取商户的聊天用户列表 + * @param $merId + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-19 + */ + public function getMerchantUserList($merId, $page, $limit) + { + $query = $this->dao->getMerchantUserList($merId)->with(['user'])->group('uid'); + $count = $query->count(); + $list = $query->setOption('field', [])->field('uid,mer_id,create_time,type')->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * TODO + * @param $merId + * @param $uid + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-19 + */ + public function getUserMsn(int $uid, $page, $limit, ?int $merId = null, ?int $serviceId = null) + { + $where['uid'] = $uid; + if ($merId) $where['mer_id'] = $merId; + if ($serviceId) $where['service_id'] = $serviceId; + $query = $this->search($where)->order('service_log_id DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->with(['user', 'service'])->select(); + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/store/service/StoreServiceReplyRepository.php b/app/common/repositories/store/service/StoreServiceReplyRepository.php new file mode 100644 index 00000000..ba8aba27 --- /dev/null +++ b/app/common/repositories/store/service/StoreServiceReplyRepository.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\service; + + +use app\common\dao\store\service\StoreServiceReplyDao; +use app\common\repositories\BaseRepository; + +/** + * Class StoreServiceRepository + * @package app\common\repositories\store\service + * @author xaboy + * @day 2020/5/29 + * @mixin StoreServiceReplyDao + */ +class StoreServiceReplyRepository extends BaseRepository +{ + /** + * StoreServiceRepository constructor. + * @param StoreServiceReplyDao $dao + */ + public function __construct(StoreServiceReplyDao $dao) + { + $this->dao = $dao; + } + + public function getList($where, $page, $limit) + { + $query = $this->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count', 'list'); + } + + public function create($data) + { + if (is_array($data['keyword'])) $data['keyword'] = implode(',', $data['keyword']); + return $this->dao->create($data); + } + +} diff --git a/app/common/repositories/store/service/StoreServiceRepository.php b/app/common/repositories/store/service/StoreServiceRepository.php new file mode 100644 index 00000000..519ec35f --- /dev/null +++ b/app/common/repositories/store/service/StoreServiceRepository.php @@ -0,0 +1,268 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\service; + + +use app\common\dao\store\service\StoreServiceDao; +use app\common\model\store\service\StoreService; +use app\common\repositories\BaseRepository; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Config; +use think\facade\Route; + +/** + * Class StoreServiceRepository + * @package app\common\repositories\store\service + * @author xaboy + * @day 2020/5/29 + * @mixin StoreServiceDao + */ +class StoreServiceRepository extends BaseRepository +{ + /** + * StoreServiceRepository constructor. + * @param StoreServiceDao $dao + */ + public function __construct(StoreServiceDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with(['user' => function ($query) { + $query->field('nickname,avatar,uid,cancel_time'); + }])->order('sort DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/5/29 + */ + public function form($merId, $isUpdate = false) + { + $pwd = Elm::password('pwd', '客服密码'); + $confirm_pwd = Elm::password('confirm_pwd', '确认密码'); + if (!$isUpdate) { + $pwd->required(); + $confirm_pwd->required(); + } + $adminRule = $filed = []; + if($merId){ + $adminRule = [ + Elm::switches('customer', '订单管理', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_goods', '商品管理', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_verify', '开启核销', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::switches('notify', '订单通知', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::input('phone', '通知电话') + ] + ] + ]) + ]; + + } + $filed = [ + "value" => 1, + "rule" => [ + "customer","is_goods","is_verify","notify" + ] + ]; + $adminRule[] = Elm::number('sort', '排序', 0)->precision(0)->max(99999); + $prefix = $merId ? config('admin.merchant_prefix') : config('admin.admin_prefix'); + return Elm::createForm(Route::buildUrl('merchantServiceCreate')->build(), array_merge([ + Elm::frameImage('uid', '用户', '/' . $prefix . '/setting/userList?field=uid&type=1')->prop('srcKey', 'src')->width('675px')->height('500px')->modal(['modal' => false]), + Elm::frameImage('avatar', '客服头像', '/' . $prefix . '/setting/uploadPicture?field=avatar&type=1')->width('896px')->height('480px')->props(['footer' => false])->modal(['modal' => false]), + Elm::input('nickname', '客服昵称')->required(), + Elm::input('account', '客服账号')->required(), + $pwd, $confirm_pwd, + Elm::switches('is_open', '账号状态', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12)->control([$filed]), + Elm::switches('status', '客服状态', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + ], $adminRule))->setTitle('添加客服'); + } + + /** + * @param $id + * @return Form + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function updateForm($id) + { + $service = $this->dao->getWith($id, ['user' => function ($query) { + $query->field('avatar,uid'); + }])->toArray(); + if($service['user'] ?? null){ + $service['uid'] = ['id' => $service['uid'], 'src' => $service['user']['avatar'] ?: $service['avatar']]; + }else{ + unset($service['uid']); + } + unset($service['user'], $service['pwd']); + return $this->form($service['mer_id'], true)->formData($service)->setTitle('编辑表单')->setAction(Route::buildUrl('merchantServiceUpdate', compact('id'))->build()); + } + + /** + * @param $merId + * @param $uid + * @return array|mixed|\think\Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function getChatService($merId, $uid = 0) + { + $service = null; + if ($uid) { + $logRepository = app()->make(StoreServiceLogRepository::class); + $lastServiceId = $logRepository->getLastServiceId($merId, $uid); + } + + if (isset($lastServiceId) && $lastServiceId) + $service = $this->getValidServiceInfo($lastServiceId); + if ($service) return $service; + $service = $this->dao->getRandService($merId); + if ($service) return $service; + } + + public function getServices($uid, array $where = [],$is_sys = 1) + { + $order = $is_sys ? 'ASC' : 'DESC'; + $where['uid'] = $uid; + $list = $this->search($where)->with(['merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name'); + }])->order('mer_id '.$order)->select()->hidden(['pwd'])->toArray(); + $config = systemConfig(['site_logo', 'site_name']); + foreach ($list as &$item){ + if ($item['mer_id'] == 0) { + $item['merchant'] = [ + 'mer_avatar' => $config['site_logo'], + 'mer_name' => $config['site_name'], + 'mer_id' => 0, + ]; + } + } + unset($item); + return $list; + } + + public function createToken(StoreService $admin) + { + $service = new JwtTokenService(); + $exp = intval(Config::get('admin.token_exp', 3)); + $token = $service->createToken($admin->service_id, 'service', strtotime("+ {$exp}hour")); + $this->cacheToken($token['token'], $token['out']); + return $token; + } + + /** + * @param string $token + * @param int $exp + * @author xaboy + * @day 2020-04-10 + */ + public function cacheToken(string $token, int $exp) + { + Cache::set('service_' . $token, time() + $exp, $exp); + } + + public function checkToken(string $token) + { + $has = Cache::has('service_' . $token); + if (!$has) + throw new AuthException('无效的token'); + $lastTime = Cache::get('service_' . $token); + if (($lastTime + (intval(Config::get('admin.token_valid_exp', 15))) * 60) < time()) + throw new AuthException('token 已过期'); + } + + public function updateToken(string $token) + { + Cache::set('service_' . $token, time(), intval(Config::get('admin.token_valid_exp', 15)) * 60); + } + + public function clearToken(string $token) + { + Cache::delete('service_' . $token); + } + + + /** + * 检测验证码 + * @param string $key key + * @param string $code 验证码 + * @author 张先生 + * @date 2020-03-26 + */ + public function checkCode(string $key, string $code) + { + $_code = Cache::get('ser_captcha' . $key); + if (!$_code) { + throw new ValidateException('验证码过期'); + } + + if (strtolower($_code) != strtolower($code)) { + throw new ValidateException('验证码错误'); + } + + //删除code + Cache::delete('ser_captcha' . $key); + } + + + /** + * @param string $code + * @return string + * @author xaboy + * @day 2020-04-09 + */ + public function createLoginKey(string $code) + { + $key = uniqid(microtime(true), true); + Cache::set('ser_captcha' . $key, $code, Config::get('admin.captcha_exp', 5) * 60); + return $key; + } +} diff --git a/app/common/repositories/store/service/StoreServiceUserRepository.php b/app/common/repositories/store/service/StoreServiceUserRepository.php new file mode 100644 index 00000000..34f03320 --- /dev/null +++ b/app/common/repositories/store/service/StoreServiceUserRepository.php @@ -0,0 +1,144 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\store\service; + + +use app\common\dao\store\service\StoreServiceUserDao; +use app\common\model\store\service\StoreServiceLog; +use app\common\repositories\BaseRepository; +use think\exception\ValidateException; + +/** + * Class StoreServiceRepository + * @package app\common\repositories\store\service + * @author xaboy + * @day 2020/5/29 + * @mixin StoreServiceUserDao + */ +class StoreServiceUserRepository extends BaseRepository +{ + /** + * StoreServiceRepository constructor. + * @param StoreServiceUserDao $dao + */ + public function __construct(StoreServiceUserDao $dao) + { + $this->dao = $dao; + } + + public function updateInfo(StoreServiceLog $log, $isService) + { + $serviceUser = $this->dao->getWhere(['service_id' => $log->service_id, 'uid' => $log->uid, 'mer_id' => $log->mer_id]); + if (!$serviceUser) { + $serviceUser = $this->dao->create([ + 'service_id' => $log->service_id, + 'uid' => $log->uid, + 'mer_id' => $log->mer_id, + 'service_unread' => $isService ? 1 : 0, + 'user_unread' => $isService ? 0 : 1, + 'is_online' => 1, + 'last_log_id' => $log->service_log_id, + 'last_time' => date('Y-m-d H:i:s') + ]); + } else { + $isService ? $serviceUser->service_unread++ : $serviceUser->user_unread++; + $serviceUser->last_log_id = $log->service_log_id; + $serviceUser->last_time = date('Y-m-d H:i:s'); + $serviceUser->is_online = 1; + $serviceUser->save(); + } + + return $serviceUser; + } + + public function read($merId, $uid, $isService = null) + { + $field = $isService ? 'service_unread' : 'user_unread'; + $this->dao->search([ + 'mer_id' => $merId, + 'uid' => $uid, + ])->update([ + $field => 0 + ]); + } + + public function userMerchantList($uid, $page, $limit) + { + $query = $this->dao->search(['uid' => $uid])->group('mer_id')->order('last_time DESC'); + $count = $query->count(); + $list = $query->with(['merchant' => function ($query) { + $query->field('mer_id,mer_avatar,mer_name'); + }, 'last'])->page($page, $limit)->setOption('field', [])->field('*,max(last_log_id) as last_log_id,sum(user_unread) as num')->select()->toArray(); + + $config = systemConfig(['site_logo', 'site_name']); + + foreach ($list as &$item) { + if ($item['mer_id'] == 0) { + $item['merchant'] = [ + 'mer_avatar' => $config['site_logo'], + 'mer_name' => $config['site_name'], + 'mer_id' => 0, + ]; + } + } + unset($item); + + return compact('count', 'list'); + } + + public function merUserList($merId, $uid, $page, $limit) + { + $service = app()->make(StoreServiceRepository::class)->getService($uid, $merId); + if (!$service) + throw new ValidateException('没有权限'); + if (!$service['status']) + throw new ValidateException('客服已离线,清开启客服状态'); + return $this->serviceUserList(['service_id' => $service->service_id], $merId, $page, $limit); + + } + + public function serviceUserList($where, $merId, $page, $limit) + { + $query = $this->dao->search($where)->group('uid')->order('last_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->with([ + 'user' => function ($query) { + $query->field('uid,avatar,nickname,user_type,sex,is_promoter,phone,now_money,phone,birthday,spread_uid')->with([ + 'spread' => function ($query) { + $query->field('uid,avatar,nickname,cancel_time'); + } + ]); + }, + 'mark' => function ($query) use ($merId) { + $query->where('mer_id', $merId)->bind(['mark' => 'extend_value']); + }, + 'last' + ])->setOption('field', [])->field('*,max(last_log_id) as last_log_id,sum(service_unread) as num')->select()->toArray(); + if (count($list) && is_null($list[0]['service_user_id'])) { + $list = []; + } + return compact('count', 'list'); + } + + public function online($uid, $online) + { + return $this->dao->search(['uid' => $uid])->update(['is_online' => $online]); + } + + public function onlineDown() + { + return $this->dao->search([])->where(['is_online' => 1])->update(['is_online' => 0]); + } + +} diff --git a/app/common/repositories/store/shipping/CityRepository.php b/app/common/repositories/store/shipping/CityRepository.php new file mode 100644 index 00000000..d323e627 --- /dev/null +++ b/app/common/repositories/store/shipping/CityRepository.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\CityDao as dao; + +class CityRepository extends BaseRepository +{ + + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @return array + */ + public function getFormatList(array $where) + { + return formatCategory($this->dao->getAll($where)->toArray(), 'city_id','parent_id'); + } + + + + +} diff --git a/app/common/repositories/store/shipping/ExpressPartnerRepository.php b/app/common/repositories/store/shipping/ExpressPartnerRepository.php new file mode 100644 index 00000000..0661f48c --- /dev/null +++ b/app/common/repositories/store/shipping/ExpressPartnerRepository.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\ExpressPartnerDao as dao; +use crmeb\services\CrmebServeServices; +use FormBuilder\Factory\Elm; +use think\facade\Db; +use think\facade\Route; + +class ExpressPartnerRepository extends BaseRepository +{ + + /** + * ExpressRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + +} diff --git a/app/common/repositories/store/shipping/ExpressRepository.php b/app/common/repositories/store/shipping/ExpressRepository.php new file mode 100644 index 00000000..053a716c --- /dev/null +++ b/app/common/repositories/store/shipping/ExpressRepository.php @@ -0,0 +1,250 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\ExpressDao as dao; +use crmeb\services\CrmebServeServices; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +/** + * Class ExpressRepository + * @package app\common\repositories\store\shipping + * @day 2020/6/13 + * @mixin dao + */ +class ExpressRepository extends BaseRepository +{ + + /** + * ExpressRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param string $value + * @param string $name + * @return bool + */ + public function nameExists(string $value,?int $id) + { + return $this->dao->merFieldExists('name',$value,null,$id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param string $value + * @param $code + * @return bool + */ + public function codeExists(string $value,?int $id) + { + return $this->dao->merFieldExists('code',$value,null,$id); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param int $value + * @return bool + */ + public function fieldExists(int $value) + { + return $this->dao->merFieldExists($this->dao->getPk(),$value); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $where + * @param int $page + * @param int $limit + * @return array + */ + public function search(array $where,int $page, int $limit) + { + $query = $this->dao->search($where)->order('is_show DESC,sort DESC,id ASC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/22 + * @param int $merId + * @param int|null $id + * @param array $formData + * @return \FormBuilder\Form + */ + public function form(int $merId, ?int $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemExpressCreate')->build() : Route::buildUrl('systemExpressUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::input('name', '快递公司名称')->required(), + Elm::input('code', '快递公司编码')->required(), + Elm::switches('is_show', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加快递公司' : '编辑快递公司')->formData($formData); + } + + /** + * @Author:Qinii + * @Date: 2020/5/22 + * @param int|null $merId + * @param $id + * @return \FormBuilder\Form + */ + public function updateForm(?int$merId,$id) + { + return $this->form($merId, $id, $this->dao->get($id, $merId)->toArray()); + } + + /** + * @Author:Qinii + * @Date: 2020/5/22 + * @param $id + * @param $data + * @return int + */ + public function switchStatus($id,$data) + { + return $this->dao->update($id,$data); + } + + public function options() + { + return $this->dao->selectWhere(['is_show' => 1], 'name label,code value')->toArray(); + } + + + /** + * TODO 从一号通同步数据 + * @author Qinii + * @day 7/23/21 + */ + public function syncExportAll() + { + $services = app()->make(CrmebServeServices::class); + $result = $services->express()->express(1); + $has = $this->dao->search([])->find(); + if (!is_null($has)) { + $arr = []; + foreach ($result['data'] as $datum) { + $res = $this->dao->getWhere(['code' => $datum['code']]); + if ($res) { + $res->name = $datum['name']; + $res->mark = $datum['mark']; + $res->partner_id = $datum['partner_id']; + $res->partner_key = $datum['partner_key']; + $res->partner_name = $datum['partner_name']; + $res->check_man = $datum['check_man']; + $res->is_code = $datum['is_code']; + $res->net = $datum['net']; + $res->save(); + } else { + $arr[] = [ + 'code' => $datum['code'], + 'name' => $datum['name'], + 'mark' => $datum['mark'], + 'partner_id' => $datum['partner_id'], + 'partner_key' => $datum['partner_key'], + 'partner_name' => $datum['partner_name'], + 'check_man' => $datum['check_man'], + 'is_code' => $datum['is_code'], + 'net' => $datum['net'], + ]; + } + } + } else { + $arr = $result['data']; + } + $this->dao->insertAll($arr); + } + + + /** + * TODO + * @param $id + * @param $merId + * @return \FormBuilder\Form + * @author Qinii + * @day 7/23/21 + */ + public function partnerForm($id,$merId) + { + $where = ['mer_id' => $merId,'express_id' => $id]; + $formData = $this->dao->get($id); + + if(!$formData['partner_id'] && !$formData['partner_key'] && !$formData['check_man'] && !$formData['partner_name'] && !$formData['is_code']&& !$formData['net']) + throw new ValidateException('无需月结账号'); + + $res = app()->make(ExpressPartnerRepository::class)->getSearch($where)->find(); + + $form = Elm::createForm(Route::buildUrl('merchantExpressPratnerUpdate', ['id' => $id])->build()); + + if ($formData['partner_id'] == 1) + $field[] = Elm::input('account', '月结账号', $res['account'] ?? ''); + if ($formData['partner_key'] == 1) + $field[] = Elm::input('key', '月结密码', $res['key'] ?? ''); + if ($formData['net'] == 1) + $field[] = Elm::input('net_name', '取件网点', $res['net_name'] ?? ''); + if ($formData['check_man'] == 1) + $field[] = Elm::input('check_man', '承载快递员名称', $res['check_man'] ?? ''); + if ($formData['partner_name'] == 1) + $field[] = Elm::input('partner_name', '客户账户名称', $res['partner_name'] ?? ''); + if ($formData['is_code'] == 1) + $field[] = Elm::input('code', '承载编号', $res['code'] ?? ''); + + $field[] = Elm::radio('status', '是否启用', $res['status'] ?? 1)->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '启用']]); + + $form->setRule($field); + + return $form->setTitle('编辑月结账号')->formData($formData->toArray()); + } + + /** + * TODO 添加月结账号 + * @param array $data + * @author Qinii + * @day 7/23/21 + */ + public function updatePartne(array $data) + { + Db::transaction(function ()use($data){ + $make = app()->make(ExpressPartnerRepository::class); + $where = [ + 'express_id' => $data['express_id'], + 'mer_id' => $data['mer_id'] + ]; + $getData = $make->getSearch($where)->find(); + if($getData){ + $make->update($getData['id'],$data); + }else{ + $make->create($data); + } + }); + } +} diff --git a/app/common/repositories/store/shipping/ShippingTemplateFreeRepository.php b/app/common/repositories/store/shipping/ShippingTemplateFreeRepository.php new file mode 100644 index 00000000..b7c0f0ba --- /dev/null +++ b/app/common/repositories/store/shipping/ShippingTemplateFreeRepository.php @@ -0,0 +1,75 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\ShippingTemplateFreeDao as dao; + +class ShippingTemplateFreeRepository extends BaseRepository +{ + + /** + * ShippingTemplateFreeRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $merId + * @param $id + * @return bool + */ + public function merExists($merId , $id) + { + $result = $this->dao->get($id); + $make = app()->make(ShippingTemplateRepository::class); + if ($result) + return $make->merExists($merId,$result['temp_id']); + return false; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $id + * @param $data + */ + public function update($id,$data) + { + foreach ($data as $item){ + if(isset($item['shipping_template_free_id']) && $item['shipping_template_free_id']){ + $item['city_id'] = implode('/',$item['city_id']); + $this->dao->update($item['shipping_template_free_id'],$item); + }else{ + $item['temp_id'] = $id; + $this->dao->create($item); + } + } + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + * @return mixed + */ + public function insertAll(array $data) + { + return $this->dao->insertAll($data); + } +} diff --git a/app/common/repositories/store/shipping/ShippingTemplateRegionRepository.php b/app/common/repositories/store/shipping/ShippingTemplateRegionRepository.php new file mode 100644 index 00000000..e7dbbdbe --- /dev/null +++ b/app/common/repositories/store/shipping/ShippingTemplateRegionRepository.php @@ -0,0 +1,77 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\ShippingTemplateRegionDao as dao; + +class ShippingTemplateRegionRepository extends BaseRepository +{ + + /** + * ShippingTemplateRegionRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $merId + * @param $id + * @return bool + */ + public function merExists($merId , $id) + { + $result = $this->dao->get($id); + $make = app()->make(ShippingTemplateRepository::class); + if ($result) + return $make->merExists($merId,$result['temp_id']); + return false; + } + + /** + * 暂未使用 + * @Author:Qinii + * @Date: 2020/5/8 + * @param $id + * @param $data + */ + public function update($id,$data) + { + foreach ($data as $item) { + if(isset($item['shipping_template_region_id']) && $item['shipping_template_region_id']){ + $item['city_id'] = implode('/',$item['city_id']); + $this->dao->update($item['shipping_template_region_id'],$item); + }else{ + $item['temp_id'] = $id; + $this->dao->create($item); + } + } + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + * @return mixed + */ + public function insertAll(array $data) + { + return $this->dao->insertAll($data); + } + +} diff --git a/app/common/repositories/store/shipping/ShippingTemplateRepository.php b/app/common/repositories/store/shipping/ShippingTemplateRepository.php new file mode 100644 index 00000000..57e44391 --- /dev/null +++ b/app/common/repositories/store/shipping/ShippingTemplateRepository.php @@ -0,0 +1,270 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\ShippingTemplateDao as dao; +use app\common\repositories\store\product\ProductRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class ShippingTemplateRepository extends BaseRepository +{ + + /** + * ShippingTemplateRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param int $merId + * @return mixed + */ + public function getList(int $merId) + { + return $this->dao->getList($merId); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param int $merId + * @param $id + * @return bool + */ + public function merExists(int $merId,$id) + { + return $this->dao->merFieldExists($merId,$this->getPk(),$id); + } + + + public function merDefaultExists(int $merId,$id) + { + $where = ['mer_id' => $merId,'is_default' => 1, $this->dao->getPk() => $id]; + return $this->dao->getWhere($where) ? true : false; + } + + public function getProductUse(int $merId ,int $id) + { + return app()->make(ProductRepository::class)->merTempExists($merId,$id); + } + + /** + * @param int $id + * @return mixed + * @author Qinii + */ + public function getOne(int $id, $api = 0) + { + $with = ['free','region','undelives']; + $result = $this->dao->getWhere([$this->dao->getPk() => $id],'*',$with); + if ($api){ + if ($result['free']) $append[] = 'free.city_name'; + if ($result['region']) $append[] = 'region.city_name'; + if ($result['undelives']) $append[] = 'undelives.city_name'; + } else { + $append = ['free.city_ids','region.city_ids','undelives.city_ids']; + } + $result->append($append); + return $result; + + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param int $merId + * @param array $where + * @param int $page + * @param int $limit + * @return array + */ + public function search(int $merId,array $where, int $page, int $limit) + { + $query = $this->dao->search($merId, $where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param int $id + * @param array $data + */ + public function update(int $id,array $data) + { + Db::transaction(function()use ($id,$data) { + $region = $data['region']; + $free = $data['free'] ?? ''; + $undelives = $data['undelives']??''; + + unset($data['region'],$data['free'],$data['undelives'],$data['city_ids']); + $this->dao->update($id, $data); + + (app()->make(ShippingTemplateRegionRepository::class))->batchRemove([], [$id]); + (app()->make(ShippingTemplateFreeRepository::class))->batchRemove([], [$id]); + (app()->make(ShippingTemplateUndeliveRepository::class))->batchRemove([], [$id]); + + if($data['appoint']) { + $settlefree = $this->settleFree($free, $id); + (app()->make(ShippingTemplateFreeRepository::class)->insertAll($settlefree)); + } + + $settleRegion = $this->settleRegion($region,$id); + (app()->make(ShippingTemplateRegionRepository::class)->insertAll($settleRegion)); + if($data['undelivery'] == 1){ + $settleUndelives = $this->settleUndelives($undelives,$id); + (app()->make(ShippingTemplateUndeliveRepository::class))->create($settleUndelives); + } + + }); + } + + public function delete($id) + { + if (is_array($id)) { + foreach ($id as $i) { + $this->dao->delete($i); + } + } else { + $this->dao->delete($id); + } + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param array $data + */ + public function create(array $data) + { + Db::transaction(function()use ($data) { + $region = $data['region']; + $free = $data['free'] ?? ''; + $undelives = $data['undelives'] ?? ''; + unset($data['region'],$data['free'],$data['undelives'],$data['city_ids']); + $temp = $this->dao->create($data); + if($data['appoint']) { + $settlefree = $this->settleFree($free, $temp['shipping_template_id']); + (app()->make(ShippingTemplateFreeRepository::class)->insertAll($settlefree)); + } + $settleRegion = $this->settleRegion($region, $temp['shipping_template_id']); + (app()->make(ShippingTemplateRegionRepository::class)->insertAll($settleRegion)); + if($data['undelivery'] == 1){ + $settleUndelives = $this->settleUndelives($undelives,$temp['shipping_template_id']); + (app()->make(ShippingTemplateUndeliveRepository::class))->create($settleUndelives); + } + }); + } + + + /** + * @param $data + * @param $id + * @return array + * @author Qinii + */ + public function settleFree($data,$id) + { + foreach ($data as $v){ + if (isset($v['city_id']) && !is_array($v['city_id'])) throw new ValidateException('包邮参数类型错误'); + $city = '/'.implode('/',$v['city_id']).'/'; + $free[] = [ + 'temp_id' => $id, + 'city_id' => $city, + 'number' => $v['number'], + 'price' => $v['price'] + ]; + } + return $free; + } + + + /** + * @param $data + * @param $id + * @return array + * @author Qinii + */ + public function settleUndelives($data,$id) + { + if (isset($v['city_id']) && !is_array($data['city_id'])) throw new ValidateException('指定不配送参数类型错误'); + return ['temp_id' => $id, 'city_id' => $data['city_id']]; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param $data + * @param $id + * @return array + */ + public function settleRegion($data,$id) + { + $result = []; + foreach ($data as $k => $v){ + $result[] = [ + 'city_id' => ($k > 0 ) ? '/'.implode('/',$v['city_id']).'/' : 0, + 'temp_id' => $id, + 'first' => $v['first'], + 'first_price'=> $v['first_price'], + 'continue' => $v['continue'], + 'continue_price'=> $v['continue_price'], + ]; + } + return $result; + } + + /** + * @param int $merId + * @author Qinii + */ + public function createDefault(int $merId) + { + $data = [ + "name" => "默认模板", + "type" => 1, + "appoint" => 0, + "undelivery" => 0, + 'mer_id' => $merId, + "region" => [[ + "first" => 0, + "first_price" => 0, + "continue" => 0, + "continue_price" => 0, + "city_id" => 0 + ]] + ]; + return $this->create($data); + } + + public function check($merId, $id) + { + if(!$this->merExists($merId, $id)) + throw new ValidateException('数据不存在,ID:'.$id); + if($this->merDefaultExists($merId, $id)) + throw new ValidateException('默认模板不能删除,ID:'.$id); + if($this->getProductUse($merId, $id)) + throw new ValidateException('模板使用中,不能删除,ID:'.$id); + } + +} diff --git a/app/common/repositories/store/shipping/ShippingTemplateUndeliveRepository.php b/app/common/repositories/store/shipping/ShippingTemplateUndeliveRepository.php new file mode 100644 index 00000000..ac69e23c --- /dev/null +++ b/app/common/repositories/store/shipping/ShippingTemplateUndeliveRepository.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\store\shipping; + +use app\common\repositories\BaseRepository; +use app\common\dao\store\shipping\ShippingTemplateUndeliveryDao as dao; + +class ShippingTemplateUndeliveRepository extends BaseRepository +{ + + /** + * ShippingTemplateUndeliveRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $merId + * @param $id + * @return bool + */ + public function merExists($merId , $id) + { + $result = $this->dao->get($id); + $make = app()->make(ShippingTemplateRepository::class); + if ($result) + return $make->merExists($merId,$result['temp_id']); + return false; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @param $id + * @param $data + */ + public function update($id,$data) + { + if(isset($data['shipping_template_undelivery_id']) && $data['shipping_template_undelivery_id']){ + $data['city_id'] = implode('/',$data['city_id']); + $this->dao->update($data['shipping_template_undelivery_id'],$data); + }else{ + $data['temp_id'] = $id; + $this->dao->create($data); + } + } + + +} diff --git a/app/common/repositories/system/CacheRepository.php b/app/common/repositories/system/CacheRepository.php new file mode 100644 index 00000000..ead67414 --- /dev/null +++ b/app/common/repositories/system/CacheRepository.php @@ -0,0 +1,276 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system; + + +use app\common\dao\system\CacheDao; +use app\common\repositories\BaseRepository; +use think\db\exception\DbException; +use think\exception\ValidateException; +use think\facade\Cache; + +/** + * Class CacheRepository + * @package app\common\repositories\system + * @author xaboy + * @day 2020-04-24 + * @mixin CacheDao + */ +class CacheRepository extends BaseRepository +{ + + //积分说明 + const INTEGRAL_RULE = 'sys_integral_rule'; + //商户入驻申请协议 + const INTEGRAL_AGREE = 'sys_intention_agree'; + //预售协议 + const PRESELL_AGREE = 'sys_product_presell_agree'; + //微信菜单 + const WECHAT_MENUS = 'wechat_menus'; + //发票说明 + const RECEIPT_AGREE = 'sys_receipt_agree'; + //佣金说明 + const EXTENSION_AGREE = 'sys_extension_agree'; + //商户类型说明 + const MERCHANT_TYPE = 'sys_merchant_type'; + //分销等级规则 + const SYS_BROKERAGE = 'sys_brokerage'; + //用户协议 + const USER_AGREE = 'sys_user_agree'; + //用户隐私协议 + const USER_PRIVACY = 'sys_userr_privacy'; + //免费会员 + const SYS_MEMBER = 'sys_member'; + //关于我们 + const ABOUT_US = 'sys_about_us'; + //资质证照 + const SYS_CERTIFICATE = 'sys_certificate'; + //注销声明 + const CANCELLATION_MSG = 'the_cancellation_msg'; + //注销重要提示 + const CANCELLATION_PROMPT = 'the_cancellation_prompt'; + //平台规则 + const PLATFORM_RULE = 'platform_rule'; + //优惠券说明 + const COUPON_AGREE = 'sys_coupon_agree'; + //付费会员协议 + const SYS_SVIP = 'sys_svip'; + + public function getAgreeList($type) + { + $data = [ + ['label' => '用户协议', 'key' => self::USER_AGREE], + ['label' => '隐私政策', 'key' => self::USER_PRIVACY], + ['label' => '平台规则', 'key' => self::PLATFORM_RULE], + ['label' => '注销重要提示', 'key' => self::CANCELLATION_PROMPT], + ['label' => '商户入驻申请协议', 'key' => self::INTEGRAL_AGREE], + ]; + if (!$type) { + $data[] = ['label' => '注销声明', 'key' => self::CANCELLATION_MSG]; + $data[] = ['label' => '关于我们', 'key' => self::ABOUT_US]; + $data[] = ['label' => '资质证照', 'key' => self::SYS_CERTIFICATE]; + } + return $data; + } + + public function getAgreeKey(){ + return [ + self::INTEGRAL_RULE, + self::INTEGRAL_AGREE, + self::PRESELL_AGREE, + self::WECHAT_MENUS, + self::RECEIPT_AGREE, + self::EXTENSION_AGREE, + self::MERCHANT_TYPE, + self::SYS_BROKERAGE, + self::USER_AGREE, + self::USER_PRIVACY, + self::SYS_MEMBER, + self::ABOUT_US, + self::SYS_CERTIFICATE, + self::CANCELLATION_MSG, + self::CANCELLATION_PROMPT, + self::PLATFORM_RULE, + self::COUPON_AGREE, + self::SYS_SVIP, + ]; + } + + /** + * CacheRepository constructor. + * @param CacheDao $dao + */ + public function __construct(CacheDao $dao) + { + $this->dao = $dao; + } + + /** + * @param string $key + * @param $result + * @param int $expire_time + * @throws DbException + * @author xaboy + * @day 2020-04-24 + */ + public function save(string $key, $result, int $expire_time = 0) + { + if (!$this->dao->fieldExists('key', $key)) { + $this->dao->create(compact('key', 'result', 'expire_time')); + } else { + $this->dao->keyUpdate($key, compact('result', 'expire_time')); + } + } + + public function getResult($key) + { + $data['title'] = ''; + foreach ($this->getAgreeList(1) as $item) { + if ($item['key'] == $key) { + $data['title'] = $item['label']; + } + } + $data[$key] = $this->dao->getResult($key) ?? ''; + return $data; + } + + public function getResultByKey($key) + { + return $this->dao->getResult($key); + } + + public function saveAll(array $data) + { + foreach ($data as $k => $v) { + $this->save($k, $v); + } + } + + + /** + * 设置用户协议内容 + * @return mixed + */ + public function setUserAgreement($content) + { + $html = << + + + + 隐私协议 + + + + + + + $content + + +HTML; + file_put_contents(public_path() . 'protocol.html', $html); + } + + public function setUserRegister($content) + { + $html = << + + + + 用户协议 + + + + + + + $content + + +HTML; + file_put_contents(public_path() . 'register.html', $html); + } + + + /* + * 整理城市数据用的方法 + */ + public function addres() + { + return []; + $re = (Cache::get('AAAAAA')); + unset($re['省市编码']); + if (!$re) throw new ValidateException('无数据'); + $shen = []; + $shi = []; + $qu = []; + foreach ($re as $key => $value) { + $item = explode(',', $value); + $cout = count($item); + //省 + if ($cout == 2) { + $shen[$item[1]] = [ + 'value' => $key, + 'label' => $item[1], + ]; + } + //市 + if ($cout == 3) { + if ($item[1] == '') { + $shen[$item[2]] = [ + 'value' => $key, + 'label' => $item[2], + ]; + $item[1] = $item[2]; + } + $_v = [ + 'value' => $key, + 'label' => $item[2] + ]; + $shi[$item[1]][] = $_v; + } + //区 + if ($cout == 4) { + $_v = [ + 'value' => $key, + 'label' => $item[3] + ]; + $qu[$item[2]][] = $_v; + } + } + $data = []; + foreach ($shen as $s => $c) { + foreach ($shi as $i => $c_) { + if ($c['label'] == $i) { + if ($c['label'] == $i) { + $san = []; + foreach ($c_ as $key => $value) { + if (isset($qu[$value['label']])) { + $value['children'] = $qu[$value['label']]; + } + $san[] = $value; + } + } + $c['children'] = $san; + } + } + $zls[$s] = $c; + } + $data = array_values($zls); + file_put_contents('address.js', json_encode($data, JSON_UNESCAPED_UNICODE)); + //$this->save('applyments_addres',$data); + } +} diff --git a/app/common/repositories/system/ExtendRepository.php b/app/common/repositories/system/ExtendRepository.php new file mode 100644 index 00000000..1722ad9c --- /dev/null +++ b/app/common/repositories/system/ExtendRepository.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system; + + +use app\common\dao\system\ExtendDao; +use app\common\repositories\BaseRepository; + +/** + * Class ExtendRepository + * @package app\common\repositories\system + * @author xaboy + * @day 2020-04-24 + * @mixin ExtendDao + */ +class ExtendRepository extends BaseRepository +{ + + const TYPE_SERVICE_USER_MARK = 'service_user_mark'; + + /** + * CacheRepository constructor. + * @param ExtendDao $dao + */ + public function __construct(ExtendDao $dao) + { + $this->dao = $dao; + } + + public function updateInfo($extend_type, $link_id, $mer_id, $extend_value) + { + $data = compact('extend_type', 'link_id', 'mer_id'); + $extend = $this->getWhere($data); + if ($extend) { + $extend->extend_value = $extend_value; + $extend->save(); + } else { + $data['extend_value'] = $extend_value; + $extend = $this->dao->create($data); + } + return $extend; + } +} diff --git a/app/common/repositories/system/RelevanceRepository.php b/app/common/repositories/system/RelevanceRepository.php new file mode 100644 index 00000000..6efa2575 --- /dev/null +++ b/app/common/repositories/system/RelevanceRepository.php @@ -0,0 +1,276 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system; + + +use app\common\dao\system\RelevanceDao; +use app\common\repositories\BaseRepository; +use think\exception\ValidateException; +use think\facade\Db; + +/** + * @mixin RelevanceDao + */ +class RelevanceRepository extends BaseRepository +{ + + //文章关联商品 + const TYPE_COMMUNITY_PRODUCT = 'community_product'; + //社区关注 + const TYPE_COMMUNITY_FANS = 'fans'; + //社区文章点赞 + const TYPE_COMMUNITY_START = 'community_start'; + //社区评论点赞 + const TYPE_COMMUNITY_REPLY_START = 'community_reply_start'; + //商户权限 + const TYPE_MERCHANT_AUTH = 'mer_auth'; + + //指定范围类型 + //0全部商品 + const TYPE_ALL = 'scope_type'; + //指定商品 + const SCOPE_TYPE_PRODUCT = 'scope_type_product'; + //指定分类 + const SCOPE_TYPE_CATEGORY = 'scope_type_category'; + //指定商户 + const SCOPE_TYPE_STORE = 'scope_type_store'; + //价格说明关联分类 + const PRICE_RULE_CATEGORY = 'price_rule_category'; + + //商品参数关联 + const PRODUCT_PARAMES_CATE = 'product_params_cate'; + + protected $dao; + /** + * RelevanceRepository constructor. + * @param RelevanceDao $dao + */ + public function __construct(RelevanceDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 添加 + * @param int $leftId + * @param int $rightId + * @param string $type + * @param $check + * @return bool + * @author Qinii + * @day 10/28/21 + */ + public function create(int $leftId, int $rightId, string $type, bool $check = false) + { + if ($check && $this->checkHas($leftId, $rightId, $type)) { + return false; + } + + $data = [ + 'left_id' => $leftId, + 'right_id'=> $rightId, + 'type' => $type, + ]; + + try{ + $this->dao->create($data); + return true; + } catch (\Exception $exception) { + throw new ValidateException('创建失败'); + } + } + + /** + * TODO 删除 + * @param int $leftId + * @param string $type + * @param int $rightId + * @return bool + * @author Qinii + * @day 10/28/21 + */ + public function destory(int $leftId, int $rightId, string $type) + { + return $this->dao->getSearch([ + 'left_id' => $leftId, + 'right_id'=> $rightId, + 'type' => $type, + ])->delete(); + } + + /** + * TODO 检测是否存在 + * @param int $leftId + * @param int $rightId + * @param string $type + * @return int + * @author Qinii + * @day 10/28/21 + */ + public function checkHas(int $leftId, int $rightId, string $type) + { + return $this->dao->getSearch([ + 'left_id' => $leftId, + 'right_id'=> $rightId, + 'type' => $type, + ])->count(); + } + + /** + * TODO 根据左键批量删除 + * @param int $leftId + * @param $type + * @return bool + * @author Qinii + * @day 10/28/21 + */ + public function batchDelete(int $leftId, $type) + { + return $this->dao->getSearch([ + 'left_id' => $leftId, + 'type' => $type, + ])->delete(); + } + + /** + * TODO 关注我的人 + * @param int $uid + * @return \think\Collection + * @author Qinii + * @day 10/28/21 + */ + public function getUserFans(int $uid, int $page, int $limit) + { + $query = $this->dao->getSearch([ + 'right_id' => $uid, + 'type' => self::TYPE_COMMUNITY_FANS, + ])->with([ + 'fans' => function($query) { + $query->field('uid,avatar,nickname,count_fans'); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['is_start']); + return compact('count','list'); + } + + /** + * TODO 我关注的人 + * @param $uid + * @return \think\Collection + * @author Qinii + * @day 10/28/21 + */ + public function getUserFocus(int $uid, int $page, int $limit) + { + $query = $this->dao->getSearch([ + 'left_id' => $uid, + 'type' => self::TYPE_COMMUNITY_FANS, + ])->with([ + 'focus' => function($query) { + $query->field('uid,avatar,nickname,count_fans'); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['is_fans']); + return compact('count','list'); + } + + + /** + * TODO 我点赞过的文章 + * @param int $uid + * @return \think\Collection + * @author Qinii + * @day 10/28/21 + */ + public function getUserStartCommunity(array $where, int $page, int $limit) + { + $query = $this->dao->joinUser($where)->with([ + 'community'=> function($query) use($where){ + $query->with([ + 'author' => function($query){ + $query->field('uid,real_name,status,avatar,nickname,count_start'); + }, + 'is_start' => function($query) use ($where) { + $query->where('left_id',$where['uid']); + }, + 'topic' => function($query) { + $query->where('status', 1)->where('is_del',0); + $query->field('topic_id,topic_name,status,category_id,pic,is_del'); + }, + 'relevance' => [ + 'spu' => function($query) { + $query->field('spu_id,store_name,image,price,product_type,activity_id,product_id'); + } + ], + 'is_fans' => function($query) use($where){ + $query->where('left_id',$where['uid']); + }]); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->each(function ($item){ + $item['time'] = date('m月d日', strtotime($item['create_time'])); + return $item; + }); + + return compact('count','list'); + } + + /** + * TODO 我点赞过的文章 + * @param int $uid + * @return \think\Collection + * @author Qinii + * @day 10/28/21 + */ + public function getUserStartCommunityByVideos(array $where, int $page, int $limit) + { + $query = $this->dao->joinUser($where)->with([ + 'community'=> function($query) { + $query->with(['author'=> function($query) { + $query->field('uid,avatar,nickname'); + }]); + }, + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->each(function ($item){ + $item['time'] = date('m月d日', strtotime($item['create_time'])); + return $item; + }); + + return compact('count','list'); + } + + public function getFieldCount(string $field, int $value, string $type) + { + return $this->dao->getSearch([$field => $value, 'type' => $type,])->count(); + } + + public function createMany(int $leftId, array $rightId, string $type) + { + if (!empty($rightId)) { + foreach ($rightId as $value) { + $res[] = [ + 'left_id' => $leftId, + 'right_id' => $value, + 'type' => $type, + ]; + } + $this->dao->insertAll($res); + } + } + +} diff --git a/app/common/repositories/system/admin/AdminLogRepository.php b/app/common/repositories/system/admin/AdminLogRepository.php new file mode 100644 index 00000000..2e89b0ba --- /dev/null +++ b/app/common/repositories/system/admin/AdminLogRepository.php @@ -0,0 +1,106 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\admin; + + +use app\common\dao\BaseDao; +use app\common\dao\system\admin\LogDao; +use app\common\repositories\BaseRepository; +use app\Request; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Model; + +/** + * Class AdminLogRepository + * @package app\common\repositories\system\admin + * @author xaboy + * @day 2020-04-16 + */ +class AdminLogRepository extends BaseRepository +{ + /** + * AdminLogRepository constructor. + * @param LogDao $dao + */ + public function __construct(LogDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $merId + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function lst($merId, array $where, $page, $limit) + { + $query = $this->dao->search($where, $merId); + $count = $query->count($this->dao->getPk()); + $list = $query->setOption('field', [])->field(['create_time', 'log_id', 'admin_name', 'route', 'method', 'url', 'ip', 'admin_id']) + ->page($page, $limit)->order('create_time DESC')->select(); + return compact('count', 'list'); + } + + /** + * @param Request $request + * @param int $merId + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-15 + */ + public function addLog(Request $request, int $merId = 0) + { + return $this->create($merId, self::parse($request)); + } + + /** + * @param int $merId + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-16 + */ + public function create(int $merId, array $data) + { + $data['mer_id'] = $merId; + return $this->dao->create($data); + } + + /** + * @param Request $request + * @return array + * @author xaboy + * @day 2020-04-16 + */ + public static function parse(Request $request) + { + return [ + 'admin_id' => $request->adminId(), + 'admin_name' => $request->adminInfo()->real_name ?: '未定义', + 'route' => $request->rule()->getName(), + 'ip' => $request->ip(), + 'url' => $request->url(true), + 'method' => $request->method() + ]; + } +} diff --git a/app/common/repositories/system/admin/AdminRepository.php b/app/common/repositories/system/admin/AdminRepository.php new file mode 100644 index 00000000..2347709a --- /dev/null +++ b/app/common/repositories/system/admin/AdminRepository.php @@ -0,0 +1,327 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\admin; + + +//附件 +use app\common\dao\system\admin\AdminDao; +use app\common\model\system\admin\Admin; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\auth\RoleRepository; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Config; +use think\facade\Route; +use think\Model; + + +/** + * Class BaseRepository + * @package common\repositories + * @mixin AdminDao + */ +class AdminRepository extends BaseRepository +{ + public function __construct(AdminDao $dao) + { + /** + * @var AdminDao + */ + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->hidden(['pwd', 'is_del', 'update_time'])->select(); + + foreach ($list as $k => $role) { + $list[$k]['rule_name'] = $role->roleNames(); + } + return compact('list', 'count'); + } + + public function passwordEncode($password) + { + return password_hash($password, PASSWORD_BCRYPT); + } + + /** + * 更新 + * @param int $id id + * @param array $data 数组 + * @return int + * @throws DbException + * @author 张先生 + * @date 2020-03-26 + */ + public function update(int $id, array $data) + { + if (isset($data['roles'])) + $data['roles'] = implode(',', $data['roles']); + return $this->dao->update($id, $data); + } + + /** + * @param int $id + * @param $isSelf + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function passwordForm(int $id, $isSelf = false) + { + $form = Elm::createForm(Route::buildUrl($isSelf ? 'systemAdminEditPassword' : 'systemAdminPassword', $isSelf ? [] : compact('id'))->build(), [ + $rules[] = Elm::password('pwd', '密码')->required(), + $rules[] = Elm::password('againPassword', '确认密码')->required(), + ]); + return $form->setTitle('修改密码'); + + } + + /** + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function editForm(array $formData) + { + $form = Elm::createForm(Route::buildUrl('systemAdminEdit')->build()); + $form->setRule([ + Elm::input('real_name', '管理员姓名')->required(), + Elm::input('phone', '联系电话') + ]); + + return $form->setTitle('修改信息')->formData($formData); + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-08 + */ + public function form(?int $id = null, array $formData = []): Form + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemAdminCreate')->build() : Route::buildUrl('systemAdminUpdate', ['id' => $id])->build()); + + $rules = [ + Elm::select('roles', '身份', [])->options(function () { + $data = app()->make(RoleRepository::class)->getAllOptions(0); + $options = []; + + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + })->multiple(true)->required(), + Elm::input('real_name', '管理员姓名'), + Elm::input('account', '账号')->required(), + Elm::input('phone', ' 联系电话'), + ]; + if (!$id) { + $rules[] = Elm::password('pwd', '密码')->required(); + $rules[] = Elm::password('againPassword', '确认密码')->required(); + } + $rules[] = Elm::switches('status', '是否开启', 1)->inactiveValue(0)->activeValue(1)->inactiveText('关')->activeText('开'); + $form->setRule($rules); + return $form->setTitle(is_null($id) ? '添加管理员' : '编辑管理员')->formData($formData); + } + + /** + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function updateForm(int $id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } + + + /** + * @param string $account + * @param string $password + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-10 + */ + public function login(string $account, string $password) + { + event('admin.login.before',compact('account','password')); + $adminInfo = $this->dao->accountByAdmin($account); + if (!$adminInfo || !password_verify($password, $adminInfo->pwd)){ + $key = 'sys_login_failuree_'.$account; + $numb = Cache::get($key) ?? 0; + $numb++; + Cache::set($key,$numb,15*60); + throw new ValidateException('账号或密码错误'); + } + + if ($adminInfo['status'] != 1) + throw new ValidateException('账号已关闭'); + + $adminInfo->last_time = date('Y-m-d H:i:s'); + $adminInfo->last_ip = app('request')->ip(); + $adminInfo->login_count++; + $adminInfo->save(); + event('admin.login',compact('adminInfo')); + return $adminInfo; + } + + /** + * TODO 登录尝试次数限制 + * @param $account + * @param int $number + * @param int $n + * @author Qinii + * @day 7/6/21 + */ + public function loginFailure($account,$number = 5,$n = 3) + { + $key = 'sys_login_failuree_'.$account; + $numb = Cache::get($key) ?? 0; + $numb++; + if($numb >= $number){ + $fail_key = 'sys_login_freeze_'.$account; + Cache::tag('sys_login_freeze')->set($fail_key,1,15*60); + throw new ValidateException('账号或密码错误次数太多,请稍后在尝试'); + }else{ + Cache::tag('sys_login_freeze')->set($key,$numb,5*60); + $msg = '账号或密码错误'; + $_n = $number - $numb; + if($_n <= $n){ + $msg .= ',还可尝试'.$_n.'次'; + } + throw new ValidateException($msg); + } + } + + /** + * @param string $token + * @param int $exp + * @author xaboy + * @day 2020-04-10 + */ + public function cacheToken(string $token, int $exp) + { + Cache::set('admin_' . $token, time() + $exp, $exp); + } + + public function checkToken(string $token) + { + $has = Cache::has('admin_' . $token); + if (!$has) + throw new AuthException('无效的token'); + $lastTime = Cache::get('admin_' . $token); + if (($lastTime + (intval(Config::get('admin.token_valid_exp', 15))) * 60) < time()) + throw new AuthException('token 已过期'); + } + + public function updateToken(string $token) + { + Cache::set('admin_' . $token, time(), intval(Config::get('admin.token_valid_exp', 15)) * 60); + } + + public function clearToken(string $token) + { + Cache::delete('admin_' . $token); + } + + /** + * @param Admin $admin + * @return array + * @author xaboy + * @day 2020-04-09 + */ + public function createToken(Admin $admin) + { + $service = new JwtTokenService(); + $exp = intval(Config::get('admin.token_exp', 3)); + $token = $service->createToken($admin->admin_id, 'admin', strtotime("+ {$exp}hour")); + $this->cacheToken($token['token'], $token['out']); + return $token; + } + + /** + * 检测验证码 + * @param string $key key + * @param string $code 验证码 + * @author 张先生 + * @date 2020-03-26 + */ + public function checkCode(string $key, string $code) + { + if (!env('DEVELOPMENT',false)) { + $_code = Cache::get('am_captcha' . $key); + if (!$_code) { + throw new ValidateException('验证码过期'); + } + + if (strtolower($_code) != strtolower($code)) { + throw new ValidateException('验证码错误'); + } + + //删除code + Cache::delete('am_captcha' . $key); + } + } + + + /** + * @param string $code + * @return string + * @author xaboy + * @day 2020-04-09 + */ + public function createLoginKey(string $code) + { + $key = uniqid(microtime(true), true); + Cache::set('am_captcha' . $key, $code, Config::get('admin.captcha_exp', 5) * 60); + return $key; + } +} diff --git a/app/common/repositories/system/attachment/AttachmentCategoryRepository.php b/app/common/repositories/system/attachment/AttachmentCategoryRepository.php new file mode 100644 index 00000000..f9a33412 --- /dev/null +++ b/app/common/repositories/system/attachment/AttachmentCategoryRepository.php @@ -0,0 +1,172 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\attachment; + + +//附件 +use app\common\dao\BaseDao; +use app\common\dao\system\attachment\AttachmentCategoryDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; +use think\Model; + +/** + * Class BaseRepository + * @package common\repositories + * @mixin AttachmentCategoryDao + */ +class AttachmentCategoryRepository extends BaseRepository +{ + /** + * AttachmentCategoryRepository constructor. + * @param AttachmentCategoryDao $dao + */ + public function __construct(AttachmentCategoryDao $dao) + { + /** + * @var AttachmentCategoryDao + */ + $this->dao = $dao; + } + + /** + * @param int $merId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-22 + */ + public function form(int $merId, ?int $id = null, array $formData = []): Form + { + if ($merId) { + $action = is_null($id) ? 'merchantAttachmentCategoryCreate' : 'merchantAttachmentCategoryUpdate'; + } else { + $action = is_null($id) ? 'systemAttachmentCategoryCreate' : 'systemAttachmentCategoryUpdate'; + } + + $form = Elm::createForm(Route::buildUrl($action, is_null($id) ? [] : ['id' => $id])->build()); + $form->setRule([ + Elm::cascader('pid', '上级分类')->options(function () use ($id, $merId) { + $menus = $this->dao->getAllOptions($merId); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'attachment_category_name'); + array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]])->appendValidate(Elm::validateInt()->required()->message('请选择上级分类')), + Elm::input('attachment_category_name', '分类名称')->required(), + Elm::input('attachment_category_enname', '分类目录', 'def')->required(), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加配置' : '编辑配置')->formData($formData); + } + + /** + * @param int $merId + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-22 + */ + public function updateForm(int $merId, int $id) + { + return $this->form($merId, $id, $this->dao->get($id, $merId)->toArray()); + } + + /** + * @param int $merId + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-22 + */ + public function getFormatList(int $merId) + { + return formatCategory($this->dao->getAll($merId)->toArray(), 'attachment_category_id'); + } + + /** + * @param int $id + * @param $merId + * @param array $data + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-30 + */ + public function update(int $id, $merId, array $data) + { + $model = $this->dao->get($id, $merId); + if ($model->pid != $data['pid']) { + Db::transaction(function () use ($data, $model) { + $data['path'] = $this->getPathById($data['pid']); + if (substr_count(trim($data['path'], '/'), '/') > 1) throw new ValidateException('素材分类最多添加三级'); + $this->dao->updatePath($model->path . $model->attachment_category_id, $data['path'] . $model->attachment_category_id); + $model->save($data); + }); + } else { + unset($data['path']); + $this->dao->update($id, $data); + } + } + + /** + * 添加 + * @param array $data 添加的数据 + * @return BaseDao|int|Model + * @author 张先生 + * @date 2020-03-30 + */ + public function create(array $data) + { + $data['path'] = $this->getPathById($data['pid']); + if (substr_count(trim($data['path'], '/'), '/') > 1) throw new ValidateException('素材分类最多添加三级'); + return $this->dao->create($data); + } + + + /** + * 获取path + * @param int $id 主键id + * @return mixed + * @author 张先生 + * @date 2020-03-30 + */ + private function getPathById(int $id = 0) + { + $result = '/'; + if ($id) { + $result = $this->dao->getPathById($id) . $id . '/'; + } + return $result; + } + +} diff --git a/app/common/repositories/system/attachment/AttachmentRepository.php b/app/common/repositories/system/attachment/AttachmentRepository.php new file mode 100644 index 00000000..2cc71e92 --- /dev/null +++ b/app/common/repositories/system/attachment/AttachmentRepository.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\attachment; + + +//附件 +use app\common\dao\BaseDao; +use app\common\dao\system\attachment\AttachmentDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; +use think\Model; + + +/** + * Class BaseRepository + * @package common\repositories + * @mixin AttachmentDao + */ +class AttachmentRepository extends BaseRepository +{ + /** + * @var AttachmentCategoryRepository + */ + private $attachmentCategoryRepository; + + /** + * AttachmentRepository constructor. + * @param AttachmentDao $dao + * @param AttachmentCategoryRepository $attachmentCategoryRepository + */ + public function __construct(AttachmentDao $dao, AttachmentCategoryRepository $attachmentCategoryRepository) + { + /** + * @var AttachmentDao + */ + $this->dao = $dao; + $this->attachmentCategoryRepository = $attachmentCategoryRepository; + } + + + /** + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function getList(array $where, int $page, int $limit) + { + $query = $this->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->hidden(['upload_type', 'user_type', 'user_id']) + ->select(); + return compact('count', 'list'); + } + + /** + * @param int $uploadType + * @param int $userType + * @param int $userId + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-15 + */ + public function create(int $uploadType, int $userType, int $userId, array $data) + { + $data['upload_type'] = $uploadType; + $data['user_type'] = $userType; + $data['user_id'] = $userId; + return $this->dao->create($data); + } + + /** + * @param array $ids + * @param int $categoryId + * @param int $merId + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-16 + */ + public function batchChangeCategory(array $ids, int $categoryId, $merId = 0) + { + return $this->dao->batchChange($ids, ['attachment_category_id' => $categoryId], $merId); + } + + public function form(int $id,int $merId) + { + if ($merId) { + $action = 'merchantAttachmentUpdate'; + } else { + $action = 'systemAttachmentUpdate'; + } + $formData = $this->dao->get($id)->toArray(); + $form = Elm::createForm(Route::buildUrl($action, is_null($id) ? [] : ['id' => $id])->build()); + $form->setRule([ + Elm::input('attachment_name', '名称')->required(), + ]); + return $form->setTitle('编辑配置')->formData($formData); + } +} diff --git a/app/common/repositories/system/auth/MenuRepository.php b/app/common/repositories/system/auth/MenuRepository.php new file mode 100644 index 00000000..c72eb912 --- /dev/null +++ b/app/common/repositories/system/auth/MenuRepository.php @@ -0,0 +1,343 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +namespace app\common\repositories\system\auth; + + +//附件 +use app\common\dao\BaseDao; +use app\common\dao\system\menu\MenuDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Exception; +use think\facade\Db; +use think\facade\Route; +use think\Model; + +/** + * Class BaseRepository + * @package common\repositories + * @mixin MenuDao + */ +class MenuRepository extends BaseRepository +{ + /** + * MenuRepository constructor. + * @param MenuDao $dao + */ + protected $styles = array( + 'success' => "\033[0;32m%s\033[0m", + 'error' => "\033[31;31m%s\033[0m", + 'info' => "\033[33;33m%s\033[0m" + ); + + public $prompt = 'all'; + + public function __construct(MenuDao $dao) + { + /** + * @var MenuDao + */ + $this->dao = $dao; + } + + + /** + * @param array $where + * @param int $merId + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function getList(array $where, $merId = 0) + { + $query = $this->dao->search($where, $merId); + $count = $query->count(); + $list = $query->hidden(['update_time', 'path'])->select()->toArray(); + return compact('count', 'list'); + } + + /** + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-09 + */ + public function create(array $data) + { + $data['path'] = '/'; + if ($data['pid']) { + $data['path'] = $this->getPath($data['pid']) . $data['pid'] . '/'; + } + return $this->dao->create($data); + } + + /** + * @param int $id + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function update(int $id, array $data) + { + $menu = $this->dao->get($id); + if ($menu->pid != $data['pid']) { + Db::transaction(function () use ($menu, $data) { + $data['path'] = '/'; + if ($data['pid']) { + $data['path'] = $this->getPath($data['pid']) . $data['pid'] . '/'; + } + $this->dao->updatePath($menu->path . $menu->menu_id . '/', $data['path'] . $menu->menu_id . '/'); + $menu->save($data); + }); + } else { + unset($data['path']); + $this->dao->update($id, $data); + } + } + + /** + * @param bool $is_mer + * @return array + * @author xaboy + * @day 2020-04-18 + */ + public function getTree($merType = 0) + { + if (!$merType) { + $options = $this->dao->getAllOptions(); + } else { + $options = $this->dao->merchantTypeByOptions($merType); + } + return formatTree($options, 'menu_name'); + } + + /** + * @param int $isMer + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-16 + */ + public function menuForm(int $isMer = 0, ?int $id = null, array $formData = []): Form + { + $action = $isMer == 0 ? (is_null($id) ? Route::buildUrl('systemMenuCreate')->build() : Route::buildUrl('systemMenuUpdate', ['id' => $id])->build()) + : (is_null($id) ? Route::buildUrl('systemMerchantMenuCreate')->build() : Route::buildUrl('systemMerchantMenuUpdate', ['id' => $id])->build()); + + $form = Elm::createForm($action); + $form->setRule([ + Elm::cascader('pid', '父级分类')->options(function () use ($id, $isMer) { + $menus = $this->dao->getAllOptions($isMer, true); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'menu_name'); + array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]), + Elm::select('is_menu', '权限类型', 1)->options([ + ['value' => 1, 'label' => '菜单'], + ['value' => 0, 'label' => '权限'], + ])->control([ + [ + 'value' => 0, + 'rule' => [ + Elm::input('menu_name', '路由名称')->required(), + Elm::textarea('params', '参数')->placeholder("路由参数:\r\nkey1:value1\r\nkey2:value2"), + ] + ], [ + 'value' => 1, + 'rule' => [ + Elm::switches('is_show', '是否显示', 1)->inactiveValue(0)->activeValue(1)->inactiveText('关')->activeText('开'), + Elm::frameInput('icon', '菜单图标', '/' . config('admin.admin_prefix') . '/setting/icons?field=icon')->icon('el-icon-circle-plus-outline')->height('338px')->width('700px')->modal(['modal' => false]), + Elm::input('menu_name', '菜单名称')->required(), + ] + ] + ]), + Elm::input('route', '路由'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999) + ]); + + return $form->setTitle(is_null($id) ? '添加菜单' : '编辑菜单')->formData($formData); + } + + + /** + * @param int $id + * @param int $merId + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function updateMenuForm(int $id, $merId = 0) + { + return $this->menuForm($merId, $id, $this->dao->get($id)->toArray()); + } + + + /** + * @param string $params + * @return array + * @author xaboy + * @day 2020-04-22 + */ + public function tidyParams(?string $params) + { + return $params ? array_reduce(explode('|', $params), function ($initial, $val) { + $data = explode(':', $val, 2); + if (count($data) != 2) return $initial; + $initial[$data[0]] = $data[1]; + return $initial; + }, []) : []; + } + + /** + * @param array $params + * @param array $routeParams + * @return bool + * @author xaboy + * @day 2020-04-23 + */ + public function checkParams(array $params, array $routeParams) + { + foreach ($routeParams as $k => $param) { + if (isset($params[$k]) && $params[$k] != $param) + return false; + } + return true; + } + + public function formatPath($is_mer = 0) + { + $options = $this->getAll($is_mer); + $options = formatCategory($options, 'menu_id'); + Db::transaction(function () use ($options) { + foreach ($options as $option) { + $this->_formatPath($option); + } + }); + } + + protected function _formatPath($parent, $path = '/') + { + $this->dao->update($parent['menu_id'], ['path' => $path]); + foreach ($parent['children'] ?? [] as $item) { + $itemPath = $path . $item['pid'] . '/'; + $this->_formatPath($item, $itemPath); + } + } + + + public function commandMenu($type, $data, $prompt) + { + $res = []; + if ($prompt) $this->prompt = $prompt; + $isMer = ($type == 'sys') ? 0 : 1; + + foreach ($data as $key => $value) { + try{ + $result = $this->dao->getMenuPid($key, $isMer, 0); + if (!$result) { + $route = $key; + $isAppend =0; + if (substr($key,0,7) === 'append_') { + $isAppend = 1; + $route = substr($key,7); + } + $result = $this->dao->getMenuPid($route, $isMer, 1); + if (!$result && $key !== 'self') { + printf($this->styles['info'], '未找到菜单: '. $key); + echo PHP_EOL; + continue; + } else { + $result = $this->dao->create([ + 'pid' => $key == 'self' ? 0 : $result['menu_id'], + 'path' => $key == 'self' ? '/' : $result['path'] . $result['menu_id'] . '/', + 'menu_name' => $isAppend ? '附加权限' : '权限' , + 'route' => $key, + 'is_mer' => $isMer, + 'is_menu' => 0 + ]); + } + } + $res = array_merge($res, $this->createSlit($isMer, $result['menu_id'], $result['path'], $value)); + }catch (\Exception $exception) { + throw new Exception($key); + } + } + $count = count($res); + if (!empty($res)) $this->dao->insertAll($res); + return $count; + } + + /** + * TODO 新增权限数据整理 + * @param int $isMer + * @param int $menuId + * @param string $path + * @param array $data + * @return array + * @author Qinii + * @day 3/18/22 + */ + public function createSlit(int $isMer,int $menuId, string $path,array $data) + { + $arr = []; + try { + foreach ($data as $k => $v) { + $result = $this->dao->getWhere(['route' => $v['route'], 'pid' => $menuId]); + if (!$result) { + $arr[] = [ + 'pid' => $menuId, + 'path' => $path . $menuId . '/', + 'menu_name' => $v['menu_name'], + 'route' => $v['route'], + 'is_mer' => $isMer, + 'is_menu' => 0, + 'params' => $v['params'] ?? [], + ]; + if ($this->prompt == 's') { + printf($this->styles['success'], '新增权限: ' . $v['menu_name'] . ' [' . $v['route'] . ']'); + echo PHP_EOL; + } + } + } + return $arr; + }catch (\Exception $exception) { + halt($isMer, $menuId, $path, $data); + } + } +} + diff --git a/app/common/repositories/system/auth/RoleRepository.php b/app/common/repositories/system/auth/RoleRepository.php new file mode 100644 index 00000000..67e648bc --- /dev/null +++ b/app/common/repositories/system/auth/RoleRepository.php @@ -0,0 +1,135 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\auth; + + +//附件 +use app\common\dao\system\menu\RoleDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; + + +/** + * Class BaseRepository + * @package common\repositories + * @mixin RoleDao + */ +class RoleRepository extends BaseRepository +{ + public function __construct(RoleDao $dao) + { + /** + * @var RoleDao + */ + $this->dao = $dao; + } + + /** + * @param int $merId + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function search(int $merId, array $where, $page, $limit) + { + $query = $this->dao->search($merId, $where); + $count = $query->count(); + $list = $query->page($page, $limit)->hidden(['update_time'])->select(); + + foreach ($list as $k => $role) { + $list[$k]['rule_name'] = $role->ruleNames(); + } + + return compact('count', 'list'); + } + + /** + * @param int $id + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function update(int $id, array $data) + { + if (isset($data['rules'])) + $data['rules'] = implode(',', $data['rules']); + return $this->dao->update($id, $data); + } + + /** + * @param bool $is_mer + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-18 + */ + public function form($merType = 0, ?int $id = null, array $formData = []): Form + { + if ($merType) + $form = Elm::createForm(is_null($id) ? Route::buildUrl('merchantRoleCreate')->build() : Route::buildUrl('merchantRoleUpdate', ['id' => $id])->build()); + else + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemRoleCreate')->build() : Route::buildUrl('systemRoleUpdate', ['id' => $id])->build()); + + $options = app()->make(MenuRepository::class)->getTree($merType); + + $form->setRule([ + Elm::input('role_name', '身份名称')->required(), + Elm::tree('rules', '权限')->data($options)->showCheckbox(true), + Elm::switches('status', '是否开启', 1)->inactiveValue(0)->activeValue(1)->inactiveText('关')->activeText('开'), + ]); + + return $form->setTitle(is_null($id) ? '添加身份' : '编辑身份')->formData($formData); + } + + + /** + * @param bool $is_mer + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function updateForm($is_mer, int $id) + { + return $this->form($is_mer, $id, $this->dao->get($id)->toArray()); + } + + public function checkRole(array $role, $merId) + { + $rest = $this->dao->search($merId, ['role_ids' => $role,'status' => 1])->column('role_id'); + sort($role); + sort($rest); + return (sort($role) == sort($rest)) ? true: false; + } +} diff --git a/app/common/repositories/system/config/ConfigClassifyRepository.php b/app/common/repositories/system/config/ConfigClassifyRepository.php new file mode 100644 index 00000000..37b77def --- /dev/null +++ b/app/common/repositories/system/config/ConfigClassifyRepository.php @@ -0,0 +1,142 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\config; + + +use app\common\dao\system\config\SystemConfigClassifyDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; + +/** + * Class ConfigClassifyRepository + * @package crmeb\repositories\system\config + * @mixin SystemConfigClassifyDao + */ +class ConfigClassifyRepository extends BaseRepository +{ + + /** + * ConfigClassifyRepository constructor. + * @param SystemConfigClassifyDao $dao + */ + public function __construct(SystemConfigClassifyDao $dao) + { + $this->dao = $dao; + } + + /** + * @return array + * @author xaboy + * @day 2020-03-27 + */ + public function options(): array + { + $options = $this->dao->getOptions(); + return formatCascaderData($options, 'classify_name'); + } + + /** + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function lst($where) + { + $query = $this->dao->search($where); + $list = $query->select(); + $count = $query->count(); + + return compact('list', 'count'); + } + + /** + * @param int $id + * @param int $status + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchStatus(int $id, int $status) + { + return $this->dao->update($id, compact('status')); + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function form(?int $id = null, array $formData = []): Form + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('configClassifyCreate')->build() : Route::buildUrl('configClassifyUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::select('pid', '上级分类', 0)->options(function () { + $data = $this->dao->getTopOptions(); + $options = [['value' => 0, 'label' => '顶级分类']]; + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + }), + Elm::input('classify_name', '配置分类名称')->required(), + Elm::input('classify_key', '配置分类key')->required(), + Elm::input('info', '配置分类说明'), + Elm::frameInput('icon', '配置分类图标', '/' . config('admin.admin_prefix') . '/setting/icons?field=icon')->icon('el-icon-circle-plus-outline')->height('338px')->width('700px')->modal(['modal' => false]), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]); + + return $form->setTitle(is_null($id) ? '添加配置分类' : '编辑配置分类')->formData($formData); + } + + /** + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-30 + */ + public function createForm() + { + return $this->form(); + } + + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function updateForm($id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } +} diff --git a/app/common/repositories/system/config/ConfigRepository.php b/app/common/repositories/system/config/ConfigRepository.php new file mode 100644 index 00000000..5f73362f --- /dev/null +++ b/app/common/repositories/system/config/ConfigRepository.php @@ -0,0 +1,475 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\config; + + +use app\common\dao\system\config\SystemConfigDao; +use app\common\model\system\config\SystemConfigClassify; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\CacheRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\facade\Route; + +/** + * Class ConfigRepository + * @package crmeb\repositories\system\config + * @mixin SystemConfigDao + */ +class ConfigRepository extends BaseRepository +{ + const TYPES = ['input' => '文本框', 'number' => '数字框', 'textarea' => '多行文本框', 'radio' => '单选框', 'switches' => '开关', 'checkbox' => '多选框', 'select' => '下拉框', 'file' => '文件上传', 'image' => '图片上传', 'images' => '多图片上传', 'color' => '颜色选择框']; + + /** + * ConfigRepository constructor. + * @param SystemConfigDao $dao + */ + public function __construct(SystemConfigDao $dao) + { + $this->dao = $dao; + } + + /** + * @param int $merId + * @param SystemConfigClassify $configClassify + * @param array $configs + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-23 + */ + public function formRule(int $merId, SystemConfigClassify $configClassify, array $configs, array $formData = []) + { + $components = $this->getRule($configs, $merId); + + $form = Elm::createForm(Route::buildUrl($merId ? 'merchantConfigSave' : 'configSave', ['key' => $configClassify->classify_key])->build(), $components); + return $form->setTitle($configClassify->classify_name)->formData(array_filter($formData, function ($item) { + return $item !== '' && !is_null($item); + })); + } + + public function getRule(array $configs, $merId) + { + $components = []; + foreach ($configs as $config) { + $component = $this->getComponent($config, $merId); + $components[] = $component; + } + return $components; + } + + public function getComponent($config, $merId) + { + switch ($config['config_type']) { + case 'image': + $component = Elm::frameImage($config['config_key'], $config['config_name'], '/' . config('admin.' . ($merId ? 'merchant' : 'admin') . '_prefix') . '/setting/uploadPicture?field=' . $config['config_key'] . '&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]); + break; + case 'images': + $component = Elm::frameImage($config['config_key'], $config['config_name'], '/' . config('admin.' . ($merId ? 'merchant' : 'admin') . '_prefix') . '/setting/uploadPicture?field=' . $config['config_key'] . '&type=2')->maxLength(5)->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]); + break; + case 'file': + $component = Elm::uploadFile($config['config_key'], $config['config_name'], rtrim(systemConfig('site_url'), '/') . Route::buildUrl('configUpload', ['field' => 'file'])->build())->headers(['X-Token' => request()->token()]); + break; + case 'select': + //notbreak + case 'checkbox': + //notbreak + case 'radio': + $options = array_map(function ($val) { + [$value, $label] = explode(':', $val, 2); + return compact('value', 'label'); + }, explode("\n", $config['config_rule'])); + $component = Elm::{$config['config_type']}($config['config_key'], $config['config_name'])->options($options); + break; + case 'switches': + $component = Elm::{$config['config_type']}($config['config_key'], $config['config_name'])->activeText('开')->inactiveText('关'); + break; + default: + $component = Elm::{$config['config_type']}($config['config_key'], $config['config_name']); + break; + } + + if ($config['required']) $component->required(); + + if ($config['config_props'] ?? '') { + $props = @parse_ini_string($config['config_props'], false, INI_SCANNER_TYPED); + if (is_array($props)) { + $guidance_uri = $props['guidance_uri'] ?? ''; + $guidance_image = $props['guidance_image'] ?? ''; + if ($guidance_image) { + $config['guidance'] = [ + 'uri' => $guidance_uri, + 'image' => $guidance_image, + ]; + } + unset($props['guidance_image'], $props['guidance_uri']); + $component->props($props); + if (isset($props['required']) && $props['required']) { + $component->required(); + } + if (isset($props['defaultValue'])) { + $component->value($props['defaultValue']); + } + } + } + if ($config['info']) { + $component->appendRule('suffix', [ + 'type' => 'guidancePop', + 'props' => [ + 'info' => $config['info'], + 'url' => $config['guidance']['uri'] ?? '', + 'image' => $config['guidance']['image'] ?? '', + ] + ]); + } + return $component; + } + + /** + * @param int $id + * @param int $status + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchStatus(int $id, int $status) + { + return $this->dao->update($id, compact('status')); + } + + /** + * @param SystemConfigClassify $configClassify + * @param int $merId + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-22 + */ + public function cidByFormRule(SystemConfigClassify $configClassify, int $merId) + { + $config = $this->dao->cidByConfig($configClassify->config_classify_id, $merId == 0 ? 0 : 1); + $keys = $config->column('config_key'); + return $this->formRule($merId, $configClassify, $config->toArray(), app()->make(ConfigValueRepository::class)->more($keys, $merId)); + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function form(?int $id = null, array $formData = []): Form + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('configSettingCreate')->build() : Route::buildUrl('configSettingUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::cascader('config_classify_id', '上级分类')->options(function () { + $configClassifyRepository = app()->make(ConfigClassifyRepository::class); + return array_merge([['value' => 0, 'label' => '请选择']], $configClassifyRepository->options()); + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]), + Elm::select('user_type', '后台类型', 0)->options([ + ['label' => '总后台配置', 'value' => 0], + ['label' => '商户后台配置', 'value' => 1], + ])->requiredNum(), + Elm::input('config_name', '配置名称')->required(), + Elm::input('config_key', '配置key')->required(), + Elm::textarea('info', '说明'), + Elm::select('config_type', '配置类型')->options(function () { + $options = []; + foreach (self::TYPES as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + })->required(), + Elm::textarea('config_rule', '选择项'), + Elm::textarea('config_props', '配置'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::switches('required', '必填', 0)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]); + + return $form->setTitle(is_null($id) ? '添加配置' : '编辑配置')->formData($formData); + } + + /** + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function updateForm(int $id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } + + /** + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function lst(array $where, int $page, int $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->withAttr('typeName', function ($value, $data) { + return self::TYPES[$data['config_type']]; + })->hidden(['config_classify_id'])->append(['typeName'])->select(); + return compact('count', 'list'); + } + + public function tabForm($group, $merId) + { + $make = app()->make(ConfigClassifyRepository::class); + $list = $make->children($group->config_classify_id, 'config_classify_id,classify_key,classify_name,info'); + $children = []; + foreach ($list as $item) { + $_children = $this->cidByFormRule($make->keyByData($item['classify_key']), $merId)->formRule(); + if ($item['info']) { + array_unshift($_children, [ + 'type' => 'el-alert', + 'props' => [ + 'type' => 'warning', + 'closable' => false, + 'title' => $item['info'] + ] + ], ['type' => 'div', 'style' => ['height' => '20px', 'width' => '100%']]); + } + $children[] = [ + 'type' => 'el-tab-pane', + 'props' => [ + 'label' => $item['classify_name'], + 'name' => $item['classify_key'] + ], + 'children' => $_children + ]; + } + if ($group['classify_key'] === 'distribution_tabs') { + $action = Route::buildUrl('configOthersSettingUpdate')->build(); + } else { + $action = Route::buildUrl($merId ? 'merchantConfigSave' : 'configSave', ['key' => $group['classify_key']])->build(); + } + return Elm::createForm($action, [ + [ + 'type' => 'el-tabs', + 'native' => true, + 'props' => [ + 'value' => $list[0]['classify_key'] ?? '' + ], + 'children' => $children + ] + ])->setTitle($group['classify_name']); + } + + public function uploadForm() + { + $config = $this->getWhere(['config_key' => 'upload_type']); + $rule = $this->getComponent($config, 0)->value(systemConfig('upload_type')); + $make = app()->make(ConfigClassifyRepository::class); + $rule->control([ + [ + 'value' => '1', + 'rule' => $this->cidByFormRule($make->keyByData('local'), 0)->formRule() + ], + [ + 'value' => '2', + 'rule' => $this->cidByFormRule($make->keyByData('qiniuyun'), 0)->formRule() + ], + [ + 'value' => '3', + 'rule' => $this->cidByFormRule($make->keyByData('aliyun_oss'), 0)->formRule() + ], + [ + 'value' => '4', + 'rule' => $this->cidByFormRule($make->keyByData('tengxun'), 0)->formRule() + ], + [ + 'value' => '5', + 'rule' => $this->cidByFormRule($make->keyByData('huawei_obs'), 0)->formRule() + ], + [ + 'value' => '6', + 'rule' => $this->cidByFormRule($make->keyByData('ucloud'), 0)->formRule() + ], + ]); + return Elm::createForm(Route::buildUrl('systemSaveUploadConfig')->build(), [$rule])->setTitle('上传配置'); + } + + public function saveUpload($data) + { + $configValueRepository = app()->make(ConfigValueRepository::class); + $uploadType = $data['upload_type'] ?? '1'; + $key = ''; + switch ($uploadType) { + case 1: + $key = 'local'; + break; + case 2: + $key = 'qiniuyun'; + break; + case 3: + $key = 'aliyun_oss'; + break; + case 4: + $key = 'tengxun'; + break; + case 5: + $key = 'huawei_obs'; + break; + case 6: + $key = 'ucloud'; + break; + + } + + Db::transaction(function () use ($data, $key, $uploadType, $configValueRepository) { + $configValueRepository->setFormData([ + 'upload_type' => $uploadType + ], 0); + if ($key) { + $make = app()->make(ConfigClassifyRepository::class); + if (!($cid = $make->keyById($key))) return app('json')->fail('保存失败'); + $configValueRepository->save($cid, $data, 0); + } + }); + } + + public function wechatForm() + { + $formData['wechat_chekc_file'] = app()->make(CacheRepository::class)->getWhere(['key' => 'wechat_chekc_file']); + if ($formData['wechat_chekc_file'] && !is_file($formData['wechat_chekc_file'])) $formData['wechat_chekc_file'] = ''; + + $form = Elm::createForm(Route::buildUrl('configWechatUploadSet')->build()); + + $form->setRule([ + Elm::uploadFile('wechat_chekc_file', '上传校验文件', rtrim(systemConfig('site_url'), '/') . Route::buildUrl('configUploadName', ['field' => 'file'])->build())->headers(['X-Token' => request()->token()]), + ]); + return $form->setTitle('上传校验文件')->formData($formData); + } + + /** + * 替换appid + * @param string $appid + * @param string $projectanme + */ + public function updateConfigJson($appId = '', $projectName = '', $path = '') + { + $fileUrl = $path . "/download/project.config.json"; + $string = file_get_contents($fileUrl); //加载配置文件 + // 替换appid + $appIdOld = '/"appid"(.*?),/'; + $appIdNew = '"appid"' . ': ' . '"' . $appId . '",'; + $string = preg_replace($appIdOld, $appIdNew, $string); // 正则查找然后替换 + // 替换小程序名称 + $projectNameOld = '/"projectname"(.*?),/'; + $projectNameNew = '"projectname"' . ': ' . '"' . $projectName . '",'; + $string = preg_replace($projectNameOld, $projectNameNew, $string); // 正则查找然后替换 + $newFileUrl = $path . "/download/project.config.json"; + @file_put_contents($newFileUrl, $string); // 写入配置文件 + } + + /** + * 替换url + * @param $url + */ + public function updateUrl($url, $path) + { + $fileUrl = $path . "/download/common/vendor.js"; + + $string = file_get_contents($fileUrl); //加载配置文件 + $string = str_replace('https://mer.crmeb.net', $url, $string); // 正则查找然后替换 + + $ws = str_replace('https', 'wss', $url); + $string = str_replace('wss://mer.crmeb.net', $ws, $string); // 正则查找然后替换 + + $newFileUrl = $path . "/download/common/vendor.js"; + @file_put_contents($newFileUrl, $string); // 写入配置文件 + } + + /** + * 关闭直播 + * @param int $iszhibo + */ + public function updateAppJson($path) + { + $fileUrl = $path . "/download/app.json"; + $string = file_get_contents($fileUrl); //加载配置文件 + $pats = '/, + "plugins": \{ + "live-player-plugin": \{ + "version": "(.*?)", + "provider": "(.*?)" + } + }/'; + $string = preg_replace($pats, '', $string); // 正则查找然后替换 + $newFileUrl = $path . "/download/app.json"; + @file_put_contents($newFileUrl, $string); // 写入配置文件 + } + + /** + * 去掉菜单 + * @param int $iszhibo + */ + public function updateRouteJson($path) + { + $fileUrl = $path . "/download/app.json"; + $string = file_get_contents($fileUrl); //加载配置文件 + $pats = '/ + { + "pagePath": "pages\/plant_grass\/index", + "iconPath": "static\/images\/5-001.png", + "selectedIconPath": "static\/images\/5-002.png", + "text": "逛逛" + },/'; + $string = preg_replace($pats, '', $string); // 正则查找然后替换 + $newFileUrl = $path . "/download/app.json"; + @file_put_contents($newFileUrl, $string); // 写入配置文件 + } + + /** + * TODO 请求方式 + * @param $path + * @param bool $plant + * @author Qinii + * @day 1/4/22 + */ + public function updatePlantJson(string $path, int $plant) + { + $fileUrl = $path . "/download/common/vendor.js"; + $string = file_get_contents($fileUrl); //加载配置文件 + $string = str_replace('"-openPlantGrass-"', $plant ? 'true' : 'false', $string); // 正则查找然后替换 + $newFileUrl = $path . "/download/common/vendor.js"; + @file_put_contents($newFileUrl, $string); // 写入配置文件 + } +} diff --git a/app/common/repositories/system/config/ConfigValueRepository.php b/app/common/repositories/system/config/ConfigValueRepository.php new file mode 100644 index 00000000..f4c45602 --- /dev/null +++ b/app/common/repositories/system/config/ConfigValueRepository.php @@ -0,0 +1,165 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\config; + + +use app\common\dao\system\config\SystemConfigValueDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\groupData\GroupRepository; +use crmeb\jobs\SyncProductTopJob; +use crmeb\services\DownloadImageService; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; + +/** + * Class ConfigValueRepository + * @package app\common\repositories\system\config + * @mixin SystemConfigValueDao + */ +class ConfigValueRepository extends BaseRepository +{ + + /** + * ConfigValueRepository constructor. + * @param SystemConfigValueDao $dao + */ + public function __construct(SystemConfigValueDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $keys + * @param int $merId + * @return array + * @author xaboy + * @day 2020-03-27 + */ + public function more(array $keys, int $merId): array + { + $config = $this->dao->fields($keys, $merId); + foreach ($keys as $key) { + if (!isset($config[$key])) $config[$key] = ''; + } + return $config; + } + + /** + * @param string $key + * @param int $merId + * @return mixed|string|null + * @author xaboy + * @day 2020-05-08 + */ + public function get(string $key, int $merId) + { + $value = $this->dao->value($key, $merId); + return $value ?? ''; + } + + /** + * @param int|array $cid + * @param array $formData + * @param int $merId + * @author xaboy + * @day 2020-03-27 + */ + public function save($cid, array $formData, int $merId) + { + $keys = array_keys($formData); + $keys = app()->make(ConfigRepository::class)->intersectionKey($cid, $keys); + if (!count($keys)) return; + foreach ($keys as $key => $info) { + if (!isset($formData[$key])) + unset($formData[$key]); + else { + if ($info['config_type'] == 'number') { + if ($formData[$key] === '' || $formData[$key] < 0) + throw new ValidateException($info['config_name'] . '不能小于0'); + $formData[$key] = floatval($formData[$key]); + } + $this->separate($key,$formData[$key],$merId); + } + } + $this->setFormData($formData, $merId); + } + + /** + * TODO 需要做特殊处理的配置参数 + * @param $key + * @author Qinii + * @day 2022/11/17 + */ + public function separate($key,$value,$merId) + { + switch($key) { + case 'mer_svip_status': + //修改商户的会员状态 + app()->make(ProductRepository::class)->getSearch([])->where(['mer_id' => $merId,'product_type' => 0])->update([$key => $value]); + break; +// case 'site_ico': +// //修改ico图标 +// $stie_ico = systemConfig('site_ico'); +// $ico = substr($value,-3); +// if ($stie_ico != $value && $ico != 'ico') { +// $path = app()->make(DownloadImageService::class)->downloadImage($value,'def','favicon.ico',1)['path']; +// $value = public_path().$path; +// if (!is_file($value)) throw new ValidateException('Ico图标文件不存在'); +// rename($value, public_path() . 'favicon.ico'); +// } +// break; + //热卖排行 + case 'hot_ranking_switch': + if ($value) { + Queue::push(SyncProductTopJob::class, []); + } + break; + case 'svip_switch_status': + if ($value == 1) { + $groupDataRepository = app()->make(GroupDataRepository::class); + $groupRepository = app()->make(GroupRepository::class); + $group_id = $groupRepository->getSearch(['group_key' => 'svip_pay'])->value('group_id'); + $where['group_id'] = $group_id; + $where['status'] = 1; + $count = $groupDataRepository->getSearch($where)->field('group_data_id,value,sort,status')->count(); + if (!$count) + throw new ValidateException('请先添加会员类型'); + } + break; + default: + break; + } + return ; + } + + public function setFormData(array $formData, int $merId) + { + Db::transaction(function () use ($merId, $formData) { + foreach ($formData as $key => $value) { + if ($this->dao->merExists($key, $merId)) + $this->dao->merUpdate($merId, $key, ['value' => $value]); + else + $this->dao->create([ + 'mer_id' => $merId, + 'value' => $value, + 'config_key' => $key + ]); + } + }); + } + +} diff --git a/app/common/repositories/system/diy/DiyRepository.php b/app/common/repositories/system/diy/DiyRepository.php new file mode 100644 index 00000000..61263185 --- /dev/null +++ b/app/common/repositories/system/diy/DiyRepository.php @@ -0,0 +1,253 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\diy; + +use app\common\dao\system\diy\DiyDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class DiyRepository extends BaseRepository +{ + const IS_DEFAULT_DIY = 'is_default_diy'; + + public function __construct(DiyDao $dao) + { + $this->dao = $dao; + } + + public function getThemeVar($type) + { + $var = [ + 'purple' => [ + 'type' => 'purple', + 'theme_color' => '#905EFF', + 'assist_color' => '#FDA900', + 'theme' => '--view-theme: #905EFF;--view-assist:#FDA900;--view-priceColor:#FDA900;--view-bgColor:rgba(253, 169, 0,.1);--view-minorColor:rgba(144, 94, 255,.1);--view-bntColor11:#FFC552;--view-bntColor12:#FDB000;--view-bntColor21:#905EFF;--view-bntColor22:#A764FF;' + ], + 'orange' => [ + 'type' => 'orange', + 'theme_color' => '#FF5C2D', + 'assist_color' => '#FDB000', + 'theme' => '--view-theme: #FF5C2D;--view-assist:#FDB000;--view-priceColor:#FF5C2D;--view-bgColor:rgba(253, 176, 0,.1);--view-minorColor:rgba(255, 92, 45,.1);--view-bntColor11:#FDBA00;--view-bntColor12:#FFAA00;--view-bntColor21:#FF5C2D;--view-bntColor22:#FF9445;' + ], + 'pink' => [ + 'type' => 'pink', + 'theme_color' => '#FF448F', + 'assist_color' => '#FDB000', + 'theme' => '--view-theme: #FF448F;--view-assist:#FDB000;--view-priceColor:#FF448F;--view-bgColor:rgba(254, 172, 65,.1);--view-minorColor:rgba(255, 68, 143,.1);--view-bntColor11:#FDBA00;--view-bntColor12:#FFAA00;--view-bntColor21:#FF67AD;--view-bntColor22:#FF448F;' + ], + 'default' => [ + 'type' => 'default', + 'theme_color' => '#E93323', + 'assist_color' => '#FF7612', + 'theme' => '--view-theme: #E93323;--view-assist:#FF7612;--view-priceColor:#E93323;--view-bgColor:rgba(255, 118, 18,.1);--view-minorColor:rgba(233, 51, 35,.1);--view-bntColor11:#FEA10F;--view-bntColor12:#FA8013;--view-bntColor21:#FA6514;--view-bntColor22:#E93323;' + ], + 'green' => [ + 'type' => 'green', + 'theme_color' => '#42CA4D', + 'assist_color' => '#FE960F', + 'theme' => '--view-theme: #42CA4D;--view-assist:#FE960F;--view-priceColor:#FE960F;--view-bgColor:rgba(254, 150, 15,.1);--view-minorColor:rgba(66, 202, 77,.1);--view-bntColor11:#FDBA00;--view-bntColor12:#FFAA00;--view-bntColor21:#42CA4D;--view-bntColor22:#70E038;' + ], + 'blue' => [ + 'type' => 'blue', + 'theme_color' => '#1DB0FC', + 'assist_color' => '#FFB200', + 'theme' => '--view-theme: #1DB0FC;--view-assist:#FFB200;--view-priceColor:#FFB200;--view-bgColor:rgba(255, 178, 0,.1);--view-minorColor:rgba(29, 176, 252,.1);--view-bntColor11:#FFD652;--view-bntColor12:#FEB60F;--view-bntColor21:#40D1F4;--view-bntColor22:#1DB0FC;' + ], + ]; + return $var[$type] ?? $var['default']; + } + + /** + * 获取DIY列表 + * @param array $where + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getSysList(array $where,int $page, int $limit) + { + $field = 'is_diy,template_name,id,title,name,type,add_time,update_time,status,is_default'; + $where['is_del'] = 0; + $query = $this->dao->getSearch($where)->order('is_default DESC, status DESC, update_time DESC,add_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[])->field($field)->select() + ->each(function($item) use($where){ + + if ($item['is_default']) { + $id = merchantConfig($where['mer_id'], self::IS_DEFAULT_DIY) ?: 0; + $item['status'] = ($id == $item['id']) ? 1 : 0; + return $item; + } + }); + return compact('count','list'); + } + + /** + * 保存资源 + * @param int $id + * @param array $data + * @return int + */ + public function saveData(int $id = 0, array $data) + { + if ($id) { + if ($data['type'] === '') { + unset($data['type']); + } + $data['update_time'] = date('Y-m-d H:i:s',time()); + $this->dao->update($id, $data); + } else { + $data['add_time'] = date('Y-m-d H:i:s',time()); + $data['update_time'] = date('Y-m-d H:i:s',time()); + $res = $this->dao->create($data); + if (!$res) throw new ValidateException('保存失败'); + $id = $res->id; + } + return $id; + } + + /** + * 删除DIY模板 + * @param int $id + */ + public function del(int $id, $merId) + { + $count = $this->dao->getWhere(['id' => $id,'mer_id' => $merId]); + if ($count['is_default']) throw new ValidateException('默认模板无法删除'); + if ($count['status']) throw new ValidateException('该模板使用中,无法删除'); + $res = $this->dao->update($id, ['is_del' => 1]); + if (!$res) throw new ValidateException('删除失败,请稍后再试'); + } + + + /** + * 获取diy详细数据 + * @param int $id + * @return array|object + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getDiyInfo($id, $merId,$is_diy = 1) + { + if ($merId) { + $merchant = app()->make(MerchantRepository::class)->get($merId); + if (!$merchant) throw new ValidateException('店铺已关闭'); + if (!$merchant['mer_state']) throw new ValidateException('店铺已打烊'); + } + $field = 'title,value'; + if ($id) { + $diyInfo = $this->dao->getWhere([$this->dao->getPk() => $id,'is_del' => 0], $field); + if (!$diyInfo && !$is_diy) throw new ValidateException('页面不存在'); + } else { + $id = merchantConfig($merId, self::IS_DEFAULT_DIY) ?: 0; + $diyInfo = $this->dao->getWhere(['id' => $id,'is_del' => 0]); + if (!$diyInfo) { + $where = ['is_default' => $merId ? 2 : 1,]; + $diyInfo = $this->dao->getWhere($where,$field); + } + } + if ($diyInfo) { + $diyInfo = $diyInfo->toArray(); + $diyInfo['value'] = json_decode($diyInfo['value'], true); + return $diyInfo; + } else { + return []; + } + } + + /** + * 获取底部导航 + * @param string $template_name + * @return array|mixed + */ + public function getNavigation() + { + $id = merchantConfig(0, self::IS_DEFAULT_DIY); + $diyInfo = $this->dao->getWhere(['id' => $id,'is_del' => 0],'value'); + if (!$diyInfo) { + $where = ['is_default' => 1,]; + $diyInfo = $this->dao->getWhere($where,'value'); + } + $navigation = []; + if ($diyInfo) { + $value = json_decode($diyInfo['value'], true); + foreach ($value as $item) { + if (isset($item['name']) && strtolower($item['name']) === 'pagefoot') { + $navigation = $item; + break; + } + } + } + return $navigation; + } + + public function copy($id, $merId) + { + $data = $this->dao->getWhere([$this->dao->getPk() => $id]); + + if (!$data) throw new ValidateException('数据不存在'); + if ($merId){ + if ($data['mer_id'] != $merId && $data['is_default'] != 2) { + throw new ValidateException('模板不属于你'); + } + } else { + if ($data['mer_id'] != $merId && $data['is_default'] != 1) { + throw new ValidateException('模板不属于你'); + } + } + $data = $data->toArray(); + $data['name'] = $data['name'].'-copy'; + $data['add_time'] = date('Y-m-d H:i:s',time()); + $data['update_time'] = date('Y-m-d H:i:s',time()); + $data['status'] = 0; + $data['is_default'] = 0; + $data['mer_id'] = $merId; + unset($data[$this->dao->getPk()]); + $res = $this->dao->create($data); + $id = $res[$this->dao->getPk()]; + return compact('id'); + } + + public function setUsed(int $id, int $merId) + { + $diyInfo = $this->dao->getWhere(['id' => $id,'is_del' => 0]); + if (!$diyInfo) throw new ValidateException('模板不存在'); + + if ($merId){ + if ($diyInfo['mer_id'] != $merId && $diyInfo['is_default'] != 2) { + throw new ValidateException('模板不属于你'); + } + } else { + if ($diyInfo['mer_id'] != $merId && $diyInfo['is_default'] != 1) { + throw new ValidateException('模板不属于你'); + } + } + return Db::transaction(function () use($id, $merId){ + $make = app()->make(ConfigValueRepository::class); + $this->dao->setUsed($id, $merId); + $make->setFormData([self::IS_DEFAULT_DIY => $id ], $merId); + return ; + }); + } + public function getOptions(array $where) + { + return $this->dao->getSearch($where)->field('name label, id value')->select(); + } +} diff --git a/app/common/repositories/system/diy/PageCategoryRepository.php b/app/common/repositories/system/diy/PageCategoryRepository.php new file mode 100644 index 00000000..8dff8fad --- /dev/null +++ b/app/common/repositories/system/diy/PageCategoryRepository.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\diy; + +use app\common\dao\system\diy\PageCategoryDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class PageCategoryRepository extends BaseRepository +{ + public function __construct(PageCategoryDao $dao) + { + $this->dao = $dao; + } + + public function getFormatList($where) + { + return formatCategory($this->dao->getSearch($where)->order('add_time DESC')->select()->toArray(), $this->dao->getPk()); + } + + public function getList(array $where, int $page, int $limit) + { + + $query = $this->dao->getSearch($where)->order('add_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + public function form(?int $id, int $isMer = 0) + { + if ($id) { + $formData = $this->dao->get($id)->toArray(); + if ($formData['type'] != 'link') throw new ValidateException('此类型不能修改'); + $form = Elm::createForm(Route::buildUrl($isMer ? 'systemDiyPageMerCategroyUpdate' : 'systemDiyPageCategroyUpdate', ['id' => $id])->build()); + $isMer = $formData['is_mer']; + } else { + $form = Elm::createForm(Route::buildUrl($isMer ? 'systemDiyPageMerCategroyCreate' : 'systemDiyPageCategroyCreate')->build()); + $formData = []; + } + + $form->setRule([ + Elm::cascader('pid', '上级分类')->options(function () use($isMer) { + $options = $this->dao->getSearch(['status' => 1,'is_mer' => $isMer,'type' => 'link'])->where('level','<',3)->column('pid,name','id'); + $options = formatCascaderData($options, 'name'); + return $options; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]])->filterable(true)->appendValidate(Elm::validateInt()->required()->message('请选择上级分类')), + Elm::input('name', '分类名称')->required(), + Elm::hidden('type','类型','link'), + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::hidden('is_mer',$isMer), + ]); + return $form->setTitle(is_null($id) ? '添加' . ($isMer ? '商户分类' : '平台分类') : '编辑' . ($isMer ? '商户分类' : '平台分类'))->formData($formData); + } + + public function getSonCategoryList($type,$pid = 0) + { + $where['pid'] = $pid; + $where['is_mer'] = $type; + $list = $this->dao->getSearch($where)->where('level','<',3) + ->field( 'id,pid,type,name label')->select(); + $arr = []; + if ($list) { + foreach ($list as $item) { + $item['title'] = $item['label']; + $item['expand'] = true; + $item['children'] = $this->getSonCategoryList($type,$item['id']); + $arr [] = $item; + } + } + return $arr; + } + +} diff --git a/app/common/repositories/system/diy/PageLinkRepository.php b/app/common/repositories/system/diy/PageLinkRepository.php new file mode 100644 index 00000000..9e29af83 --- /dev/null +++ b/app/common/repositories/system/diy/PageLinkRepository.php @@ -0,0 +1,86 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\diy; + +use app\common\dao\system\diy\PageLinkDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class PageLinkRepository extends BaseRepository +{ + public function __construct(PageLinkDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with(['category'])->order('add_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + public function form(?int $id, $isMer) + { + if ($id) { + $formData = $this->dao->get($id)->toArray(); + + $form = Elm::createForm(Route::buildUrl($isMer ? 'systemDiyPageLinkMerUpdate' : 'systemDiyPageLinkUpdate', ['id' => $id])->build()); + } else { + $form = Elm::createForm(Route::buildUrl($isMer ? 'systemDiyPageLinkMerCreate': 'systemDiyPageLinkCreate')->build()); + $formData = []; + } + + $rule = [ + Elm::cascader('cate_id', '上级分类')->options(function () use($isMer) { + $options = app()->make(PageCategoryRepository::class)->getSearch(['status' => 1,'is_mer' => $isMer,'type' => 'link','level' => 3])->column('id value, name label'); + return $options; + + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]) + ->filterable(true) + ->appendValidate(Elm::validateInt()->required()->message('请选择上级分类')), + Elm::input('name', '页面名称')->required(), + Elm::input('url', '页面链接')->required(), + Elm::text('param', '参数'), + + Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]; + + $form->setRule($rule); + return $form->setTitle(is_null($id) ? '添加分类' : '编辑分类')->formData($formData); + } + + /** + * TODO 分类下的链接列表 + * @param int $pid + * @param int $merId + * @return mixed + * @author Qinii + * @day 3/24/22 + */ + public function getLinkList(int $pid,int $merId) + { + $where['pid'] = $pid; + $where['is_mer'] = $merId ? 1 : 0; + $make = app()->make(PageCategoryRepository::class); + $list = $make->getSearch($where)->with([ + 'pageLink', + ])->select(); + return $list; + } +} diff --git a/app/common/repositories/system/financial/FinancialRepository.php b/app/common/repositories/system/financial/FinancialRepository.php new file mode 100644 index 00000000..04148751 --- /dev/null +++ b/app/common/repositories/system/financial/FinancialRepository.php @@ -0,0 +1,689 @@ + +// +---------------------------------------------------------------------- +namespace app\common\repositories\system\financial; + + +use app\common\dao\system\financial\FinancialDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\common\repositories\user\UserBillRepository; +use crmeb\jobs\ChangeMerchantStatusJob; +use crmeb\jobs\SendSmsJob; +use crmeb\services\WechatService; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +class FinancialRepository extends BaseRepository +{ + public function __construct(FinancialDao $dao) + { + $this->dao = $dao; + } + + public function financialAccountForm($id) + { + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $id])->find(); + + $form = Elm::createForm(Route::buildUrl('merchantFinancialAccountSave',['id' => $id])->build()); + $form->setRule([ + Elm::radio('financial_type', '转账类型', $merchant->financial_type) + ->setOptions([ + ['value' => 1, 'label' => '银行卡'], + ['value' => 2, 'label' => '微信'], + ['value' => 3, 'label' => '支付宝'], + ])->control([ + [ + 'value' => 1, + 'rule'=> [ + Elm::input('name', '姓名')->value($merchant->financial_bank->name??'')->required(), + Elm::input('bank', '开户银行')->value($merchant->financial_bank->bank??'')->required(), + Elm::input('bank_code', '银行卡号')->value($merchant->financial_bank->bank_code??'')->required(), + ] + ], + [ + 'value' => 2, + 'rule'=> [ + Elm::input('name', '姓名')->value($merchant->financial_wechat->name??'')->required(), + Elm::input('wechat', '微信号')->value($merchant->financial_wechat->wechat??'')->required(), + Elm::frameImage('wechat_code', '收款二维码', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=wechat_code&type=1')->value($merchant->financial_wechat->wechat_code??'')->modal(['modal' => false])->width('896px')->height('480px'), + ] + ], + [ + 'value' => 3, + 'rule'=> [ + Elm::input('name', '姓名')->value($merchant->financial_alipay->name??'')->required(), + Elm::input('alipay', '支付宝账号')->value($merchant->financial_alipay->alipay??'')->required(), + Elm::frameImage('alipay_code', '收款二维码', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=alipay_code&type=1')->value($merchant->financial_alipay->alipay_code??'')->modal(['modal' => false])->width('896px')->height('480px'), + ] + ], + + ]), + ]); + return $form->setTitle('转账信息'); + } + + /** + * TODO 保存转账信息 + * @param int $merId + * @param array $data + * @author Qinii + * @day 3/18/21 + */ + public function saveAccount(int $merId,array $data) + { + switch ($data['financial_type']) + { + case 1: + $key = 'financial_bank' ; + $update = [ + 'name' => $data['name'], + 'bank' => $data['bank'], + 'bank_code' => $data['bank_code'], + ]; + break; + case 2: + $key = 'financial_wechat' ; + $update = [ + 'name' => $data['name'], + //'idcard' => $data['idcard'], + 'wechat' => $data['wechat'], + 'wechat_code' => $data['wechat_code'], + ]; + break; + case 3: + $key = 'financial_alipay' ; + $update = [ + 'name' => $data['name'], + //'idcard' => $data['idcard'], + 'alipay' => $data['alipay'], + 'alipay_code' => $data['alipay_code'], + ]; + break; + } + return app()->make(MerchantRepository::class)->update($merId,[$key => json_encode($update),'financial_type' => $data['financial_type']]); + } + + public function applyForm(int $merId) + { + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $merId])->field('mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay,financial_type')->find(); + $extract_minimum_line = systemConfig('extract_minimum_line') ?: 0; + $extract_minimum_num = systemConfig('extract_minimum_num'); + $_line = bcsub($merchant->mer_money,$extract_minimum_line,2); + $_extract = ($_line < 0) ? 0 : $_line; + $form = Elm::createForm(Route::buildUrl('merchantFinancialCreateSave')->build()); + $form->setRule([ + [ + 'type' => 'span', + 'title' => '商户名称:', + 'native' => false, + 'children' => ["$merchant->mer_name"] + ], + [ + 'type' => 'span', + 'title' => '商户ID:', + 'native' => false, + 'children' => ["$merId"] + ], +// [ +// 'type' => 'span', +// 'title' => '', +// 'children' => [] +// ], + [ + 'type' => 'span', + 'title' => '提示:', + 'native' => false, + 'children' => ['最低可提现额度:'.$extract_minimum_line.'元;最低提现金额:'.$extract_minimum_num.'元'] + ], + [ + 'type' => 'span', + 'title' => '商户余额:', + 'native' => false, + 'children' => ["$merchant->mer_money"] + ], + [ + 'type' => 'span', + 'native' => false, + 'title' => '商户可提现金额:', + 'children' => ["$_extract"] + ], + + Elm::radio('financial_type', '转账类型:', $merchant->financial_type) + ->setOptions([ + ['value' => 1, 'label' => '银行卡'], + ['value' => 2, 'label' => '微信'], + ['value' => 3, 'label' => '支付宝'], + ])->control([ + [ + 'value' => 1, + 'rule'=> [ + [ + 'type' => 'span', + 'title' => '姓名', + 'native' => false, + 'children' => [$merchant->financial_bank->name??'未填写'] + ], + [ + 'type' => 'span', + 'title' => '开户银行', + 'native' => false, + 'children' => [$merchant->financial_bank->bank??'未填写'] + ], + [ + 'type' => 'span', + 'title' => '银行卡号', + 'native' => false, + 'children' => [$merchant->financial_bank->bank_code??'未填写'] + ], + ] + ], + [ + 'value' => 2, + 'rule'=> [ + [ + 'type' => 'span', + 'title' => '姓名', + 'native' => false, + 'children' => [$merchant->financial_wechat->name??'未填写'] + ], + [ + 'type' => 'span', + 'title' => '微信号', + 'native' => false, + 'children' => [$merchant->financial_wechat->wechat??'未填写'] + ], + [ + 'type' => 'img', + 'title' => '收款二维码', + 'native' => false, + 'attrs' => ['src' => $merchant->financial_wechat->wechat_code ?? ''], + 'style' => ['width' => '86px','height' => '48px'] + ], + ] + ], + [ + 'value' => 3, + 'rule'=> [ + [ + 'type' => 'span', + 'title' => '姓名', + 'native' => false, + 'children' => [$merchant->financial_alipay->name??'未填写'] + ], + [ + 'type' => 'span', + 'title' => '支付宝账号', + 'native' => false, + 'children' => [$merchant->financial_alipay->alipay??'未填写'] + ], + [ + 'type' => 'img', + 'title' => '收款二维码', + 'native' => false, + 'attrs' => ['src' => $merchant->financial_alipay->alipay_code ?? ''], + 'style' => ['width' => '86px','height' => '48px'] + ], + ] + ], + + ]), + Elm::number('extract_money', '申请金额:')->value($extract_minimum_num)->required(), + ]); + return $form->setTitle('申请转账'); + } + + /** + * TODO 保存申请 + * @param int $merId + * @param array $data + * @author Qinii + * @day 3/19/21 + */ + public function saveApply(int $merId,array $data) + { + $make = app()->make(MerchantRepository::class); + $merchant = $make->search(['mer_id' => $merId])->field('mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay')->find(); + + if($merchant['mer_money'] <= 0) throw new ValidateException('余额不足'); + + if($data['financial_type'] == 1){ + $financial_account = $merchant->financial_bank; + }elseif ($data['financial_type'] == 2){ + $financial_account = $merchant->financial_wechat; + }elseif ($data['financial_type'] == 3){ + $financial_account = $merchant->financial_alipay; + } + if(empty($financial_account)) throw new ValidateException('未填写银行转账信息'); + + $extract_maxmum_num = systemConfig('extract_maxmum_num'); + if($extract_maxmum_num > 0 && $data['extract_money'] > $extract_maxmum_num) throw new ValidateException('单次申请金额不得大于'.$extract_maxmum_num.'元'); + //最低提现额度 + $extract_minimum_line = systemConfig('extract_minimum_line') ? systemConfig('extract_minimum_line') : 0; + $_line = bcsub($merchant->mer_money,$extract_minimum_line,2); + if($_line < $extract_minimum_line) throw new ValidateException('余额大于'.$extract_minimum_line.'才可提现'); + if($data['extract_money'] > $_line) throw new ValidateException('提现金额大于可提现金额'); + + //最低提现金额 + $extract_minimum_num = systemConfig('extract_minimum_num'); + if($data['extract_money'] < $extract_minimum_num) throw new ValidateException('最低提现金额'.$extract_minimum_num); + + //可提现金额 + $_line = bcsub($merchant->mer_money,$extract_minimum_line,2); + if($_line < 0) throw new ValidateException('余额大于'.$extract_minimum_line.'才可提现'); + + //最低提现金额 + if($data['extract_money'] < $extract_minimum_num) throw new ValidateException('最低提现金额'.$extract_minimum_num); + + //不足提现最低金额 + if($_line < $extract_minimum_num) throw new ValidateException('提现金额不足'); + + $_money = bcsub($merchant['mer_money'],$data['extract_money'],2); + + $sn = date('YmdHis'.$merId); + $ret = [ + 'status' => 0, + 'mer_id' => $merId, + 'mer_money' => $_money, + 'financial_sn' => $sn, + 'extract_money' => $data['extract_money'], + 'financial_type' => $data['financial_type'], + 'financial_account' => json_encode($financial_account,JSON_UNESCAPED_UNICODE), + 'financial_status' => 0, + 'mer_admin_id' => $data['mer_admin_id'], + 'mark' => $datap['mark']??'', + 'refusal' => '', + ]; + Db::transaction(function()use($merId,$ret,$data,$make){ + $this->dao->create($ret); + $make->subMoney($merId,(float)$data['extract_money']); + }); + } + + + public function refundMargin($merId, $adminId) + { + $res = app()->make(MerchantRepository::class)->get($merId); + if ($res['is_margin'] == -1) throw new ValidateException('请勿重复申请'); + + if (!in_array($res['is_margin'],[10,-10]) || $res['margin'] <= 0) + throw new ValidateException('无可退保证金'); + + $order = app()->make(ServeOrderRepository::class)->getWhere([ + 'mer_id' => $res['mer_id'], + 'status' => 1, + 'type' => 10, + ]); + if (!$order) throw new ValidateException('未查询到支付订单'); + $financial_account = [ + 'name' => '保证金退款', + 'order_id' => $order['order_id'], + 'order_sn' => $order['order_sn'], + 'pay_price'=> $order['pay_price'], + 'pay_type' => 1, + 'ot_margin'=> $res->ot_margin + ]; + $sn = 'mm'.date('YmdHis'.$merId); + + $ret = [ + 'status' => 0, + 'mer_id' => $merId, + 'mer_money' => 0, + 'financial_sn' => $sn, + 'extract_money' => $res['margin'], + 'financial_type' => 1, + 'financial_account' => json_encode($financial_account,JSON_UNESCAPED_UNICODE), + 'financial_status' => 0, + 'mer_admin_id' => $adminId, + 'mark' => '', + 'type' => 1 + ]; + + return Db::transaction(function()use($ret,$res){ + $this->dao->create($ret); +// $res->margin = 0; + $res->is_margin = -1; + $res->save(); + }); + } + + + /** + * TODO 商户列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 3/19/21 + */ + public function getAdminList(array $where,int $page,int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->search($where)->with([ + 'merchant' => function($query){ + $query->field('mer_id,mer_name,is_trader,mer_avatar,type_id,mer_phone,mer_address,is_margin,margin,real_name'); + $query->with([ + 'merchantType', + 'marginOrder' => function($query){ + $query->field('order_id,order_sn,pay_price')->where('status',10); + } + ]); + } + ]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + + return compact('count','list'); + } + + + /** + * TODO 取消/拒绝 变更状态返还余额 + * @param $merId + * @param $id + * @param $data + * @author Qinii + * @day 3/19/21 + */ + public function cancel(?int $merId,int $id,array $data) + { + $where = [ + 'financial_id' => $id, + 'is_del' => 0, + 'status' => 0 + ]; + if($merId) $where['mer_id'] = $merId; + $res = $this->dao->getWhere($where); + if(!$res) throw new ValidateException('数据不存在'); + if($res['financial_status'] == 1) throw new ValidateException('当前状态无法完成此操作'); + $merId = $merId?? $res['mer_id']; + Db::transaction(function()use($merId,$res,$id,$data) { + $this->dao->update($id,$data); + app()->make(MerchantRepository::class)->addMoney($merId, (float)$res['extract_money']); + }); + } + + /** + * TODO + * @param $id + * @return \FormBuilder\Form + * @author Qinii + * @day 4/21/21 + */ + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('merchantFinancialMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('mark', '备注', $data['mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + /** + * TODO + * @param $id + * @return \FormBuilder\Form + * @author Qinii + * @day 4/21/21 + */ + public function adminMarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemFinancialMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('admin_mark', '备注', $data['admin_mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + public function adminMarginMarkForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMarginRefundMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('admin_mark', '备注', $data['admin_mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + public function statusForm($id) + { + $data = $this->dao->get($id); + if (!$data['merchant']->marginOrder) throw new ValidateException('未查询到缴费记录'); + if ($data['status'] !== 0) throw new ValidateException('请勿重复审核'); + $form = Elm::createForm(Route::buildUrl('systemMarginRefundSwitchStatus', ['id' => $id])->build()); + $form->setRule([ + Elm::input('mer_name','商户名称', $data['merchant']->mer_name)->disabled(true), + Elm::input('mer_id','商户ID', $data['mer_id'])->disabled(true), + Elm::input('type_name','店铺类型', $data['merchant']->merchantType->type_name)->disabled(true), + Elm::input('pay_price','保证金额度', $data['merchant']->marginOrder->pay_price)->disabled(true), + Elm::input('sub','扣费金额', bcsub($data['merchant']->marginOrder->pay_price, $data['extract_money'], 2))->disabled(true), + Elm::input('refund','退回金额', $data['extract_money'])->disabled(true), + Elm::radio('status', '审核', -1)->setOptions([ + ['value' => 1, 'label' => '同意'], + ['value' => -1, 'label' => '拒绝'], + ])->control([ + [ + 'value' => -1, + 'rule' => [ + Elm::input('refusal', '拒绝原因')->required() + ] + ],]) + ]); + return $form->setTitle('退保证金审核'); + } + + /** + * TODO 详情 + * @param $id + * @return array|\think\Model|null + * @author Qinii + * @day 4/22/21 + */ + public function detail($id,$merId=0) + { + $where[$this->dao->getPk()] = $id; + if($merId) $where['mer_id'] = $merId; + $data = $this->dao->getSearch($where)->with(['merchant' => function($query){ + $query->field('mer_id,mer_name,mer_avatar'); + }])->find(); + if(!$data) throw new ValidateException('数据不存在'); + return $data; + } + + /** + * TODO 头部统计 + * @return array + * @author Qinii + * @day 4/22/21 + */ + public function getTitle() + { + $make = app()->make(MerchantRepository::class); + //应付商户金额 = 所有商户的余额之和 + $all = $make->search(['is_del' => 0])->sum('mer_money'); + //商户可提现金额 = (每个商户的余额 - 平台设置的最低提现额度) 之和 + $extract_minimum_line = systemConfig('extract_minimum_line') ?: 0; + $ret = $make->search(['is_del' => 0])->where('mer_money','>',$extract_minimum_line) + ->field("sum(mer_money - $extract_minimum_line) as money") + ->find(); + $money = $ret->money; + //申请转账的商户数 = 申请提现且未转账的商户数量 + $where = [ + "financial_status" => 0 + ]; + $query = $this->dao->getSearch($where)->where('status','>',-1); + $count = $query->group('mer_id')->count(); + //申请转账的总金额 = 申请提现已通过审核,且未转账的申请金额 之和 + $where['status'] = 1; + $all_ = $this->dao->getSearch($where)->sum('extract_money'); + $where['status'] = 0; + $all_0 = $this->dao->getSearch($where)->sum('extract_money'); + $merLockMoney = app()->make(UserBillRepository::class)->merchantLickMoney(); + $stat = [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $all, + 'field' => '元', + 'name' => '应付商户金额' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $money, + 'field' => '元', + 'name' => '商户可提现金额' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $count, + 'field' => '个', + 'name' => '申请转账的商户数' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $all_, + 'field' => '元', + 'name' => '申请转账的总金额' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $all_0, + 'field' => '元', + 'name' => '待审核的总金额' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $merLockMoney, + 'field' => '元', + 'name' => '商户冻结金额' + ], + ]; + + return $stat; + } + + public function updateMargin($id, $data) + { + $where = [ + 'financial_id' => $id, + 'is_del' => 0, + 'status' => 0 + ]; + + $res = $this->dao->getWhere($where); + if(!$res) throw new ValidateException('数据不存在'); + if ($data['status'] == 1) { + + } else { + $this->dao->update($id, $data); + } + } + + public function switchStatus($id, $type, $data) + { + $where = [ + 'financial_id' => $id, + 'is_del' => 0, + 'status' => 0, + 'type' => $type + ]; + + $res = $this->dao->getWhere($where); + if(!$res) throw new ValidateException('数据不存在'); + + switch ($type) { + case 0: + if ($data['status'] == -1) $this->cancel(null,$id,$data); + break; + case 1: + if ($data['status'] == 1) { + $this->agree($res); + $data['financial_status'] = 1; + $tempId = 'REFUND_MARGIN_SUCCESS'; + }else if ($data['status'] == -1) { +// $res->merchant->margin = $res['extract_money']; + $res->merchant->is_margin = -10; + $res->merchant->save(); + $tempId = 'REFUND_MARGIN_FAIL'; + } + Queue::push(SendSmsJob::class, [ + 'tempId' => $tempId, + 'id' => [ + 'name' => $res->merchant->mer_name, + 'time' => $res->create_time, + 'phone' => $res->merchant->mer_phone + ]]); + break; + } + + return $this->dao->update($id, $data); + } + + public function refundShow($id) + { + $where = [ + 'financial_id' => $id, + 'type' => 1, + 'status'=> 1 + ]; + $res = $this->dao->getWhere($where, '*', ['merchant' => ['merchantType']]); + if (!$res) throw new ValidateException('数据不存在'); + return $res; + } + + /** + * TODO 同意退保证金 + * @param $res + * @author Qinii + * @day 1/27/22 + */ + public function agree($res) + { + //验证 + $comp = bccomp($res['financial_account']->pay_price, $res['extract_money'], 2); + if ($comp == -1) + throw new ValidateException('申请退款金额:'.$res['extract_money'].',大于支付保证金:'.$res['financial_account']->pay_price); + +// if (bccomp($res['merchant']['margin'], $res['extract_money'],2) == -1) +// throw new ValidateException('申请退款金额:'.$res['extract_money'].',大于剩余保证金:'.$res['merchant']['margin']); + + Db::transaction(function () use ($res){ + //退款 + $data = [ + 'refund_id' => $res['financial_account']->order_sn, + 'pay_price' => $res['financial_account']->pay_price, + 'refund_price' => $res['extract_money'] + ]; + WechatService::create()->payOrderRefund($res['financial_account']->order_sn, $data); + + //改订单 + $order = app()->make(ServeOrderRepository::class)->get($res['financial_account']->order_id); + $order->status = 20; + $order->save(); + + //关店 + $res->merchant->is_margin = $res['merchant']['merchantType']['is_margin']; + $res->merchant->margin = $res['merchant']['merchantType']['margin']; + if ($res['merchant']['merchantType']['is_margin'] == 1) { + $res->merchant->mer_state = 0; + Queue::push(ChangeMerchantStatusJob::class, $res['mer_id']); + } + $res->merchant->save(); + + }); + + } +} diff --git a/app/common/repositories/system/groupData/GroupDataRepository.php b/app/common/repositories/system/groupData/GroupDataRepository.php new file mode 100644 index 00000000..4805c142 --- /dev/null +++ b/app/common/repositories/system/groupData/GroupDataRepository.php @@ -0,0 +1,386 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\groupData; + + +use app\common\dao\BaseDao; +use app\common\dao\system\groupData\GroupDataDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductLabelRepository; +use app\common\repositories\store\StoreCategoryRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Route; +use think\Model; + +/** + * Class GroupDataRepository + * @package app\common\repositories\system\groupData + * @mixin GroupDataDao + * @author xaboy + * @day 2020-03-30 + */ +class GroupDataRepository extends BaseRepository +{ + + /** + * GroupDataRepository constructor. + * @param GroupDataDao $dao + */ + public function __construct(GroupDataDao $dao) + { + $this->dao = $dao; + } + + /** + * @param int $merId + * @param array $data + * @param array $fieldRule + * @return BaseDao|Model + * @author xaboy + * @day 2020-03-30 + */ + public function create(int $merId, array $data, array $fieldRule) + { + $this->checkData($data['value'], $fieldRule); + $data['mer_id'] = $merId; + return $this->dao->create($data); + } + + /** + * @param $merId + * @param $id + * @param $data + * @param $fieldRule + * @return int + * @throws DbException + * @author xaboy + * @day 2020/9/23 + */ + public function merUpdate($merId, $id, $data, $fieldRule) + { + $this->checkData($data['value'], $fieldRule); + return $this->dao->merUpdate($merId, $id, $data); + } + + /** + * @param array $data + * @param array $fieldRule + * @author xaboy + * @day 2020/9/23 + */ + public function checkData(array $data, array $fieldRule) + { + foreach ($fieldRule as $rule) { +// if (!isset($data[$rule['field']]) || $data[$rule['field']] === '') { +// throw new ValidateException($rule['name'] . '不能为空'); +// } + if ($rule['type'] === 'number' && $data[$rule['field']] < 0) + throw new ValidateException($rule['name'] . '不能小于0'); + } + } + + /** + * @param int $merId + * @param int $groupId + * @param int $page + * @param int $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-30 + */ + public function getGroupDataLst(int $merId, int $groupId, int $page, int $limit): array + { + $query = $this->dao->getGroupDataWhere($merId, $groupId)->order('group_data_id DESC'); + $count = $query->count(); + $list = $query->field('group_data_id,value,sort,status,create_time')->page($page, $limit)->select()->toArray(); + foreach ($list as $k => $data) { + $value = $data['value']; + unset($data['value']); + $data += $value; + $list[$k] = $data; + } + return compact('count', 'list'); + } + + /** + * @param int $groupId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-02 + */ + public function form(int $groupId, ?int $id = null, ?int $merId = null, array $formData = []): Form + { + $fields = app()->make(GroupRepository::class)->fields($groupId); + if (is_null($merId)) { + $url = is_null($id) + ? Route::buildUrl('groupDataCreate', compact('groupId'))->build() + : Route::buildUrl('groupDataUpdate', compact('groupId', 'id'))->build(); + } else { + $url = is_null($id) + ? Route::buildUrl('merchantGroupDataCreate', compact('groupId'))->build() + : Route::buildUrl('merchantGroupDataUpdate', compact('groupId', 'id'))->build(); + } + + $form = Elm::createForm($url); + $rules = []; + foreach ($fields as $field) { + $rule = null; + if ($field['type'] == 'image') { + $rule = Elm::frameImage($field['field'], $field['name'], '/' . config('admin.' . ($merId ? 'merchant' : 'admin') . '_prefix') . '/setting/uploadPicture?field=' . $field['field'] . '&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]); + } else if ($field['type'] == 'images') { + $rule = Elm::frameImage($field['field'], $field['name'], '/' . config('admin.' . ($merId ? 'merchant' : 'admin') . '_prefix') . '/setting/uploadPicture?field=' . $field['field'] . '&type=2')->maxLength(5)->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]); + } else if ($field['type'] == 'cate') { + $rule = Elm::cascader($field['field'], $field['name'])->options(function () use ($id) { + $storeCategoryRepository = app()->make(StoreCategoryRepository::class); + $menus = $storeCategoryRepository->getAllOptions(0, 1, null); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'cate_name'); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]])->filterable(true)->appendValidate(Elm::validateInt()->required()->message('请选择分类')); + } else if ($field['type'] == 'label') { + $rule = Elm::select($field['field'], $field['name'])->options(function () { + return app()->make(ProductLabelRepository::class)->getSearch(['mer_id' => request()->merId(), 'status' => 1])->column('label_name as label,product_label_id as value'); + })->appendValidate(Elm::validateNum()->required()->message('请选择标签')); + } else if (in_array($field['type'], ['select', 'checkbox', 'radio'])) { + $options = array_map(function ($val) { + [$value, $label] = explode(':', $val, 2); + return compact('value', 'label'); + }, explode("\n", $field['param'])); + $rule = Elm::{$field['type']}($field['field'], $field['name'])->options($options); + if ($field['type'] == 'select') { + $rule->filterable(true)->prop('allow-create', true); + } + } else if ($field['type'] == 'file') { + $rule = Elm::uploadFile($field['field'], $field['name'], rtrim(systemConfig('site_url'), '/') . Route::buildUrl('configUpload', ['field' => 'file'])->build())->headers(['X-Token' => request()->token()]); + } else { + $rule = Elm::{$field['type']}($field['field'], $field['name'], ''); + } + if ($field['props'] ?? '') { + $props = @parse_ini_string($field['props'], false, INI_SCANNER_TYPED); + if (is_array($props)) { + $rule->props($props); + if(isset($props['required']) && $props['required']){ + $rule->required(); + } + if (isset($props['defaultValue'])) { + $rule->value($props['defaultValue']); + } + } + } + $rules[] = $rule; + } + $rules[] = Elm::number('sort', '排序', 0)->precision(0)->max(99999); + $rules[] = Elm::switches('status', '是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'); + + $form->setRule($rules); + + return $form->setTitle(is_null($id) ? '添加数据' : '编辑数据')->formData(array_filter($formData, function ($item) { + return $item !== '' && !is_null($item); + })); + } + + /** + * @param int $groupId + * @param int $merId + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-02 + */ + public function updateForm(int $groupId, int $merId, int $id) + { + $data = $this->dao->getGroupDataWhere($merId, $groupId)->where('group_data_id', $id)->find()->toArray(); + $value = $data['value']; + unset($data['value']); + $data += $value; + return $this->form($groupId, $id, $merId, $data); + } + + /** + * @param string $key + * @param int $merId + * @param int|null $page + * @param int|null $limit + * @return array + * @author xaboy + * @day 2020/5/27 + */ + public function groupData(string $key, int $merId, ?int $page = null, ?int $limit = 10) + { + $make = app()->make(GroupRepository::class); + $groupId = $make->keyById($key); + if (!$groupId) return []; + return $this->dao->getGroupData($merId, $groupId, $page, $limit); + } + + /** + * @param string $key + * @param int $merId + * @param int|null $page + * @param int|null $limit + * @return int + * @author xaboy + * @day 2020/5/27 + */ + public function getGroupDataCount(string $key, int $merId) + { + /** @var GroupRepository $make */ + $make = app()->make(GroupRepository::class); + $groupId = $make->keyById($key); + if (!$groupId) 0; + return $this->dao->groupDataCount($merId, $groupId); + } + + /** + * @param int $id + * @param int $merId + * @return mixed|void + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/2 + */ + public function idByData(int $id, int $merId) + { + $data = $this->dao->merGet($id, $merId); + if (!$data) return; + return json_decode($data['value']); + } + + /** + * @param string $key + * @param int $merId + * @param int|null $page + * @param int|null $limit + * @return array + * @author xaboy + * @day 2020/6/3 + */ + public function groupDataId(string $key, int $merId, ?int $page = null, ?int $limit = 10) + { + $make = app()->make(GroupRepository::class); + $groupId = $make->keyById($key); + if (!$groupId) return []; + return $this->dao->getGroupDataId($merId, $groupId, $page, $limit); + } + + public function setGroupData(string $key, $merId, array $data) + { + $groupRepository = app()->make(GroupRepository::class); + $group = $groupRepository->getWhere(['group_key' => $key]); + $fields = array_column($groupRepository->fields($group->group_id), 'field'); + $insert = []; + foreach ($data as $item) { + unset($item['group_data_id'], $item['group_mer_id']); + $value = []; + foreach ($fields as $field) { + if (isset($item[$field])) { + $value[$field] = $item[$field]; + } + } + $insert[] = [ + 'value' => json_encode($value,JSON_UNESCAPED_UNICODE), + 'status' => 1, + 'sort' => 0, + 'group_id' => $group->group_id, + 'mer_id' => $merId, + ]; + } + + $this->dao->selectWhere(['group_id' => $group->group_id])->delete(); + if (count($insert)) { + $this->dao->insertAll($insert); + } + } + + public function reSetDataForm(int $groupId, ?int $id, ?int $merId) + { + $formData = []; + if (is_null($id)) { + $url = is_null($merId) + ? Route::buildUrl('groupDataCreate', compact('groupId'))->build() + : Route::buildUrl('merchantGroupDataCreate', compact('groupId'))->build(); + + } else { + $data = $this->dao->getSearch([])->find($id); + if (!$data) throw new ValidateException('数据不存在'); + $formData = $data->value; + $formData['status'] = $data->status; + $formData['sort'] = $data->sort; + $url = is_null($merId) + ? Route::buildUrl('systemUserSvipTypeUpdate', compact('groupId','id'))->build() + : Route::buildUrl('merchantGroupDataUpdate', compact('groupId','id'))->build(); + } + $form = Elm::createForm($url); + $rules = [ + Elm::input('svip_name', '会员名')->required(), + Elm::radio('svip_type', '会员类别', '2') + ->setOptions([ + ['value' => '1', 'label' => '试用期',], + ['value' => '2', 'label' => '有限期',], + ['value' => '3', 'label' => '永久期',], + ])->control([ + [ + 'value' => '1', + 'rule' => [ + Elm::number('svip_number', '有效期(天)')->required()->min(0), + ] + ], + [ + 'value' =>'2', + 'rule' => [ + Elm::number('svip_number', '有效期(天)')->required()->min(0), + ] + ], + [ + 'value' => '3', + 'rule' => [ + Elm::input('svip_number1', '有效期(天)','永久期')->disabled(true), + Elm::input('svip_number', '有效期(天)','永久期')->hiddenStatus(true), + ] + ], + ])->appendRule('suffix', [ + 'type' => 'div', + 'style' => ['color' => '#999999'], + 'domProps' => [ + 'innerHTML' =>'试用期每个用户只能购买一次,购买过付费会员之后将不在展示,不可购买', + ] + ]), + Elm::number('cost_price', '原价')->required(), + Elm::number('price', '优惠价')->required(), + Elm::number('sort', '排序'), + Elm::switches('status', '是否显示')->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]; + $form->setRule($rules); + if ($formData && $formData['svip_type'] == 3) $formData['svip_number'] = '永久期'; + return $form->setTitle(is_null($id) ? '添加' : '编辑')->formData($formData); + } +} diff --git a/app/common/repositories/system/groupData/GroupRepository.php b/app/common/repositories/system/groupData/GroupRepository.php new file mode 100644 index 00000000..d30f1dbe --- /dev/null +++ b/app/common/repositories/system/groupData/GroupRepository.php @@ -0,0 +1,214 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\groupData; + + +use app\common\dao\system\groupData\GroupDao; +use app\common\model\system\groupData\SystemGroup; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; +use think\Model; + +/** + * Class GroupRepository + * @package app\common\repositories\system\groupData + * @mixin GroupDao + * @author xaboy + * @day 2020-03-27 + */ +class GroupRepository extends BaseRepository +{ + + /** + * + */ + const TYPES = ['input' => '文本框', 'number' => '数字框', 'textarea' => '多行文本框', 'radio' => '单选框', 'checkbox' => '多选框', 'select' => '下拉框', 'file' => '文件上传', 'image' => '图片上传', 'images' => '多图上传', 'color' => '颜色选择框', 'label' => '标签', 'cate' => '平台分类']; + + + /** + * GroupRepository constructor. + * @param GroupDao $dao + */ + public function __construct(GroupDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $data + * @return SystemGroup|Model + * @author xaboy + * @day 2020-03-27 + */ + public function create(array $data) + { + $data['fields'] = $this->tidyFields($data['fields']); + return $this->dao->create($data); + } + + /** + * @param int $id + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function update(int $id, array $data) + { + + $data['fields'] = json_encode($this->tidyFields($data['fields'])); + return $this->dao->update($id, $data); + } + + /** + * @param array $fields + * @return array + * @author xaboy + * @day 2020-03-27 + */ + public function tidyFields(array $fields): array + { + if (!count($fields)) + throw new ValidateException('字段最少设置一个'); + + $data = []; + $fieldKey = []; + foreach ($fields as $field) { + if (!isset($field['type'])) + throw new ValidateException('字段类型不能为空'); + if (!isset($field['field'])) + throw new ValidateException('字段key不能为空'); + if (!isset($field['name'])) + throw new ValidateException('字段名称不能为空'); + if (in_array($field['field'], $fieldKey)) + throw new ValidateException('字段key不能重复'); + $fieldKey[] = $field['field']; + $data[] = [ + 'name' => $field['name'], + 'field' => $field['field'], + 'type' => $field['type'], + 'param' => $field['param'] ?? '', + 'props' => $field['props'] ?? '' + ]; + } + return $data; + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function form(?int $id = null, array $formData = []): Form + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('groupCreate')->build() : Route::buildUrl('groupUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::select('user_type', '后台类型', 0)->options([ + ['label' => '总后台配置', 'value' => 0], + ['label' => '商户后台配置', 'value' => 1], + ])->requiredNum(), + Elm::input('group_name', '组合数据名称')->required(), + Elm::input('group_key', '组合数据key')->required(), + Elm::input('group_info', '组合数据说明'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + Elm::group('fields', '字段')->rules([ + Elm::select('type', '类型')->required()->options(function () { + $options = []; + foreach (self::TYPES as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + }), + Elm::input('name', '字段名称'), + Elm::input('field', '字段key'), + Elm::textarea('param', '选择项'), + Elm::textarea('props', '配置'), + ]), + ]); + + return $form->setTitle(is_null($id) ? '添加组合数据' : '编辑组合数据')->formData($formData); + } + + /** + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-02 + */ + public function updateForm(int $id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } + + /** + * @param int $page + * @param int $limit + * @return array + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-01 + */ + public function page(int $page, int $limit) + { + $list = $this->dao->page($page, $limit)->hidden(['fields', 'sort'])->order('create_time DESC')->select(); + $count = $this->dao->count(); + return compact('count', 'list'); + } + + /** + * @param int $id + * @return array + * @author xaboy + * @day 2020-04-02 + */ + public function keys(int $id): array + { + return array_column($this->fields($id), 'field'); + } + + /** + * @param $id + * @author xaboy + * @day 2020-05-16 + */ + public function delete($id) + { + Db::transaction(function () use ($id) { + $this->delete($id); + + /** @var GroupDataRepository $make */ + $make = app()->make(GroupDataRepository::class); + $make->clearGroup($id); + }); + } + +} diff --git a/app/common/repositories/system/merchant/FinancialRecordRepository.php b/app/common/repositories/system/merchant/FinancialRecordRepository.php new file mode 100644 index 00000000..3b693f81 --- /dev/null +++ b/app/common/repositories/system/merchant/FinancialRecordRepository.php @@ -0,0 +1,639 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\merchant; + + +use app\common\dao\system\merchant\FinancialRecordDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRechargeRepository; +use think\facade\Cache; +use think\facade\Db; + +/** + * Class FinancialRecordRepository + * @package app\common\repositories\system\merchant + * @author xaboy + * @day 2020/8/5 + * @mixin FinancialRecordDao + */ +class FinancialRecordRepository extends BaseRepository +{ + public function __construct(FinancialRecordDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 5/7/21 + */ + public function getList(array $where,int $page,int $limit) + { + $query = $this->dao->search($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * TODO 流水头部计算 + * @param int|null $merId + * @param array $where + * @return array + * @author Qinii + * @day 5/7/21 + */ + public function getFiniancialTitle(?int $merId,array $where) + { + /** + * 平台支出 + * 商户的收入 order_true + 佣金 brokerage_one,brokerage_two + 手续费 refund_charge + 商户预售收入 presell_true + * + * 商户支出 + * 退回收入 refund_order + (佣金 brokerage_one,brokerage_two - 退回佣金 refund_brokerage_two,refund_brokerage_one ) + (手续费 order_charge + 预售手续费 presell_charge - 平台退给商户的手续费 refund_charge ) + */ + $where['is_mer'] = $merId; + if($merId){ + //商户收入 + $income = $this->dao->search($where)->where('financial_type','in',['order','mer_presell'])->sum('number'); + //商户支出 + $expend_ = $this->dao->search($where)->where('financial_type','in',['refund_order','brokerage_one','brokerage_two','order_charge','presell_charge'])->sum('number'); + $_expend = $this->dao->search($where)->where('financial_type','in',['refund_charge','refund_brokerage_two','refund_brokerage_one'])->sum('number'); + $expend = bcsub($expend_,$_expend,2); + $msg = '商户'; + }else{ + //平台收入 + $income = $this->dao->search($where)->where('financial_type','in',['order','order_presell','presell'])->sum('number'); + //平台支出 + $expend = $this->dao->search($where)->where('financial_type','in',['brokerage_one','brokerage_two','order_true','refund_charge','presell_true','order_platform_coupon','order_svip_coupon'])->sum('number'); + $msg = '平台'; + } + $data = [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $income, + 'field' => '元', + 'name' => $msg.'收入' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $expend, + 'field' => '元', + 'name' => $msg.'支出' + ], + ]; + return $data; + } + + /** + * TODO 平台头部统计 + * @param $where + * @return array + * @author Qinii + * @day 3/23/21 + */ + public function getAdminTitle($where) + { + //订单收入总金额 + $count = $this->dao->search($where)->where('financial_type','in',['order','order_presell','presell'])->sum('number'); + //退款支出金额 + $refund_order = $this->dao->search($where)->where('financial_type','refund_order')->sum('number'); + //佣金支出金额 + $brokerage_ = $this->dao->search($where)->where('financial_type','in',['brokerage_one','brokerage_two'])->sum('number'); + $_brokerage = $this->dao->search($where)->where('financial_type','in',['refund_brokerage_two','refund_brokerage_one'])->sum('number'); + $brokerage = bcsub($brokerage_,$_brokerage,2); + //平台手续费 + $charge_ = $this->dao->search($where)->where('financial_type','in',['order_charge','presell_charge'])->sum('number'); + $_charge = $this->dao->search($where)->where('financial_type','refund_charge')->sum('number'); + $charge = bcsub($charge_,$_charge,2); + //优惠券费用 ,'order_platform_coupon','order_svip_coupon' + $coupon = $this->dao->search($where)->where('financial_type','in',['order_platform_coupon','order_svip_coupon'])->sum('number'); + //充值金额 + $bill_where = [ + 'status' => 1, + 'date' => $where['date'], + 'category' => 'now_money', + ]; + $bill = app()->make(UserBillRepository::class)->search($bill_where)->where('type','in',['sys_inc_money','recharge'])->sum('number'); + //充值消费金额 + $bill_where = [ + 'pm' => 0, + 'status' => 1, + 'date' => $where['date'], + 'category' => 'now_money', + ]; + $_bill = app()->make(UserBillRepository::class)->search($bill_where)->where('type','in',['presell','pay_product','sys_dec_money'])->sum('number'); + //产生交易的商户数 + $mer_number = $this->dao->search($where)->group('mer_id')->count(); + + $stat = [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $count, + 'field' => '元', + 'name' => '订单收入总金额' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $refund_order, + 'field' => '元', + 'name' => '退款支出金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $brokerage, + 'field' => '元', + 'name' => '佣金支出金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $charge, + 'field' => '元', + 'name' => '平台手续费' + ], + [ + 'className' => 'el-icon-s-finance', + 'count' => $bill, + 'field' => '元', + 'name' => '充值金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $_bill, + 'field' => '元', + 'name' => '充值消费金额' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $mer_number, + 'field' => '个', + 'name' => '产生交易的商户数' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $coupon, + 'field' => '元', + 'name' => '优惠券金额' + ] + ]; + return compact('stat'); + } + + /** + * TODO 商户头部统计 + * @param $where + * @return array + * @author Qinii + * @day 5/6/21 + */ + public function getMerchantTitle($where) + { + //商户收入 + $count = $this->dao->search($where)->where('financial_type','in',['order','mer_presell'])->sum('number'); + //平台优惠券 + $coupon = $this->dao->search($where)->where('financial_type','in',['order_platform_coupon','order_svip_coupon'])->sum('number'); + //商户余额 + $mer_money = app()->make(MerchantRepository::class)->search(['mer_id' => $where['is_mer']])->value('mer_money'); + //最低提现额度 + $extract_minimum_line = systemConfig('extract_minimum_line'); + //商户可提现金额 + $_line = bcsub($mer_money,$extract_minimum_line,2); + //退款支出金额 + $refund_order = $this->dao->search($where)->where('financial_type','refund_order')->sum('number'); + //佣金支出金额 + $_brokerage = $this->dao->search($where)->where('financial_type','in',['brokerage_one','brokerage_two'])->sum('number'); + $refund_brokerage = $this->dao->search($where)->where('financial_type','in',['refund_brokerage_one','refund_brokerage_two'])->sum('number'); + $brokerage = bcsub($_brokerage,$refund_brokerage,2); + //平台手续费 + $refund_true = $this->dao->search($where)->where('financial_type','in',['order_charge','presell_charge'])->sum('number'); + $order_charge = $this->dao->search($where)->where('financial_type','refund_charge')->sum('number'); + $charge = bcsub($refund_true,$order_charge,2); + //商户可提现金额 +// $bill_order = app()->make(StoreOrderRepository::class)->search(['paid' => 1,'date' => $where['date'],'pay_type' => 0])->sum('pay_price'); + $merLockMoney = app()->make(UserBillRepository::class)->merchantLickMoney($where['is_mer']); + $stat = [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $count, + 'field' => '元', + 'name' => '商户收入' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $mer_money, + 'field' => '元', + 'name' => '商户余额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => ($_line < 0) ? 0 : $_line, + 'field' => '元', + 'name' => '商户可提现金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $refund_order, + 'field' => '元', + 'name' => '退款支出' + ], + [ + 'className' => 'el-icon-s-finance', + 'count' => $brokerage, + 'field' => '元', + 'name' => '佣金支出' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $charge, + 'field' => '元', + 'name' => '平台手续费' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $coupon, + 'field' => '元', + 'name' => '平台优惠券补贴' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $merLockMoney, + 'field' => '元', + 'name' => '商户冻结金额' + ], + ]; + return compact('stat'); + } + + /** + * TODO 月账单 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 3/23/21 + */ + public function getAdminList(array $where,int $page,int $limit) + { + //日 + if($where['type'] == 1){ + $field = Db::raw('from_unixtime(unix_timestamp(create_time),\'%Y-%m-%d\') as time'); + }else{ + //月 + if(!empty($where['date'])){ + list($startTime, $endTime) = explode('-', $where['date']); + $firstday = date('Y/m/01', strtotime($startTime)); + $lastday_ = date('Y/m/01', strtotime($endTime)); + $lastday = date('Y/m/d', strtotime("$lastday_ +1 month -1 day")); + $where['date'] = $firstday.'-'.$lastday; + } + $field = Db::raw('from_unixtime(unix_timestamp(create_time),\'%Y-%m\') as time'); + } + $make = app()->make(UserBillRepository::class); + + $query = $this->dao->search($where)->field($field)->group("time")->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select()->each(function ($item) use($where){ + + $key = $where['is_mer'] ? $where['is_mer'].'_financial_record_list_'.$item['time'] : 'sys_financial_record_list_'.$item['time']; + if(($where['type'] == 1 && ($item['time'] == date('Y-m-d',time()))) || ($where['type'] == 2 && ($item['time'] == date('Y-m',time())))){ + $income = ($this->countIncome($where['type'],$where,$item['time']))['number'] ; + $expend = ($this->countExpend($where['type'],$where,$item['time']))['number'] ; + $ret = [ + 'income' => $income, + 'expend' => $expend , + 'charge' => bcsub($income,$expend,2), + ]; + + }else{ + if(!$ret = Cache::get($key)){ + $income = ($this->countIncome($where['type'],$where,$item['time']))['number'] ; + $expend = ($this->countExpend($where['type'],$where,$item['time']))['number'] ; + $ret = [ + 'income' => $income, + 'expend' => $expend , + 'charge' => bcsub($income,$expend,2), + ]; + Cache::tag('system')->set($key,$ret,24 * 3600); + } + } + $item['income'] = $ret['income']; + $item['expend'] = $ret['expend']; + $item['charge'] = $ret['charge']; + }); + + return compact('count','list'); + } + + /** + * TODO 平台详情 + * @param int $type + * @param array $where + * @return mixed + * @author Qinii + * @day 3/23/21 + */ + public function adminDetail(int $type,array $where) + { + $date_ = strtotime($where['date']);unset($where['date']); + $date = ($type == 1) ? date('Y-m-d',$date_) : date('Y-m',$date_); + $income = $this->countIncome($type,$where,$date); + $bill = $this->countBill($type,$date); + $expend = $this->countExpend($type,$where,$date); + $charge = bcsub($income['number'],$expend['number'],2); + $data['date'] = $date; + $data['income'] = [ + 'title' => '订单收入总金额', + 'number' => $income['number'] , + 'count' => $income['count'].'笔', + 'data' => [ + ['订单支付', $income['number_order'].'元', $income['count_order'].'笔'], + ['退回优惠券补贴', $income['number_coupon'].'元', $income['count_coupon'].'笔'], + ['退回会员优惠券补贴', $income['number_svipcoupon'].'元', $income['count_svipcoupon'].'笔'], + ] + ]; + $data['bill'] = [ + 'title' => '充值金额', + 'number' => $bill['number'] , + 'count' => $bill['count'].'笔', + 'data' => [] + ]; + $data['expend'] = [ + 'title' => '支出总金额', + 'number' => $expend['number'] , + 'count' => $expend['count'].'笔', + 'data' => [ + ['应付商户金额', $expend['number_order'] .'元', $expend['count_order'].'笔'], + ['佣金', $expend['number_brokerage'] .'元', $expend['count_brokerage'].'笔'], + ['返还手续费', $expend['number_charge'] .'元', $expend['count_charge'].'笔'], + ['优惠券补贴',$expend['number_coupon'] .'元', $expend['count_coupon'].'笔'], + ['会员优惠券补贴',$expend['number_svipcoupon'] .'元', $expend['count_svipcoupon'].'笔'], + ] + ]; + $data['charge'] = [ + 'title' => '平台手续费收入总金额', + 'number' => $charge , + 'count' => '', + 'data' => [] + ]; + return $data; + } + + /** + * TODO 商户详情 + * @param int $type + * @param array $where + * @return mixed + * @author Qinii + * @day 5/6/21 + */ + public function merDetail(int $type,array $where) + { + $date_ = strtotime($where['date']); unset($where['date']); + $date = ($type == 1) ? date('Y-m-d',$date_) : date('Y-m',$date_); + $income = $this->countIncome($type,$where,$date); + $expend = $this->countExpend($type,$where,$date); + $charge = bcsub($income['number'],$expend['number'],2); + + $data['date'] = $date; + $data['income'] = [ + 'title' => '订单收入总金额', + 'number' => $income['number'] , + 'count' => $income['count'].'笔', + 'data' => [ + ['订单支付', $income['number_order'].'元', $income['count_order'].'笔'], + ['优惠券补贴', $income['number_coupon'].'元', $income['count_coupon'].'笔'], + ['会员优惠券补贴', $income['number_svipcoupon'].'元', $income['count_svipcoupon'].'笔'], + ] + ]; + $data['expend'] = [ + 'title' => '支出总金额', + 'number' => $expend['number'] , + 'count' => $expend['count'].'笔', + 'data' => [ + [ + '平台手续费', + bcsub($expend['number_order_charge'],$expend['number_charge'],2) .'元', + $expend['count_charge']+$expend['count_order_charge'].'笔' + ], + [ + '佣金', + bcsub($expend['number_brokerage'],$expend['number_refund_brokerage'],2) .'元', + $expend['count_brokerage'] + $expend['count_refund_brokerage'].'笔' + ], + [ + '商户退款', + $expend['number_refund'] .'元', + $expend['count_refund'].'笔' + ], + [ + '退还优惠券补贴', + $expend['number_coupon'] .'元', + $expend['count_coupon'].'笔' + ], + [ + '退还会员优惠券补贴', + $expend['number_svipcoupon'] .'元', + $expend['count_svipcoupon'].'笔' + ], + ] + ]; + $data['charge'] = [ + 'title' => '应入账总金额', + 'number' => $charge , + 'count' => '', + 'data' => [] + ]; + + return $data; + } + + /** + * TODO 总收入 + * @param $type + * @param $date + * @return array + * @author Qinii + * @day 3/23/21 + */ + public function countIncome($type, $where, $date) + { + $financialType = ['order','order_presell','presell','mer_presell']; + [$data['count_order'],$data['number_order']] = $this->dao->getDataByType($type, $where, $date, $financialType); + if ($where['is_mer']){ + $financialType = ['order_platform_coupon']; + } else { + $financialType = ['refund_platform_coupon']; + } + [ $data['count_coupon'], $data['number_coupon']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + if ($where['is_mer']){ + $financialType = ['order_svip_coupon']; + } else { + $financialType = ['refund_svip_coupon']; + } + [ $data['count_svipcoupon'], $data['number_svipcoupon']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + $data['count'] = $data['count_order']; + $data['number'] = bcadd($data['number_coupon'],$data['number_order'],2); + + return $data; + } + + /** + * TODO 充值金额 + * @param $type + * @param $date + * @return array + * @author Qinii + * @day 3/23/21 + */ + public function countBill($type, $date) + { + $bill_where = [ + 'pm' => 1, + 'status' => 1, + 'category' => 'now_money', + ]; + $query = app()->make(UserBillRepository::class)->search($bill_where)->where('type','in',['sys_inc_money','recharge']); + //充值消费金额 + if($type == 1) $query->whereDay('create_time', $date); + if($type == 2) $query->whereMonth('create_time',$date); + + $count = $query->count(); + $number = $query->sum('number'); + + return compact('count','number'); + } + + /** + * TODO 平台总支出 + * @param $type + * @param $date + * @return array + * @author Qinii + * @day 3/23/21 + */ + public function countExpend($type, $where, $date) + { + /** + * 平台支出 + * 商户的收入 order_true + 佣金 brokerage_one,brokerage_two + 手续费 refund_charge + 商户预售收入 presell_true + * + * 商户支出 + * 退回收入 refund_order + (佣金 brokerage_one,brokerage_two - 退回佣金 refund_brokerage_two,refund_brokerage_one ) + (手续费 order_charge + 预售手续费 presell_charge - 平台退给商户的手续费 refund_charge ) + */ + // 退回佣金 + $financialType = ['brokerage_one','brokerage_two']; + [$data['count_brokerage'],$data['number_brokerage']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + // 退回 手续费 + $financialType = ['refund_charge']; + [$data['count_charge'],$data['number_charge']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + if($where['is_mer']){ //商户的 + //退回 收入 + $financialType = ['refund_order']; + [$data['count_refund'],$data['number_refund']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + //平台手续费 + $financialType = ['order_charge','presell_charge']; + [$data['count_order_charge'],$data['number_order_charge']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + //退回佣金 + $financialType = ['refund_brokerage_two','refund_brokerage_one']; + [$data['count_refund_brokerage'],$data['number_refund_brokerage']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + //退回给平台的优惠券金额 + $financialType = ['refund_platform_coupon']; + [$data['count_coupon'], $data['number_coupon']] = $this->dao->getDataByType($type, $where, $date, $financialType); + //退回给平台的会员优惠券金额 + $financialType = ['refund_svip_coupon']; + [$data['count_svipcoupon'], $data['number_svipcoupon']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + //佣金 brokerage_one,brokerage_two - 退回佣金 refund_brokerage_two,refund_brokerage_one ) + $number = bcsub($data['number_brokerage'],$data['number_refund_brokerage'],3); + + //平台手续费 =( order_charge + 预售手续费 presell_charge - 平台退给商户的手续费 refund_charge ) + $number_1 = bcsub($data['number_order_charge'],$data['number_charge'],3); + + //退回收入 refund_order + 退回佣金 + $number_2 = bcadd(bcadd($data['number_refund'],$data['number_coupon'],2),$data['number_svipcoupon'],2); + + $data['count'] = $data['count_brokerage'] + $data['count_refund'] + $data['count_order_charge'] + $data['count_refund'] + $data['count_refund_brokerage'] + $data['count_svipcoupon']; + $data['number'] =bcadd(bcadd($number_2,$number,3),$number_1,2); + + }else{ //平台的 + // 退回 订单实际获得金额 + + $financialType = ['order_true','presell_true']; + [$data['count_order'],$data['number_order']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + //付给商户的优惠券抵扣金额 + $financialType = ['order_platform_coupon']; + [$data['count_coupon'], $data['number_coupon']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + //付给商户的svip优惠券抵扣金额 + $financialType = ['order_svip_coupon']; + [$data['count_svipcoupon'], $data['number_svipcoupon']] = $this->dao->getDataByType($type, $where, $date, $financialType); + + $number = bcadd($data['number_brokerage'],$data['number_order'],2); + $number_1 = bcadd(bcadd($number,$data['number_coupon'],2),$data['number_svipcoupon'],2); + + $data['count'] = $data['count_brokerage'] + $data['count_order'] + $data['count_charge']; + $data['number'] = bcadd($number_1,$data['number_charge'],2); + } + + return $data; + } + + /** + * TODO 手续费 + * @param $where + * @param $date + * @return mixed + * @author Qinii + * @day 3/24/21 + */ + public function countCharge($type,$where,$date) + { + $financialType = ['order_charge']; + [$count, $number] = $this->dao->getDataByType($type, $where, $date, $financialType); + + return compact('count','number'); + } + + /** + * TODO 退款 + * @param $where + * @param $date + * @return mixed + * @author Qinii + * @day 3/24/21 + */ + public function countRefund($type,$where,$date) + { + $financialType = ['refund_order']; + [$count, $number] = $this->dao->getDataByType($type, $where, $date, $financialType); + + return compact('count','number'); + } +} diff --git a/app/common/repositories/system/merchant/MerchantAdminRepository.php b/app/common/repositories/system/merchant/MerchantAdminRepository.php new file mode 100644 index 00000000..f3dac475 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantAdminRepository.php @@ -0,0 +1,382 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\merchant; + + +use app\common\dao\BaseDao; +use app\common\dao\system\merchant\MerchantAdminDao; +use app\common\model\system\merchant\Merchant; +use app\common\model\system\merchant\MerchantAdmin; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\auth\RoleRepository; +use crmeb\exceptions\AuthException; +use crmeb\services\JwtTokenService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Config; +use think\facade\Route; +use think\Model; + +/** + * Class MerchantRepository + * @package app\common\repositories\system\merchant + * @mixin MerchantAdminDao + * @author xaboy + * @day 2020-04-16 + */ +class MerchantAdminRepository extends BaseRepository +{ + + const PASSWORD_TYPE_ADMIN = 1; + const PASSWORD_TYPE_MERCHANT = 2; + const PASSWORD_TYPE_SELF = 3; + + /** + * MerchantAdminRepository constructor. + * @param MerchantAdminDao $dao + */ + public function __construct(MerchantAdminDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $merId + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function getList($merId, array $where, $page, $limit) + { + $query = $this->dao->search($merId, $where, 1); + $count = $query->count(); + $list = $query->page($page, $limit)->hidden(['pwd', 'is_del'])->select(); + $topAccount = $this->dao->merIdByAccount($merId); + foreach ($list as $k => $role) { + if ($topAccount) + $list[$k]['account'] = $topAccount . '@' . $role['account']; + $list[$k]['rule_name'] = $role->roleNames(); + } + return compact('list', 'count'); + } + + /** + * @param int $merId + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-18 + */ + public function form(int $merId, ?int $id = null, array $formData = []): Form + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('merchantAdminCreate')->build() : Route::buildUrl('merchantAdminUpdate', ['id' => $id])->build()); + + $rules = [ + Elm::select('roles', '身份', [])->options(function () use ($merId) { + $data = app()->make(RoleRepository::class)->getAllOptions($merId); + $options = []; + + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + })->multiple(true), + Elm::input('real_name', '管理员姓名'), + Elm::input('account', '账号')->required(), + Elm::input('phone', ' 联系电话'), + ]; + if (!$id) { + $rules[] = Elm::password('pwd', '密码')->required(); + $rules[] = Elm::password('againPassword', '确认密码')->required(); + } + $rules[] = Elm::switches('status', '是否开启', 1)->inactiveValue(0)->activeValue(1)->inactiveText('关')->activeText('开'); + $form->setRule($rules); + return $form->setTitle(is_null($id) ? '添加管理员' : '编辑管理员')->formData($formData); + } + + /** + * @param int $merId + * @param int $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function updateForm(int $merId, int $id) + { + return $this->form($merId, $id, $this->dao->get($id)->toArray()); + } + + /** + * @param Merchant $merchant + * @param $account + * @param $pwd + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-17 + */ + public function createMerchantAccount(Merchant $merchant, $account, $pwd) + { + $pwd = $this->passwordEncode($pwd); + $data = compact('pwd', 'account') + [ + 'mer_id' => $merchant->mer_id, + 'real_name' => $merchant->real_name, + 'phone' => $merchant->mer_phone, + 'level' => 0 + ]; + return $this->create($data); + } + + + /** + * @param $password + * @return bool|string + * @author xaboy + * @day 2020-04-17 + */ + public function passwordEncode($password) + { + return password_hash($password, PASSWORD_BCRYPT); + } + + /** + * @param string $account + * @param string $password + * @return array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-17 + */ + public function login(string $account, string $password) + { + event('admin.merLogin.before',compact('account', 'password')); + $accountInfo = explode('@', $account, 2); + if (count($accountInfo) === 1) { + $adminInfo = $this->dao->accountByTopAdmin($accountInfo[0]); + } else { + $merId = $this->dao->accountByMerchantId($accountInfo[0]); + if (!$merId){ + $key = 'mer_login_failuree_'.$account; + $numb = Cache::get($key) ?? 0; + $numb++; + Cache::set($key,$numb,15*60); + throw new ValidateException('账号或密码错误'); + } + $adminInfo = $this->dao->accountByAdmin($accountInfo[1], $merId); + } + + if (!$adminInfo || !password_verify($password, $adminInfo->pwd)){ + $key = 'mer_login_failuree_'.$account; + $numb = Cache::get($key) ?? 0; + $numb++; + Cache::set($key,$numb,15*60); + throw new ValidateException('账号或密码错误'); + } + + if ($adminInfo['status'] != 1) + throw new ValidateException('账号已关闭'); + + + /** + * @var MerchantRepository $merchantRepository + */ + $merchantRepository = app()->make(MerchantRepository::class); + $merchant = $merchantRepository->get($adminInfo->mer_id); + if (!$merchant) + throw new ValidateException('商户不存在'); + if (!$merchant['status']) + throw new ValidateException('商户已被锁定'); + + $adminInfo->last_time = date('Y-m-d H:i:s'); + $adminInfo->last_ip = app('request')->ip(); + $adminInfo->login_count++; + $adminInfo->save(); + event('admin.merLogin',compact('adminInfo')); + return $adminInfo; + } + + /** + * @param string $token + * @param int $exp + * @author xaboy + * @day 2020-04-10 + */ + public function cacheToken(string $token, int $exp) + { + Cache::set('mer_' . $token, time() + $exp, $exp); + } + + /** + * @param string $token + * @author xaboy + * @day 2020-04-17 + */ + public function checkToken(string $token) + { + $has = Cache::has('mer_' . $token); + if (!$has) + throw new AuthException('无效的token'); + $lastTime = Cache::get('mer_' . $token); + if (($lastTime + (intval(Config::get('admin.token_valid_exp', 15))) * 60) < time()) + throw new AuthException('token 已过期'); + } + + /** + * @param string $token + * @author xaboy + * @day 2020-04-17 + */ + public function updateToken(string $token) + { + Cache::set('mer_' . $token, time(), intval(Config::get('admin.token_valid_exp', 15)) * 60); + } + + /** + * @param string $token + * @author xaboy + * @day 2020-04-17 + */ + public function clearToken(string $token) + { + Cache::delete('mer_' . $token); + } + + /** + * @param MerchantAdmin $admin + * @return array + * @author xaboy + * @day 2020-04-17 + */ + public function createToken(MerchantAdmin $admin) + { + $service = new JwtTokenService(); + $exp = intval(Config::get('admin.token_exp', 3)); + $token = $service->createToken($admin->merchant_admin_id, 'mer', strtotime("+ {$exp}hour")); + $this->cacheToken($token['token'], $token['out']); + return $token; + } + + /** + * @param string $key + * @param string $code + * @author xaboy + * @day 2020-04-17 + */ + public function checkCode(string $key, string $code) + { + if (!env('DEVELOPMENT',false)){ + $_code = Cache::get('am_captcha' . $key); + if (!$_code) { + throw new ValidateException('验证码过期'); + } + + if (strtolower($_code) != strtolower($code)) { + throw new ValidateException('验证码错误'); + } + + //删除code + Cache::delete('am_captcha' . $key); + } + } + + + /** + * @param string $code + * @return string + * @author xaboy + * @day 2020-04-17 + */ + public function createLoginKey(string $code) + { + $key = uniqid(microtime(true), true); + Cache::set('am_captcha' . $key, $code, Config::get('admin.captcha_exp', 5) * 60); + return $key; + } + + /** + * @param int $id + * @param int $userType + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function passwordForm(int $id, $userType = 2) + { + $action = 'merchantAdminPassword'; + if ($userType == self::PASSWORD_TYPE_ADMIN) + $action = 'systemMerchantAdminPassword'; + else if ($userType == self::PASSWORD_TYPE_SELF) + $action = 'merchantAdminEditPassword'; + + $form = Elm::createForm(Route::buildUrl($action, $userType == self::PASSWORD_TYPE_SELF ? [] : compact('id'))->build(), [ + $rules[] = Elm::password('pwd', '密码')->required(), + $rules[] = Elm::password('againPassword', '确认密码')->required(), + ]); + return $form->setTitle('修改密码'); + } + + /** + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function editForm(array $formData) + { + $form = Elm::createForm(Route::buildUrl('merchantAdminEdit')->build()); + $form->setRule([ + Elm::input('real_name', '管理员姓名')->required(), + Elm::input('phone', '联系电话') + ]); + + return $form->setTitle('修改信息')->formData($formData); + } + + /** + * @param int $id + * @param array $data + * @return int + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function update(int $id, array $data) + { + if (isset($data['roles'])) + $data['roles'] = implode(',', $data['roles']); + return $this->dao->update($id, $data); + } + +} diff --git a/app/common/repositories/system/merchant/MerchantApplymentsRepository.php b/app/common/repositories/system/merchant/MerchantApplymentsRepository.php new file mode 100644 index 00000000..ef30dede --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantApplymentsRepository.php @@ -0,0 +1,570 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\system\merchant; + +use app\common\dao\system\merchant\MerchantAppymentsDao; +use app\common\model\system\merchant\MerchantApplyments; +use app\common\repositories\BaseRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\ImageWaterMarkService; +use crmeb\services\SmsService; +use crmeb\services\UploadService; +use crmeb\services\WechatService; +use crmeb\services\YunxinSmsService; +use FormBuilder\Factory\Elm; +use function Symfony\Component\String\b; +use think\db\concern\Transaction; +use think\Exception; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +class MerchantApplymentsRepository extends BaseRepository +{ + + const IDCARD = 'IDENTIFICATION_TYPE_MAINLAND_IDCARD'; //:中国大陆居民-身份证 + const PASSPORT = 'IDENTIFICATION_TYPE_OVERSEA_PASSPORT'; //:其他国家或地区居民-护照 + const HONGKONG = 'IDENTIFICATION_TYPE_HONGKONG'; //:中国香港居民–来往内地通行证 + const MACAO = 'IDENTIFICATION_TYPE_MACAO'; //:中国澳门居民–来往内地通行证 + const TAIWAN = 'IDENTIFICATION_TYPE_TAIWAN'; //:中国台湾居民–来往大陆通行证 + const FOREIGN_RESIDENT = 'IDENTIFICATION_TYPE_FOREIGN_RESIDENT'; //:外国人居留证 + const MACAO_RESIDENT = 'IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT'; //:港澳居民证 + const TAIWAN_RESIDENT = 'IDENTIFICATION_TYPE_TAIWAN_RESIDENT'; //:台湾居民证 + + public function __construct(MerchantAppymentsDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 申请 + * @param array $data + * @param $merId + * @return mixed + * @author Qinii + * @day 6/23/21 + */ + public function create(array $data,$merId) + { + $count = $this->dao->getSearch(['mer_id' => $merId])->count('*'); + if($count) throw new ValidateException('此商户已存在申请信息'); + + $out_request_no = $this->getOutRequestNo($merId); + $ret['mer_name'] = $data['merchant_shortname']; + $ret['out_request_no'] = $out_request_no; + $data['out_request_no'] = $out_request_no; + $ret['info'] = json_encode($data,JSON_UNESCAPED_UNICODE); + $ret['mer_id'] = $merId; + + $this->dao->create($ret); + } + + /** + * TODO 整理请求数据 + * @param $info + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function sltData($info) + { + foreach ($info as $key => $value){ + if(is_object($value)){ + $value = (array)$value; + } + $data[$key] = $value; + } + if (isset($data['need_account_info'])) unset($data['need_account_info']); + $data['id_doc_type'] = $this->getIdDocType($data['id_doc_type']); + + //营业执照 + if(isset($data['business_license_info'])){ + if(isset($data['business_license_info']['business_license_copy'])) { + $business_license_copy = $data['business_license_info']['business_license_copy']->media_id; + unset($data['business_license_info']['business_license_copy']); + $data['business_license_info']['business_license_copy'] = $business_license_copy; + } + if(isset($data['business_license_info']['business_time'])){ + $organization_time = json_encode($data['business_license_info']['business_time'],JSON_UNESCAPED_UNICODE); + $data['business_license_info']['business_time'] = $organization_time; + } + } + + //组织机构代码 + if(isset($data['organization_cert_info'])){ + if(isset($data['organization_cert_info']['organization_copy'])) { + $organization_copy = $data['organization_cert_info']['organization_copy']->media_id; + unset($data['organization_cert_info']['organization_copy']); + $data['organization_cert_info']['organization_copy'] = $organization_copy; + } + if(isset($data['organization_cert_info']['organization_time'])){ + $organization_time = json_encode($data['organization_cert_info']['organization_time'],JSON_UNESCAPED_UNICODE); + $data['organization_cert_info']['organization_time'] = $organization_time; + } + } + + //身份证 + if(isset($data['id_card_info'])){ + if(isset($data['id_card_info']['id_card_copy'])) { + $id_card_copy = $data['id_card_info']['id_card_copy']->media_id; + unset($data['id_card_info']['id_card_copy']); + $data['id_card_info']['id_card_copy'] = $id_card_copy; + } + if(isset($data['id_card_info']['id_card_national'])) { + $id_card_national = $data['id_card_info']['id_card_national']->media_id; + unset($data['id_card_info']['id_card_national']); + $data['id_card_info']['id_card_national'] = $id_card_national; + } + } + + //银行 + if(isset($data['account_info'])) { + if(is_array($data['account_info']['bank_address_code'])){ + $bank_address_code = (string)$data['account_info']['bank_address_code'][2]; + unset($data['account_infoaccount_info']['bank_address_code']); + $data['account_info']['bank_address_code'] = $bank_address_code; + } + $data['account_info']['bank_account_type'] = (string)$data['account_info']['bank_account_type']; + } + + //管理员 + if(isset($data['contact_info'])) { + $data['contact_info']['contact_type'] = (string)$data['contact_info']['contact_type']; + if ($data['contact_info']['contact_type'] == 65) { + unset( + $data['contact_info']['contact_id_doc_copy'], + $data['contact_info']['contact_id_doc_copy_back'], + $data['contact_info']['contact_id_doc_period_begin'], + $data['contact_info']['contact_id_doc_period_end'], + $data['contact_info']['business_authorization_letter'], + $data['contact_info']['contact_id_doc_type'] + ); + } + if(isset($data['contact_info']['contact_id_doc_period_end'])) + { + $doc_ = json_encode($data['contact_info']['contact_id_doc_period_end'],JSON_UNESCAPED_UNICODE); + $data['contact_info']['contact_id_doc_period_end'] = $doc_; + } + + if(isset($data['contact_info']['contact_id_doc_type'])) + { + $data['contact_info']['contact_id_doc_type'] = $this->getIdDocType($data['contact_info']['contact_id_doc_type']); + } + if(isset($data['contact_info']['contact_id_doc_copy'])) { + $contact_id_doc_copy = $data['contact_info']['contact_id_doc_copy']->media_id; + unset($data['contact_info']['contact_id_doc_copy']); + $data['contact_info']['contact_id_doc_copy'] = $contact_id_doc_copy; + } + + if(isset($data['contact_info']['contact_id_doc_copy_back'])) { + $contact_id_doc_copy_back = $data['contact_info']['contact_id_doc_copy_back']->media_id; + unset($data['contact_info']['contact_id_doc_copy_back']); + $data['contact_info']['contact_id_doc_copy_back'] = $contact_id_doc_copy_back; + } + if(isset($data['contact_info']['business_authorization_letter'])) { + $business_authorization_letter = $data['contact_info']['business_authorization_letter']->media_id; + unset($data['contact_info']['business_authorization_letter']); + $data['contact_info']['business_authorization_letter'] = $business_authorization_letter; + } + } + + //其他证件 + if(isset($data['id_doc_info'])){ + $doc_ = json_encode($data['id_doc_info']['doc_period_end'],JSON_UNESCAPED_UNICODE); + $data['id_doc_info']['doc_period_end'] = $doc_; + + if(isset($data['id_doc_info']['id_doc_copy'])) { + $id_doc_copy = $data['id_doc_info']['id_doc_copy']->media_id; + unset($data['id_doc_info']['id_doc_copy']); + $data['id_doc_info']['id_doc_copy'] = $id_doc_copy; + } + if(isset($data['id_doc_info']['id_doc_copy_back'])) { + $id_doc_copy_back = $data['id_doc_info']['id_doc_copy_back']->media_id; + unset($data['id_doc_info']['id_doc_copy_back']); + $data['id_doc_info']['id_doc_copy_back'] = $id_doc_copy_back; + } + } + + //店铺信息 + if(isset($data['sales_scene_info']['store_qr_code']) && $data['sales_scene_info']['store_qr_code']){ + $store_qr_code= $data['sales_scene_info']['store_qr_code']->media_id; + unset($data['sales_scene_info']['store_qr_code']); + $data['sales_scene_info']['store_qr_code'] = $store_qr_code; + } + + //特殊资质 + if(isset($data['qualifications']) && !empty($data['qualifications'])){ + $qualifications = []; + foreach ($data['qualifications'] as $item){ + $qualifications[] = $item->media_id; + } + unset($data['qualifications']); + $data['qualifications'] = json_encode($qualifications,JSON_UNESCAPED_UNICODE); + } + + //补充材料 + if(isset($data['business_addition_pics']) && !empty($data['business_addition_pics'])){ + $business_addition_pics = []; + foreach ($data['business_addition_pics'] as $item){ + $business_addition_pics[] = $item->media_id; + } + unset($data['business_addition_pics']); + $data['business_addition_pics'] = json_encode($business_addition_pics,JSON_UNESCAPED_UNICODE); + } + $data['organization_type'] = (string)$data['organization_type']; + return $data; + } + + /** + * TODO 生成申请单 + * @param $merId + * @return string + * @author Qinii + * @day 6/24/21 + */ + public function getOutRequestNo($merId) + { + + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $key = 'MERCHANT' . $merId . '_' . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369)); + + do{ + $ret = $this->dao->getSearch(['out_request_no' => $key])->count(); + }while($ret); + + return $key; + } + + /** + * TODO 详情 + * @param $id + * @param $merId + * @return array|\think\Model|null + * @author Qinii + * @day 6/22/21 + */ + public function detail(int $merId) + { + if($merId) $where['mer_id'] = $merId; + + $data = $this->dao->getSearch($where)->find(); + + if(!$data) return []; + $data['info'] = json_decode($data['info']); + return $data; + } + + /** + * TODO 编辑 + * @param $id + * @param $data + * @author Qinii + * @day 6/22/21 + */ + public function edit($id,$data) + { + //申请状态: 0.平台未提交,-1.平台驳回,10.平台提交审核中,11.需用户操作 ,20.已完成,30.已冻结,40.驳回 + $get = $this->dao->get($id); + if(!$get) throw new ValidateException('数据不存在'); + if(!in_array($get['status'],[-1,0,40])) throw new ValidateException('数据当前状态不可编辑'); + + $data['out_request_no'] = $get['out_request_no']; + $ret['info'] = json_encode($data,JSON_UNESCAPED_UNICODE); + $ret['status'] = 0; + $ret['message'] = ''; + $this->dao->update($id,$ret); + } + + /** + * TODO 查询申请状态 + * @param $merId + * @author Qinii + * @day 6/23/21 + */ + public function check($merId) + { + $ret = $this->dao->getSearch(['mer_id' => $merId])->find(); + $data = []; + if($ret['status'] < 10) throw new ValidateException('平台审核中...'); + if($ret['status'] == 20) throw new ValidateException('申请已完成,请勿重复查询'); + try{ + $data = WechatService::create()->applyments()->getApplicationById($ret->applyment_id); + }catch (\Exception $exception){ + + } + if(!$data){ + $data = WechatService::create()->applyments()->getApplicationByNo($ret->out_request_no); + if($data){ + $ret->applyment_id = $data['applyment_id']; + $ret->save(); + } + } + if($data) { + $result = $this->getApplymentState($data); + $this->sendSms($ret,$result['status']); + return Db::transaction(function () use ($merId, $ret, $result) { + if (isset($result['sub_mchid'])) $this->profitsharingAdd($ret,$result); + $this->dao->update($ret->mer_applyments_id, $result); + }); + }else{ + return ; + } + } + + /** + * TODO 添加分账商户 + * @param MerchantApplyments $ret + * @param $result + * @author Qinii + * @day 6/24/21 + */ + public function profitsharingAdd(MerchantApplyments $ret,$result) + { + $info = json_decode($ret['info']); + $profitsharing = [ + "type" => 'MERCHANT_ID', + "account" => $result['sub_mchid'], + // "name" => $info->account_info->account_name, + "relation_type" => "PLATFORM" + ]; + $res = WechatService::create()->applyments()->profitsharingAdd($profitsharing); + if(isset($res['account'])) app()->make(MerchantRepository::class)->update($ret->mer_id, ['sub_mchid' => $res['account'] ]); + } + + /** + * TODO 查询返回的状态整理 + * @param $data + * @return array + * @author Qinii + * @day 6/23/21 + */ + public function getApplymentState($data) + { + //CHECKING:资料校验中 + //ACCOUNT_NEED_VERIFY:待账户验证 + //AUDITING:审核中 + //REJECTED:已驳回 + //NEED_SIGN:待签约 + //FINISH:完成 + //FROZEN:已冻结 + $result = []; + $message = ''; + $status = 10; + switch (($data['applyment_state'])) + { + //申请状态: 0.平台未提交,-1.平台驳回,10.平台提交审核中,11.需用户操作 ,20.已完成,30.已冻结,40.驳回 + case 'ACCOUNT_NEED_VERIFY': + $status = 11; + if(isset($data['account_validation'])){ + $ret = $data['account_validation']; + $message = '通过申请银行账号向以下信息汇款完成验证,'.PHP_EOL; + $message .= '收款方信息:'.PHP_EOL; + $message .= "汇款金额:".$ret['pay_amount'].'(单位:分);'.PHP_EOL; + $message .= "收款卡号:".$ret['destination_account_number'].';'.PHP_EOL; + $message .= "收款户名:".$ret['destination_account_name'].';'.PHP_EOL; + $message .= "开户银行:".$ret['destination_account_bank'].';'.PHP_EOL; + $message .= "省市信息:".$ret['city'].';'.PHP_EOL; + $message .= "备注信息:".$ret['remark'].';'.PHP_EOL; + $message .= "汇款截止时间:".$ret['deadline'].'。'; + } + if(isset($data['legal_validation_url'])){ + $message = '商户法人通过此链接完成验证:'.$data['legal_validation_url']; + } + break; + case 'REJECTED': + $message = ''; + foreach ($data['audit_detail'] as $datum){ + $message .= '参数名称:'.$datum['param_name'].PHP_EOL; + $message .= '驳回原因:'.$datum['reject_reason'].PHP_EOL; + } + $status = 40; + break; + case 'NEED_SIGN': + $status = 11; + $message = $data['sign_url']; + break; + case 'FINISH': + $result['sub_mchid'] = $data['sub_mchid']; + $status = 20; + $message = '完成'; + break; + case 'FROZEN': + $status = 30; + break; + default: + break; + } + $result['status'] = $status; + $result['message'] = $message; + return $result; + } + + /** + * TODO 上传图片 + * @param $field + * @return array + * @author Qinii + * @day 6/21/21 + */ + public function uploadImage($field,$water) + { + $upload = UploadService::create(1); + $info = $upload->to('def')->move($field); + if ($info === false) throw new ValidateException($upload->getError()); + $res = $upload->getUploadInfo(); + $res['path'] = app()->getRootPath().'public'.($res['dir']); + $res['dir'] = tidy_url($res['dir']); + if($res['path']) $ret = WechatService::create()->uploadImages([$res]); + if(!$water) app()->make(ImageWaterMarkService::class)->run($res['path']); + return $ret; + } + + /** + * TODO 列表 + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 6/24/21 + */ + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where)->with(['merchant' => function($query){ + $query->field('mer_id,mer_name'); + }])->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + /** + * TODO 审核操作 + * @param int $id + * @param array $data + * @author Qinii + * @day 6/23/21 + */ + public function switchWithStatus(int $id,array $data) + { + $ret = $this->dao->get($id); + if(!$ret) throw new ValidateException('数据不存在'); + if($ret['status'] !== 0) throw new ValidateException('请勿重复审核'); + + if($data['status'] == 10){ + $info = $this->sltData(json_decode($ret['info'])); + Db::transaction(function() use($id,$info){ + WechatService::create()->applyments()->submitApplication($info); + $this->dao->update($id,['status' => 10]); + }); + } + if($data['status'] == -1) { + $this->dao->update($id,$data); + $this->sendSms($ret,-1); + } + + return ; + } + + /** + * TODO 发送短信 + * @param MerchantApplyments $ret + * @param $type + * @author Qinii + * @day 7/9/21 + */ + public function sendSms(MerchantApplyments $ret,$type) + { + if(!systemConfig('applyments_sms')) return ; + $info = json_decode($ret['info']); + switch ($type) + { + case -1: + $tmp = 'APPLYMENTS_FAIL'; + break; + case 11: + $tmp = 'APPLYMENTS_SIGN'; + break; + case 20: + $tmp = 'APPLYMENTS_SUCCESS'; + break; + case 40: + $tmp = 'APPLYMENTS_FAIL'; + break; + default: + return ; + break; + } + Queue::push(SendSmsJob::class,['tempId' => $tmp, 'id' => ['phone'=> $info->contact_info->mobile_phone, 'mer_name' => $info->merchant_shortname]]); + } + + /** + * TODO 查询商户的分账信息 + * @param $merId + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function getMerchant($merId) + { + $data = app()->make(MerchantRepository::class)->get($merId); + if(!$data) throw new ValidateException('数据不存在'); + if(!$data['sub_mchid']) throw new ValidateException('该商户不是分账商户'); + $ret = WechatService::create()->applyments()->getSubMerchant($data['sub_mchid']); + + return $ret; + } + + /** + * TODO 备注 + * @param $id + * @return \FormBuilder\Form + * @author Qinii + * @day 7/5/21 + */ + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantApplymentsMarrkSave', ['id' => $id])->build()); + $form->setRule([ + Elm::text('mark', '备注', $data['mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + /** + * TODO 经营者/法人证件类型 + * @param $key + * @return array|mixed + * @author Qinii + * @day 6/22/21 + */ + public function getIdDocType($key) + { + $data = [ + 1 => self::IDCARD, + 2 => self::PASSPORT, + 3 => self::HONGKONG, + 4 => self::MACAO, + 5 => self::TAIWAN, + 6 => self::FOREIGN_RESIDENT, + 7 => self::MACAO_RESIDENT, + 8 => self::TAIWAN_RESIDENT, + ]; + if($key) return $data[$key]; + return $data; + } +} diff --git a/app/common/repositories/system/merchant/MerchantCategoryRepository.php b/app/common/repositories/system/merchant/MerchantCategoryRepository.php new file mode 100644 index 00000000..02998579 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantCategoryRepository.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\merchant; + + +use app\common\dao\system\merchant\MerchantCategoryDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; + +/** + * Class MerchantCategoryRepository + * @package app\common\repositories\system\merchant + * @author xaboy + * @day 2020-05-06 + * @mixin MerchantCategoryDao + */ +class MerchantCategoryRepository extends BaseRepository +{ + /** + * @var MerchantCategoryDao + */ + protected $dao; + + /** + * MerchantCategoryRepository constructor. + * @param MerchantCategoryDao $dao + */ + public function __construct(MerchantCategoryDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->select()->toArray(); + foreach ($list as $k => $v) { + $list[$k]['commission_rate'] = ($v['commission_rate'] > 0 ? bcmul($v['commission_rate'], 100, 2) : 0) . '%'; + } + return compact('count', 'list'); + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-06 + */ + public function form(?int $id = null, array $formData = []) + { + $action = Route::buildUrl(is_null($id) ? 'systemMerchantCategoryCreate' : 'systemMerchantCategoryUpdate', is_null($id) ? [] : compact('id'))->build(); + + $form = Elm::createForm($action, [ + Elm::input('category_name', '分类名称')->required(), + Elm::number('commission_rate', '手续费(%)', 0)->required()->max(100)->precision(2) + ]); + + return $form->formData($formData)->setTitle(is_null($id) ? '添加商户分类' : '编辑商户分类'); + } + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-06 + */ + public function updateForm($id) + { + $res = $this->dao->get($id)->toArray(); + $res['commission_rate'] = $res['commission_rate'] > 0 ? bcmul($res['commission_rate'], 100, 2) : 0; + return $this->form($id, $res); + } + + /** + * 筛选分类 + * @Author:Qinii + * @Date: 2020/9/15 + * @return array + */ + public function getSelect() + { + $query = $this->search([])->field('merchant_category_id,category_name'); + $list = $query->select()->toArray(); + return $list; + } +} diff --git a/app/common/repositories/system/merchant/MerchantIntentionRepository.php b/app/common/repositories/system/merchant/MerchantIntentionRepository.php new file mode 100644 index 00000000..4be464e6 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantIntentionRepository.php @@ -0,0 +1,187 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\system\merchant; + +use app\common\repositories\BaseRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\SmsService; +use FormBuilder\Factory\Elm; +use app\common\dao\system\merchant\MerchantIntentionDao; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +/** + * @mixin MerchantIntentionDao + */ +class MerchantIntentionRepository extends BaseRepository +{ + + public function __construct(MerchantIntentionDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->order('create_time DESC , status ASC')->with(['merchantCategory', 'merchantType'])->select(); + + return compact('count', 'list'); + } + + public function detail($id, ?int $uid) + { + $where = ['mer_intention_id' => $id]; + if (!is_null($uid)) { + $where['uid'] = $uid; + } + return $this->dao->search($where)->find(); + } + + public function updateIntention($id, array $data) + { + if ($this->dao->existsWhere(['mer_intention_id' => $id, 'status' => '1'])) + throw new ValidateException('当前状态不能修改'); + $data['images'] = implode(',', (array)$data['images']); + $data['status'] = 0; + $data['fail_msg'] = ''; + return $this->dao->update($id, $data); + } + + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantIntentionMark', ['id' => $id])->build()); + $form->setRule([ + Elm::textarea('mark', '备注', $data['remark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + public function statusForm($id) + { + $form = Elm::createForm(Route::buildUrl('systemMerchantIntentionStatus', ['id' => $id])->build()); + $form->setRule([ + Elm::select('status', '审核状态', 1)->options([ + ['value' => 1, 'label' => '同意'], + ['value' => 2, 'label' => '拒绝'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::radio('create_mer', '自动创建商户', 1)->options([ + ['value' => 1, 'label' => '创建'], + ['value' => 2, 'label' => '不创建'], + ]) + ] + ], + [ + 'value' => 2, + 'rule' => [ + Elm::textarea('fail_msg', '失败原因', '信息填写有误') + ] + ] + ]), + ]); + return $form->setTitle('修改审核状态'); + } + + public function updateStatus($id, $data) + { + $create = $data['create_mer'] == 1; + unset($data['create_mer']); + $intention = $this->search(['mer_intention_id' => $id])->find(); + if (!$intention) + throw new ValidateException('信息不存在'); + if ($intention->status) + throw new ValidateException('状态有误,修改失败'); + $config = systemConfig(['broadcast_room_type', 'broadcast_goods_type']); + + $margin = app()->make(MerchantTypeRepository::class)->get($intention['mer_type_id']); + $data['is_margin'] = $margin['is_margin'] ?? -1; + $data['margin'] = $margin['margin'] ?? 0; + $merData = []; + if ($create) { + $password = substr($intention['phone'], -6); + $merData = [ + 'mer_name' => $intention['mer_name'], + 'mer_phone' => $intention['phone'], + 'mer_account' => $intention['phone'], + 'category_id' => $intention['merchant_category_id'], + 'type_id' => $intention['mer_type_id'], + 'real_name' => $intention['name'], + 'status' => 1, + 'area_id' => $intention['area_id'], + 'street_id' => $intention['street_id'], + 'village_id' => $intention['village_id'], + 'is_audit' => 1, + 'is_bro_room' => $config['broadcast_room_type'] == 1 ? 0 : 1, + 'is_bro_goods' => $config['broadcast_goods_type'] == 1 ? 0 : 1, + 'mer_password' => $password, + 'is_margin' => $margin['is_margin'] ?? -1, + 'margin' => $margin['margin'] ?? 0 + ]; + $data['fail_msg'] = ''; + $smsData = [ + 'date' => date('m月d日', strtotime($intention->create_time)), + 'mer' => $intention['mer_name'], + 'phone' => $intention['phone'], + 'pwd' => $password ?? '', + 'site_name' => systemConfig('site_name'), + ]; + } + if ($data['status'] == 2) { + $smsData = [ + 'phone' => $intention['phone'], + 'date' => date('m月d日', strtotime($intention->create_time)), + 'mer' => $intention['mer_name'], + 'site' => systemConfig('site_name'), + ]; + } + Db::transaction(function () use ($config, $intention, $data, $create,$margin,$merData,$smsData) { + if ($data['status'] == 1) { + if ($create) { + $merchant = app()->make(MerchantRepository::class)->createMerchant($merData); + $data['mer_id'] = $merchant->mer_id; + $data['uid'] = $intention['uid']; + $data['reg_admin_id'] = $merchant['merchant_admin']['merchant_admin_id']; + // 写入商户客服表 + $store_service_data['mer_id'] = $merchant->mer_id; + $store_service_data['uid'] = $intention['uid']; + $store_service_data['avatar'] = 'https://lihai001.oss-cn-chengdu.aliyuncs.com/def/1b716202302251108516996.png'; + $store_service_data['nickname'] = $intention['mer_name']; + $store_service_data['account'] = $intention['phone']; + $store_service_data['pwd'] = password_hash('123456', PASSWORD_BCRYPT);; + $store_service_data['status'] = 1; + $store_service_data['is_open'] = 1; + $store_service_data['notify'] = 1; + $store_service_data['customer'] = 1; + $store_service_data['is_verify'] = 1; + $store_service_data['is_goods'] = 1; + $store_service_data['phone'] = $intention['phone']; + $store_service_data['create_time'] = date('Y-m-d H:i:s'); + Db::name('store_service')->insert($store_service_data); + + Queue::push(SendSmsJob::class, ['tempId' => 'APPLY_MER_SUCCESS', 'id' => $smsData]); + } + } else { + Queue::push(SendSmsJob::class, ['tempId' => 'APPLY_MER_FAIL', 'id' => $smsData]); + } + $intention->save($data); + }); + } + +} diff --git a/app/common/repositories/system/merchant/MerchantIntentionRepository.php.bak b/app/common/repositories/system/merchant/MerchantIntentionRepository.php.bak new file mode 100644 index 00000000..b5428766 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantIntentionRepository.php.bak @@ -0,0 +1,166 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\system\merchant; + +use app\common\repositories\BaseRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\SmsService; +use FormBuilder\Factory\Elm; +use app\common\dao\system\merchant\MerchantIntentionDao; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +/** + * @mixin MerchantIntentionDao + */ +class MerchantIntentionRepository extends BaseRepository +{ + + public function __construct(MerchantIntentionDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->order('create_time DESC , status ASC')->with(['merchantCategory', 'merchantType'])->select(); + + return compact('count', 'list'); + } + + public function detail($id, ?int $uid) + { + $where = ['mer_intention_id' => $id]; + if (!is_null($uid)) { + $where['uid'] = $uid; + } + return $this->dao->search($where)->find(); + } + + public function updateIntention($id, array $data) + { + if ($this->dao->existsWhere(['mer_intention_id' => $id, 'status' => '1'])) + throw new ValidateException('当前状态不能修改'); + $data['images'] = implode(',', (array)$data['images']); + $data['status'] = 0; + $data['fail_msg'] = ''; + return $this->dao->update($id, $data); + } + + public function markForm($id) + { + $data = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemMerchantIntentionMark', ['id' => $id])->build()); + $form->setRule([ + Elm::textarea('mark', '备注', $data['remark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + public function statusForm($id) + { + $form = Elm::createForm(Route::buildUrl('systemMerchantIntentionStatus', ['id' => $id])->build()); + $form->setRule([ + Elm::select('status', '审核状态', 1)->options([ + ['value' => 1, 'label' => '同意'], + ['value' => 2, 'label' => '拒绝'], + ])->control([ + [ + 'value' => 1, + 'rule' => [ + Elm::radio('create_mer', '自动创建商户', 1)->options([ + ['value' => 1, 'label' => '创建'], + ['value' => 2, 'label' => '不创建'], + ]) + ] + ], + [ + 'value' => 2, + 'rule' => [ + Elm::textarea('fail_msg', '失败原因', '信息填写有误') + ] + ] + ]), + ]); + return $form->setTitle('修改审核状态'); + } + + public function updateStatus($id, $data) + { + $create = $data['create_mer'] == 1; + unset($data['create_mer']); + $intention = $this->search(['mer_intention_id' => $id])->find(); + if (!$intention) + throw new ValidateException('信息不存在'); + if ($intention->status) + throw new ValidateException('状态有误,修改失败'); + $config = systemConfig(['broadcast_room_type', 'broadcast_goods_type']); + + $margin = app()->make(MerchantTypeRepository::class)->get($intention['mer_type_id']); + $data['is_margin'] = $margin['is_margin'] ?? -1; + $data['margin'] = $margin['margin'] ?? 0; + $merData = []; + if ($create) { + $password = substr($intention['phone'], -6); + $merData = [ + 'mer_name' => $intention['mer_name'], + 'mer_phone' => $intention['phone'], + 'mer_account' => $intention['phone'], + 'category_id' => $intention['merchant_category_id'], + 'type_id' => $intention['mer_type_id'], + 'real_name' => $intention['name'], + 'status' => 1, + 'is_audit' => 1, + 'is_bro_room' => $config['broadcast_room_type'] == 1 ? 0 : 1, + 'is_bro_goods' => $config['broadcast_goods_type'] == 1 ? 0 : 1, + 'mer_password' => $password, + 'is_margin' => $margin['is_margin'] ?? -1, + 'margin' => $margin['margin'] ?? 0 + ]; + $data['fail_msg'] = ''; + $smsData = [ + 'date' => date('m月d日', strtotime($intention->create_time)), + 'mer' => $intention['mer_name'], + 'phone' => $intention['phone'], + 'pwd' => $password ?? '', + 'site_name' => systemConfig('site_name'), + ]; + } + if ($data['status'] == 2) { + $smsData = [ + 'phone' => $intention['phone'], + 'date' => date('m月d日', strtotime($intention->create_time)), + 'mer' => $intention['mer_name'], + 'site' => systemConfig('site_name'), + ]; + } + + Db::transaction(function () use ($config, $intention, $data, $create,$margin,$merData,$smsData) { + if ($data['status'] == 1) { + if ($create) { + $merchant = app()->make(MerchantRepository::class)->createMerchant($merData); + $data['mer_id'] = $merchant->mer_id; + Queue::push(SendSmsJob::class, ['tempId' => 'APPLY_MER_SUCCESS', 'id' => $smsData]); + } + } else { + Queue::push(SendSmsJob::class, ['tempId' => 'APPLY_MER_FAIL', 'id' => $smsData]); + } + $intention->save($data); + }); + } + +} diff --git a/app/common/repositories/system/merchant/MerchantRepository.php b/app/common/repositories/system/merchant/MerchantRepository.php new file mode 100644 index 00000000..5decc4f4 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantRepository.php @@ -0,0 +1,646 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\merchant; + + +use app\common\dao\system\merchant\MerchantDao; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\product\ProductReply; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserVisitRepository; +use app\common\repositories\wechat\RoutineQrcodeRepository; +use crmeb\jobs\ClearMerchantStoreJob; +use crmeb\services\QrcodeService; +use crmeb\services\UploadService; +use crmeb\services\WechatService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Exception; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class MerchantRepository + * @package app\common\repositories\system\merchant + * @mixin MerchantDao + * @author xaboy + * @day 2020-04-16 + */ +class MerchantRepository extends BaseRepository +{ + + /** + * MerchantRepository constructor. + * @param MerchantDao $dao + */ + public function __construct(MerchantDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function lst(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->setOption('field', []) + ->with([ + 'admin' => function ($query) { + $query->field('mer_id,account'); + }, + 'merchantCategory', + 'merchantType' + ]) + ->field('sort, mer_id, mer_name, real_name, mer_phone, mer_address, mark, status, create_time,is_best,is_trader,type_id,category_id,copy_product_num,export_dump_num,is_margin,margin,mer_avatar')->select(); + return compact('count', 'list'); + } + + public function count($where) + { + $where['status'] = 1; + $valid = $this->dao->search($where)->count(); + $where['status'] = 0; + $invalid = $this->dao->search($where)->count(); + return compact('valid', 'invalid'); + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-16 + */ + public function form(?int $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemMerchantCreate')->build() : Route::buildUrl('systemMerchantUpdate', ['id' => $id])->build()); + $is_margin = 0; + if ($formData && $formData['is_margin'] == 10) $is_margin = 1; + /** @var MerchantCategoryRepository $make */ + $make = app()->make(MerchantCategoryRepository::class); + $merchantTypeRepository = app()->make(MerchantTypeRepository::class); + $options = $merchantTypeRepository->getOptions(); + $margin = $merchantTypeRepository->getMargin(); + + $config = systemConfig(['broadcast_room_type', 'broadcast_goods_type']); + + $rule = [ + Elm::input('mer_name', '商户名称')->required(), + Elm::select('category_id', '商户分类')->options(function () use ($make) { + return $make->allOptions(); + })->requiredNum(), + + Elm::select('type_id', '店铺类型')->disabled($is_margin)->options($options)->requiredNum()->col(12)->control($margin), + + + Elm::cascader('geo_street', '商圈')->options(function () { + $slect=Db::name('geo_area')->where('city_code','510500') + ->withAttr('children',function ($value,$data){ + $select= Db::name('geo_street')->where('area_code',$data['value']) + ->field('street_code value,street_name label') + ->select(); + $arr=[]; + foreach ($select as $k=>$v){ + $v['value']=(int)$v['value']; + $arr[]=$v; + } + return $arr; + }) + ->field('area_code value,area_name label') + ->select()->toArray(); + return $slect; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]])->filterable(true), + Elm::input('mer_account', '商户账号')->required()->disabled(!is_null($id))->required(!is_null($id)), + Elm::password('mer_password', '登录密码')->required()->disabled(!is_null($id))->required(!is_null($id)), + Elm::input('real_name', '商户姓名'), + Elm::input('mer_phone', '商户手机号')->col(12)->required(), + Elm::number('commission_rate', '手续费(%)')->col(12), + Elm::input('mer_keyword', '商户关键字')->col(12), + Elm::input('mer_address', '商户地址'), + Elm::input('sub_mchid', '微信分账商户号'), + Elm::textarea('mark', '备注'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + $id ? Elm::hidden('status', 1) : Elm::switches('status', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_bro_room', '直播间审核', $config['broadcast_room_type'] == 1 ? 0 : 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_audit', '产品审核', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_bro_goods', '直播间商品审核', $config['broadcast_goods_type'] == 1 ? 0 : 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_best', '是否推荐')->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_trader', '是否自营')->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + ]; + + $form->setRule($rule); + return $form->setTitle(is_null($id) ? '添加商户' : '编辑商户')->formData($formData); + } + + /** + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/6/25 + */ + public function merchantForm(array $formData = []) + { + $form = Elm::createForm(Route::buildUrl('merchantUpdate')->build()); + $rule = [ + Elm::textarea('mer_info', '店铺简介')->required(), + Elm::input('service_phone', '服务电话')->required(), + Elm::frameImage('mer_banner', '店铺Banner(710*200px)', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=mer_banner&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]), + Elm::frameImage('mer_avatar', '店铺头像(120*120px)', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=mer_avatar&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]), + Elm::switches('mer_state', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + ]; + $form->setRule($rule); + return $form->setTitle('编辑店铺信息')->formData($formData); + } + + /** + * @param $id + * @return Form + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function updateForm($id) + { + $data = $this->dao->get($id)->toArray(); + /** @var MerchantAdminRepository $make */ + $make = app()->make(MerchantAdminRepository::class); + $data['mer_account'] = $make->merIdByAccount($id); + $data['mer_password'] = '***********'; + if($data['category_id'] == 0){ + $data['category_id'] = ''; + } + if($data['type_id'] == 0){ + $data['type_id'] = ''; + } + $find=Db::name('merchant_address')->where('mer_id',$id)->find(); + $data['geo_address']=$find; + return $data; +// return $this->form($id, $data); + } + + /** + * @param array $data + * @author xaboy + * @day 2020-04-17 + */ + public function createMerchant(array $data) + { + if ($this->fieldExists('mer_name', $data['mer_name'])) + throw new ValidateException('商户名已存在'); + if ($data['mer_phone'] && isPhone($data['mer_phone'])) + throw new ValidateException('请输入正确的手机号'); + $merchantCategoryRepository = app()->make(MerchantCategoryRepository::class); + $adminRepository = app()->make(MerchantAdminRepository::class); + + if (!$data['category_id'] || !$merchantCategoryRepository->exists($data['category_id'])) + throw new ValidateException('商户分类不存在'); + if ($adminRepository->fieldExists('account', $data['mer_account'])) + throw new ValidateException('账号已存在'); + + /** @var MerchantAdminRepository $make */ + $make = app()->make(MerchantAdminRepository::class); + + $margin = app()->make(MerchantTypeRepository::class)->get($data['type_id']); + $data['is_margin'] = $margin['is_margin'] ?? -1; + $data['margin'] = $margin['margin'] ?? 0; + + return Db::transaction(function () use ($data, $make) { + $account = $data['mer_account']; + $password = $data['mer_password']; + unset($data['mer_account'], $data['mer_password']); + + $merchant = $this->dao->create($data); + $merchant['merchant_admin']=$make->createMerchantAccount($merchant, $account, $password); + $address_id = Db::name('merchant_address')->insertGetId(['mer_id'=>$merchant->mer_id,'street_id'=>$data['street_id'],'area_id'=>$data['area_id'],'village_id'=>$data['village_id']]); + if($data['area_id'] && $data['village_id']){ + Db::name('merchant_address')->where('id',$address_id)->update(['area_id'=>$data['area_id'],'village_id'=>$data['village_id']]); + } + app()->make(ShippingTemplateRepository::class)->createDefault($merchant->mer_id); + app()->make(ProductCopyRepository::class)->defaulCopyNum($merchant->mer_id); + return $merchant; + }); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $where + * @param $page + * @param $limit + * @return array + */ + public function getList($where, $page, $limit, $userInfo) + { + $field = 'care_count,is_trader,type_id,mer_id,mer_banner,mini_banner,mer_name, mark,mer_avatar,product_score,service_score,postage_score,sales,status,is_best,create_time,long,lat,is_margin'; + $where['status'] = 1; + $where['mer_state'] = 1; + $where['is_del'] = 0; + if (isset($where['location'])) { + $data = @explode(',', (string)$where['location']); + if (2 != count(array_filter($data ?: []))) { + unset($where['location']); + } else { + $where['location'] = [ + 'lat' => (float)$data[0], + 'long' => (float)$data[1], + ]; + } + } + + if ($where['keyword'] !== '') { + app()->make(UserVisitRepository::class)->searchMerchant($userInfo ? $userInfo['uid'] : 0, $where['keyword']); + } + $query = $this->dao->search($where)->with(['type_name']); + $count = $query->count(); + $status = systemConfig('mer_location'); + $list = $query->page($page, $limit)->setOption('field', [])->field($field)->select() + ->each(function ($item) use ($status, $where) { + if ($status && $item['lat'] && $item['long'] && isset($where['location']['lat'], $where['location']['long'])) { + $distance = getDistance($where['location']['lat'], $where['location']['long'], $item['lat'], $item['long']); + if ($distance < 0.9) { + $distance = max(bcmul($distance, 1000, 0), 1).'m'; + if ($distance == '1m') { + $distance = '100m以内'; + } + } else { + $distance .= 'km'; + } + $item['distance'] = $distance; + } + $item['recommend'] = isset($where['delivery_way']) ? $item['CityRecommend'] : $item['AllRecommend']; + return $item; + }); + + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return array|Model|null + */ + public function merExists(int $id) + { + return ($this->dao->get($id)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @param $userInfo + * @return array|Model|null + */ + public function detail($id, $userInfo) + { + $merchant = $this->dao->apiGetOne($id)->hidden([ + "real_name", "mer_phone", "reg_admin_id", "sort", "is_del", "is_audit", "is_best", "mer_state", "bank", "bank_number", "bank_name", 'update_time', + 'financial_alipay', 'financial_bank', 'financial_wechat', 'financial_type','mer_take_phone' + ]); + $merchant->append(['type_name', 'isset_certificate', 'services_type']); + $merchant['care'] = false; + if ($userInfo) + $merchant['care'] = $this->getCareByUser($id, $userInfo->uid); + return $merchant; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $merId + * @param int $userId + * @return bool + */ + public function getCareByUser(int $merId, int $userId) + { + if (app()->make(UserRelationRepository::class)->getWhere(['type' => 10, 'type_id' => $merId, 'uid' => $userId])) + return true; + return false; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $merId + * @param $where + * @param $page + * @param $limit + * @param $userInfo + * @return mixed + */ + public function productList($merId, $where, $page, $limit, $userInfo) + { + return app()->make(ProductRepository::class)->getApiSearch($merId, $where, $page, $limit, $userInfo); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return mixed + */ + public function categoryList(int $id) + { + return app()->make(StoreCategoryRepository::class)->getApiFormatList($id, 1); + } + + public function wxQrcode($merId) + { + $siteUrl = systemConfig('site_url'); + $name = md5('mwx' . $merId . date('Ymd')) . '.jpg'; + $attachmentRepository = app()->make(AttachmentRepository::class); + $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]); + + if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) { + $imageInfo->delete(); + $imageInfo = null; + } + if (!$imageInfo) { + $codeUrl = rtrim($siteUrl, '/') . '/pages/store/home/index?id=' . $merId; //二维码链接 + if (systemConfig('open_wechat_share')) { + $qrcode = WechatService::create(false)->qrcodeService(); + $codeUrl = $qrcode->forever('_scan_url_mer_' . $merId)->url; + } + $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($codeUrl, $name); + if (is_string($imageInfo)) throw new ValidateException('二维码生成失败'); + + $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl); + + $attachmentRepository->create(systemConfig('upload_type') ?: 1, -2, $merId, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $urlCode = $imageInfo['dir']; + } else $urlCode = $imageInfo['attachment_src']; + return $urlCode; + } + + public function routineQrcode($merId) + { + $name = md5('smrt' . $merId . date('Ymd')) . '.jpg'; + return tidy_url(app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/store/home/index', 'id=' . $merId), 0); + } + + public function copyForm(int $id) + { + $form = Elm::createForm(Route::buildUrl('systemMerchantChangeCopy', ['id' => $id])->build()); + $form->setRule([ + Elm::input('copy_num', '复制次数', $this->dao->getCopyNum($id))->disabled(true)->readonly(true), + Elm::radio('type', '修改类型', 1) + ->setOptions([ + ['value' => 1, 'label' => '增加'], + ['value' => 2, 'label' => '减少'], + ]), + Elm::number('num', '修改数量', 0)->required() + ]); + return $form->setTitle('修改复制商品次数'); + } + + public function delete($id) + { + Db::transaction(function () use ($id) { + $this->dao->update($id, ['is_del' => 1]); + app()->make(MerchantAdminRepository::class)->deleteMer($id); + Queue::push(ClearMerchantStoreJob::class, ['mer_id' => $id]); + }); + } + + /** + * TODO 清理删除商户但没有删除的商品数据 + * @author Qinii + * @day 5/15/21 + */ + public function clearRedundancy() + { + $ret = (int)$this->dao->search(['is_del' => 1])->value('mer_id'); + if (!$ret) return; + try { + app()->make(ProductRepository::class)->clearMerchantProduct($ret); + app()->make(StoreCouponRepository::class)->getSearch([])->where('mer_id', $ret)->update(['is_del' => 1, 'status' => 0]); + app()->make(StoreCouponUserRepository::class)->getSearch([])->where('mer_id', $ret)->update(['is_fail' => 1, 'status'=>2]); + } catch (\Exception $exception) { + throw new ValidateException($exception->getMessage()); + } + } + + public function addLockMoney(int $merId, string $orderType, int $orderId, float $money) + { + if ($money <= 0) return; + if (systemConfig('mer_lock_time')) { + app()->make(UserBillRepository::class)->incBill($merId, 'mer_lock_money', $orderType, [ + 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId, + 'mer_id' => $merId, + 'status' => 0, + 'title' => '商户冻结余额', + 'number' => $money, + 'mark' => '商户冻结余额', + 'balance' => 0 + ]); + } else { + $this->dao->addMoney($merId, $money); + } + } + + public function checkCrmebNum(int $merId, string $type) + { + $merchant = $this->dao->get($merId); + switch ($type) { + case 'copy': + if (!systemConfig('copy_product_status')) { + throw new ValidateException('复制商品未开启'); + } + if (!$merchant['copy_product_num']) { + throw new ValidateException('复制商品剩余次数不足'); + } + break; + case 'dump': + if (!systemConfig('crmeb_serve_dump')) { + throw new ValidateException('电子面单未开启'); + } + if (!$merchant['export_dump_num']) { + throw new ValidateException('电子面单剩余次数不足'); + } + break; + } + return true; + } + + public function subLockMoney(int $merId, string $orderType, int $orderId, float $money) + { + if ($money <= 0) return; + $make = app()->make(UserBillRepository::class); + $bill = $make->search(['category' => 'mer_lock_money', 'type' => $orderType, 'mer_id' => $merId, 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId, 'status' => 0])->find(); + if (!$bill) { + $this->dao->subMoney($merId, $money); + } else { + $make->decBill($merId, 'mer_refund_money', $orderType, [ + 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId, + 'mer_id' => $merId, + 'status' => 1, + 'title' => '商户冻结余额退款', + 'number' => $money, + 'mark' => '商户冻结余额退款', + 'balance' => 0 + ]); + } + } + + public function computedLockMoney(StoreOrder $order) + { + Db::transaction(function () use ($order) { + $money = 0; + $make = app()->make(UserBillRepository::class); + $bill = $make->search(['category' => 'mer_lock_money', 'type' => 'order', 'link_id' => '1' . $order->order_id, 'status' => 0])->find(); + if ($bill) { + $money = bcsub($bill->number, $make->refundMerchantMoney($bill->link_id, $bill->type, $bill->mer_id), 2); + if ($order->presellOrder) { + $presellBill = $make->search(['category' => 'mer_lock_money', 'type' => 'presell', 'link_id' => '2' . $order->presellOrder->presell_order_id, 'status' => 0])->find(); + if ($presellBill) { + $money = bcadd($money, bcsub($presellBill->number, $make->refundMerchantMoney($presellBill->link_id, $presellBill->type, $presellBill->mer_id), 2), 2); + $presellBill->status = 1; + $presellBill->save(); + } + } + $bill->status = 1; + $bill->save(); + } + if ($money > 0) { + app()->make(UserBillRepository::class)->incBill($order->uid, 'mer_computed_money', 'order', [ + 'link_id' => $order->order_id, + 'mer_id' => $order->mer_id, + 'status' => 0, + 'title' => '商户待解冻余额', + 'number' => $money, + 'mark' => '交易完成,商户待解冻余额' . floatval($money) . '元', + 'balance' => 0 + ]); + } + }); + } + + public function checkMargin($merId, $typeId) + { + $merchant = $this->dao->get($merId); + $is_margin = 0; + $margin = 0; + if ($merchant['is_margin'] == 10) { + $margin = $merchant['margin']; + $is_margin = $merchant['is_margin']; + } else { + $marginData = app()->make(MerchantTypeRepository::class)->get($typeId); + + if ($marginData) { + $is_margin = $marginData['is_margin']; + $margin = $marginData['margin']; + } + } + return compact('is_margin', 'margin'); + } + + public function setMarginForm(int $id) + { + $merchant = $this->dao->get($id); + if ($merchant->is_margin !== 10) { + throw new ValidateException('商户无保证金可扣'); + } + $form = Elm::createForm(Route::buildUrl('systemMarginSet')->build()); + $form->setRule([ + Elm::input('mer_name', '商户名称', $merchant->mer_name)->disabled(true), + Elm::input('mer_id', '商户ID', $merchant->mer_id)->disabled(true), + Elm::input('margin', '商户剩余保证金', $merchant->margin)->disabled(true), + Elm::number('number', '保证金扣除金额', 0)->max($merchant->margin)->precision(2)->required(), + Elm::text('mark', '保证金扣除原因')->required(), + ]); + return $form->setTitle('扣除保证金'); + } + + /** + * TODO + * @param $data + * @return \think\response\Json + * @author Qinii + * @day 2/7/22 + */ + public function setMargin($data) + { + $merechant = $this->dao->get($data['mer_id']); + if ($merechant->is_margin !== 10) { + throw new ValidateException('商户未支付保证金或已申请退款'); + } + if ($data['number'] < 0) { + throw new ValidateException('扣除保证金额不能小于0'); + } + + if (bccomp($merechant->margin, $data['number'], 2) == -1) { + throw new ValidateException('扣除保证金额不足'); + } + + $data['balance'] = bcsub($merechant->margin, $data['number'], 2); + + Db::transaction(function () use ($merechant, $data) { + $merechant->margin = $data['balance']; + $merechant->save(); + app()->make(UserBillRepository::class)->bill(0, 'mer_margin', $data['type'], 0, $data); + }); + } + + public function changeDeliveryBalance($merId,$number) + { + $merechant = $this->dao->get($merId); + if (bccomp($merechant->delivery_balance, $number, 2) == -1) { + throw new ValidateException('余额不足,请先充值(配送费用:'.$number.'元)'); + } + Db::transaction(function () use ($merechant, $number) { + $merechant->delivery_balance = bcsub($merechant->delivery_balance, $number, 2); + $merechant->save(); + }); + } + + +} diff --git a/app/common/repositories/system/merchant/MerchantRepository.php.bak b/app/common/repositories/system/merchant/MerchantRepository.php.bak new file mode 100644 index 00000000..78d1f9e5 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantRepository.php.bak @@ -0,0 +1,621 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\merchant; + + +use app\common\dao\system\merchant\MerchantDao; +use app\common\model\store\order\StoreOrder; +use app\common\model\store\product\ProductReply; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserVisitRepository; +use app\common\repositories\wechat\RoutineQrcodeRepository; +use crmeb\jobs\ClearMerchantStoreJob; +use crmeb\services\QrcodeService; +use crmeb\services\UploadService; +use crmeb\services\WechatService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\Exception; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class MerchantRepository + * @package app\common\repositories\system\merchant + * @mixin MerchantDao + * @author xaboy + * @day 2020-04-16 + */ +class MerchantRepository extends BaseRepository +{ + + /** + * MerchantRepository constructor. + * @param MerchantDao $dao + */ + public function __construct(MerchantDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function lst(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->setOption('field', []) + ->with([ + 'admin' => function ($query) { + $query->field('mer_id,account'); + }, + 'merchantCategory', + 'merchantType' + ]) + ->field('sort, mer_id, mer_name, real_name, mer_phone, mer_address, mark, status, create_time,is_best,is_trader,type_id,category_id,copy_product_num,export_dump_num,is_margin,margin,mer_avatar')->select(); + return compact('count', 'list'); + } + + public function count($where) + { + $where['status'] = 1; + $valid = $this->dao->search($where)->count(); + $where['status'] = 0; + $invalid = $this->dao->search($where)->count(); + return compact('valid', 'invalid'); + } + + /** + * @param int|null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-16 + */ + public function form(?int $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemMerchantCreate')->build() : Route::buildUrl('systemMerchantUpdate', ['id' => $id])->build()); + $is_margin = 0; + if ($formData && $formData['is_margin'] == 10) $is_margin = 1; + /** @var MerchantCategoryRepository $make */ + $make = app()->make(MerchantCategoryRepository::class); + $merchantTypeRepository = app()->make(MerchantTypeRepository::class); + $options = $merchantTypeRepository->getOptions(); + $margin = $merchantTypeRepository->getMargin(); + + $config = systemConfig(['broadcast_room_type', 'broadcast_goods_type']); + + $rule = [ + Elm::input('mer_name', '商户名称')->required(), + Elm::select('category_id', '商户分类')->options(function () use ($make) { + return $make->allOptions(); + })->requiredNum(), + + Elm::select('type_id', '店铺类型')->disabled($is_margin)->options($options)->requiredNum()->col(12)->control($margin), + + + Elm::input('mer_account', '商户账号')->required()->disabled(!is_null($id))->required(!is_null($id)), + Elm::password('mer_password', '登录密码')->required()->disabled(!is_null($id))->required(!is_null($id)), + Elm::input('real_name', '商户姓名'), + Elm::input('mer_phone', '商户手机号')->col(12)->required(), + Elm::number('commission_rate', '手续费(%)')->col(12), + Elm::input('mer_keyword', '商户关键字')->col(12), + Elm::input('mer_address', '商户地址'), + Elm::input('sub_mchid', '微信分账商户号'), + Elm::textarea('mark', '备注'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + $id ? Elm::hidden('status', 1) : Elm::switches('status', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_bro_room', '直播间审核', $config['broadcast_room_type'] == 1 ? 0 : 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_audit', '产品审核', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_bro_goods', '直播间商品审核', $config['broadcast_goods_type'] == 1 ? 0 : 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_best', '是否推荐')->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + Elm::switches('is_trader', '是否自营')->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + ]; + + $form->setRule($rule); + return $form->setTitle(is_null($id) ? '添加商户' : '编辑商户')->formData($formData); + } + + /** + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020/6/25 + */ + public function merchantForm(array $formData = []) + { + $form = Elm::createForm(Route::buildUrl('merchantUpdate')->build()); + $rule = [ + Elm::textarea('mer_info', '店铺简介')->required(), + Elm::input('service_phone', '服务电话')->required(), + Elm::frameImage('mer_banner', '店铺Banner(710*200px)', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=mer_banner&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]), + Elm::frameImage('mer_avatar', '店铺头像(120*120px)', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=mer_avatar&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]), + Elm::switches('mer_state', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开')->col(12), + ]; + $form->setRule($rule); + return $form->setTitle('编辑店铺信息')->formData($formData); + } + + /** + * @param $id + * @return Form + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function updateForm($id) + { + $data = $this->dao->get($id)->toArray(); + /** @var MerchantAdminRepository $make */ + $make = app()->make(MerchantAdminRepository::class); + $data['mer_account'] = $make->merIdByAccount($id); + $data['mer_password'] = '***********'; + if($data['category_id'] == 0){ + $data['category_id'] = ''; + } + if($data['type_id'] == 0){ + $data['type_id'] = ''; + } + return $this->form($id, $data); + } + + /** + * @param array $data + * @author xaboy + * @day 2020-04-17 + */ + public function createMerchant(array $data) + { + if ($this->fieldExists('mer_name', $data['mer_name'])) + throw new ValidateException('商户名已存在'); + if ($data['mer_phone'] && isPhone($data['mer_phone'])) + throw new ValidateException('请输入正确的手机号'); + $merchantCategoryRepository = app()->make(MerchantCategoryRepository::class); + $adminRepository = app()->make(MerchantAdminRepository::class); + + if (!$data['category_id'] || !$merchantCategoryRepository->exists($data['category_id'])) + throw new ValidateException('商户分类不存在'); + if ($adminRepository->fieldExists('account', $data['mer_account'])) + throw new ValidateException('账号已存在'); + + /** @var MerchantAdminRepository $make */ + $make = app()->make(MerchantAdminRepository::class); + + $margin = app()->make(MerchantTypeRepository::class)->get($data['type_id']); + $data['is_margin'] = $margin['is_margin'] ?? -1; + $data['margin'] = $margin['margin'] ?? 0; + return Db::transaction(function () use ($data, $make) { + $account = $data['mer_account']; + $password = $data['mer_password']; + unset($data['mer_account'], $data['mer_password']); + + $merchant = $this->dao->create($data); + $make->createMerchantAccount($merchant, $account, $password); + app()->make(ShippingTemplateRepository::class)->createDefault($merchant->mer_id); + app()->make(ProductCopyRepository::class)->defaulCopyNum($merchant->mer_id); + return $merchant; + }); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $where + * @param $page + * @param $limit + * @return array + */ + public function getList($where, $page, $limit, $userInfo) + { + $field = 'care_count,is_trader,type_id,mer_id,mer_banner,mini_banner,mer_name, mark,mer_avatar,product_score,service_score,postage_score,sales,status,is_best,create_time,long,lat,is_margin'; + $where['status'] = 1; + $where['mer_state'] = 1; + $where['is_del'] = 0; + if (isset($where['location'])) { + $data = @explode(',', (string)$where['location']); + if (2 != count(array_filter($data ?: []))) { + unset($where['location']); + } else { + $where['location'] = [ + 'lat' => (float)$data[0], + 'long' => (float)$data[1], + ]; + } + } + + if ($where['keyword'] !== '') { + app()->make(UserVisitRepository::class)->searchMerchant($userInfo ? $userInfo['uid'] : 0, $where['keyword']); + } + $query = $this->dao->search($where)->with(['type_name']); + $count = $query->count(); + $status = systemConfig('mer_location'); + $list = $query->page($page, $limit)->setOption('field', [])->field($field)->select() + ->each(function ($item) use ($status, $where) { + if ($status && $item['lat'] && $item['long'] && isset($where['location']['lat'], $where['location']['long'])) { + $distance = getDistance($where['location']['lat'], $where['location']['long'], $item['lat'], $item['long']); + if ($distance < 0.9) { + $distance = max(bcmul($distance, 1000, 0), 1).'m'; + if ($distance == '1m') { + $distance = '100m以内'; + } + } else { + $distance .= 'km'; + } + $item['distance'] = $distance; + } + $item['recommend'] = isset($where['delivery_way']) ? $item['CityRecommend'] : $item['AllRecommend']; + return $item; + }); + + return compact('count', 'list'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return array|Model|null + */ + public function merExists(int $id) + { + return ($this->dao->get($id)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @param $userInfo + * @return array|Model|null + */ + public function detail($id, $userInfo) + { + $merchant = $this->dao->apiGetOne($id)->hidden([ + "real_name", "mer_phone", "reg_admin_id", "sort", "is_del", "is_audit", "is_best", "mer_state", "bank", "bank_number", "bank_name", 'update_time', + 'financial_alipay', 'financial_bank', 'financial_wechat', 'financial_type','mer_take_phone' + ]); + $merchant->append(['type_name', 'isset_certificate', 'services_type']); + $merchant['care'] = false; + if ($userInfo) + $merchant['care'] = $this->getCareByUser($id, $userInfo->uid); + return $merchant; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $merId + * @param int $userId + * @return bool + */ + public function getCareByUser(int $merId, int $userId) + { + if (app()->make(UserRelationRepository::class)->getWhere(['type' => 10, 'type_id' => $merId, 'uid' => $userId])) + return true; + return false; + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $merId + * @param $where + * @param $page + * @param $limit + * @param $userInfo + * @return mixed + */ + public function productList($merId, $where, $page, $limit, $userInfo) + { + return app()->make(ProductRepository::class)->getApiSearch($merId, $where, $page, $limit, $userInfo); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param int $id + * @return mixed + */ + public function categoryList(int $id) + { + return app()->make(StoreCategoryRepository::class)->getApiFormatList($id, 1); + } + + public function wxQrcode($merId) + { + $siteUrl = systemConfig('site_url'); + $name = md5('mwx' . $merId . date('Ymd')) . '.jpg'; + $attachmentRepository = app()->make(AttachmentRepository::class); + $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]); + + if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) { + $imageInfo->delete(); + $imageInfo = null; + } + if (!$imageInfo) { + $codeUrl = rtrim($siteUrl, '/') . '/pages/store/home/index?id=' . $merId; //二维码链接 + if (systemConfig('open_wechat_share')) { + $qrcode = WechatService::create(false)->qrcodeService(); + $codeUrl = $qrcode->forever('_scan_url_mer_' . $merId)->url; + } + $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($codeUrl, $name); + if (is_string($imageInfo)) throw new ValidateException('二维码生成失败'); + + $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl); + + $attachmentRepository->create(systemConfig('upload_type') ?: 1, -2, $merId, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $urlCode = $imageInfo['dir']; + } else $urlCode = $imageInfo['attachment_src']; + return $urlCode; + } + + public function routineQrcode($merId) + { + $name = md5('smrt' . $merId . date('Ymd')) . '.jpg'; + return tidy_url(app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/store/home/index', 'id=' . $merId), 0); + } + + public function copyForm(int $id) + { + $form = Elm::createForm(Route::buildUrl('systemMerchantChangeCopy', ['id' => $id])->build()); + $form->setRule([ + Elm::input('copy_num', '复制次数', $this->dao->getCopyNum($id))->disabled(true)->readonly(true), + Elm::radio('type', '修改类型', 1) + ->setOptions([ + ['value' => 1, 'label' => '增加'], + ['value' => 2, 'label' => '减少'], + ]), + Elm::number('num', '修改数量', 0)->required() + ]); + return $form->setTitle('修改复制商品次数'); + } + + public function delete($id) + { + Db::transaction(function () use ($id) { + $this->dao->update($id, ['is_del' => 1]); + app()->make(MerchantAdminRepository::class)->deleteMer($id); + Queue::push(ClearMerchantStoreJob::class, ['mer_id' => $id]); + }); + } + + /** + * TODO 清理删除商户但没有删除的商品数据 + * @author Qinii + * @day 5/15/21 + */ + public function clearRedundancy() + { + $ret = (int)$this->dao->search(['is_del' => 1])->value('mer_id'); + if (!$ret) return; + try { + app()->make(ProductRepository::class)->clearMerchantProduct($ret); + app()->make(StoreCouponRepository::class)->getSearch([])->where('mer_id', $ret)->update(['is_del' => 1, 'status' => 0]); + app()->make(StoreCouponUserRepository::class)->getSearch([])->where('mer_id', $ret)->update(['is_fail' => 1, 'status'=>2]); + } catch (\Exception $exception) { + throw new ValidateException($exception->getMessage()); + } + } + + public function addLockMoney(int $merId, string $orderType, int $orderId, float $money) + { + if ($money <= 0) return; + if (systemConfig('mer_lock_time')) { + app()->make(UserBillRepository::class)->incBill($merId, 'mer_lock_money', $orderType, [ + 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId, + 'mer_id' => $merId, + 'status' => 0, + 'title' => '商户冻结余额', + 'number' => $money, + 'mark' => '商户冻结余额', + 'balance' => 0 + ]); + } else { + $this->dao->addMoney($merId, $money); + } + } + + public function checkCrmebNum(int $merId, string $type) + { + $merchant = $this->dao->get($merId); + switch ($type) { + case 'copy': + if (!systemConfig('copy_product_status')) { + throw new ValidateException('复制商品未开启'); + } + if (!$merchant['copy_product_num']) { + throw new ValidateException('复制商品剩余次数不足'); + } + break; + case 'dump': + if (!systemConfig('crmeb_serve_dump')) { + throw new ValidateException('电子面单未开启'); + } + if (!$merchant['export_dump_num']) { + throw new ValidateException('电子面单剩余次数不足'); + } + break; + } + return true; + } + + public function subLockMoney(int $merId, string $orderType, int $orderId, float $money) + { + if ($money <= 0) return; + $make = app()->make(UserBillRepository::class); + $bill = $make->search(['category' => 'mer_lock_money', 'type' => $orderType, 'mer_id' => $merId, 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId, 'status' => 0])->find(); + if (!$bill) { + $this->dao->subMoney($merId, $money); + } else { + $make->decBill($merId, 'mer_refund_money', $orderType, [ + 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId, + 'mer_id' => $merId, + 'status' => 1, + 'title' => '商户冻结余额退款', + 'number' => $money, + 'mark' => '商户冻结余额退款', + 'balance' => 0 + ]); + } + } + + public function computedLockMoney(StoreOrder $order) + { + Db::transaction(function () use ($order) { + $money = 0; + $make = app()->make(UserBillRepository::class); + $bill = $make->search(['category' => 'mer_lock_money', 'type' => 'order', 'link_id' => '1' . $order->order_id, 'status' => 0])->find(); + if ($bill) { + $money = bcsub($bill->number, $make->refundMerchantMoney($bill->link_id, $bill->type, $bill->mer_id), 2); + if ($order->presellOrder) { + $presellBill = $make->search(['category' => 'mer_lock_money', 'type' => 'presell', 'link_id' => '2' . $order->presellOrder->presell_order_id, 'status' => 0])->find(); + if ($presellBill) { + $money = bcadd($money, bcsub($presellBill->number, $make->refundMerchantMoney($presellBill->link_id, $presellBill->type, $presellBill->mer_id), 2), 2); + $presellBill->status = 1; + $presellBill->save(); + } + } + $bill->status = 1; + $bill->save(); + } + if ($money > 0) { + app()->make(UserBillRepository::class)->incBill($order->uid, 'mer_computed_money', 'order', [ + 'link_id' => $order->order_id, + 'mer_id' => $order->mer_id, + 'status' => 0, + 'title' => '商户待解冻余额', + 'number' => $money, + 'mark' => '交易完成,商户待解冻余额' . floatval($money) . '元', + 'balance' => 0 + ]); + } + }); + } + + public function checkMargin($merId, $typeId) + { + $merchant = $this->dao->get($merId); + $is_margin = 0; + $margin = 0; + if ($merchant['is_margin'] == 10) { + $margin = $merchant['margin']; + $is_margin = $merchant['is_margin']; + } else { + $marginData = app()->make(MerchantTypeRepository::class)->get($typeId); + + if ($marginData) { + $is_margin = $marginData['is_margin']; + $margin = $marginData['margin']; + } + } + return compact('is_margin', 'margin'); + } + + public function setMarginForm(int $id) + { + $merchant = $this->dao->get($id); + if ($merchant->is_margin !== 10) { + throw new ValidateException('商户无保证金可扣'); + } + $form = Elm::createForm(Route::buildUrl('systemMarginSet')->build()); + $form->setRule([ + Elm::input('mer_name', '商户名称', $merchant->mer_name)->disabled(true), + Elm::input('mer_id', '商户ID', $merchant->mer_id)->disabled(true), + Elm::input('margin', '商户剩余保证金', $merchant->margin)->disabled(true), + Elm::number('number', '保证金扣除金额', 0)->max($merchant->margin)->precision(2)->required(), + Elm::text('mark', '保证金扣除原因')->required(), + ]); + return $form->setTitle('扣除保证金'); + } + + /** + * TODO + * @param $data + * @return \think\response\Json + * @author Qinii + * @day 2/7/22 + */ + public function setMargin($data) + { + $merechant = $this->dao->get($data['mer_id']); + if ($merechant->is_margin !== 10) { + throw new ValidateException('商户未支付保证金或已申请退款'); + } + if ($data['number'] < 0) { + throw new ValidateException('扣除保证金额不能小于0'); + } + + if (bccomp($merechant->margin, $data['number'], 2) == -1) { + throw new ValidateException('扣除保证金额不足'); + } + + $data['balance'] = bcsub($merechant->margin, $data['number'], 2); + + Db::transaction(function () use ($merechant, $data) { + $merechant->margin = $data['balance']; + $merechant->save(); + app()->make(UserBillRepository::class)->bill(0, 'mer_margin', $data['type'], 0, $data); + }); + } + + public function changeDeliveryBalance($merId,$number) + { + $merechant = $this->dao->get($merId); + if (bccomp($merechant->delivery_balance, $number, 2) == -1) { + throw new ValidateException('余额不足,请先充值(配送费用:'.$number.'元)'); + } + Db::transaction(function () use ($merechant, $number) { + $merechant->delivery_balance = bcsub($merechant->delivery_balance, $number, 2); + $merechant->save(); + }); + } + + +} diff --git a/app/common/repositories/system/merchant/MerchantTypeRepository.php b/app/common/repositories/system/merchant/MerchantTypeRepository.php new file mode 100644 index 00000000..87595f78 --- /dev/null +++ b/app/common/repositories/system/merchant/MerchantTypeRepository.php @@ -0,0 +1,143 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\merchant; + + +use app\common\dao\system\merchant\MerchantTypeDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\auth\MenuRepository; +use app\common\repositories\system\RelevanceRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +/** + * @mixin MerchantTypeDao + */ +class MerchantTypeRepository extends BaseRepository +{ + public function __construct(MerchantTypeDao $dao) + { + $this->dao = $dao; + } + + public function getList($page, $limit) + { + $query = $this->dao->search()->with(['auth']); + $count = $query->count(); + $list = $query->page($page, $limit)->order('mer_type_id DESC')->select(); + foreach ($list as $item){ + $item['auth_ids'] = array_column($item['auth']->toArray(), 'right_id'); + unset($item['auth']); + } + return compact('count', 'list'); + } + + public function getSelect() + { + $query = $this->search([])->field('mer_type_id,type_name'); + return $query->select()->toArray(); + } + + public function delete(int $id) + { + return Db::transaction(function () use ($id) { + $this->dao->delete($id); + app()->make(MerchantRepository::class)->clearTypeId($id); + app()->make(RelevanceRepository::class)->batchDelete($id, RelevanceRepository::TYPE_MERCHANT_AUTH); + }); + } + + public function create(array $data) + { + return Db::transaction(function () use ($data) { + $auth = array_filter(array_unique($data['auth'])); + unset($data['auth']); + $type = $this->dao->create($data); + $inserts = []; + foreach ($auth as $id) { + $inserts[] = [ + 'left_id' => $type->mer_type_id, + 'right_id' => (int)$id, + 'type' => RelevanceRepository::TYPE_MERCHANT_AUTH + ]; + } + app()->make(RelevanceRepository::class)->insertAll($inserts); + return $type; + }); + } + + public function update(int $id, array $data) + { + return Db::transaction(function () use ($id, $data) { + $auth = array_filter(array_unique($data['auth'])); + + unset($data['auth']); + $inserts = []; + foreach ($auth as $aid) { + $inserts[] = [ + 'left_id' => $id, + 'right_id' => (int)$aid, + 'type' => RelevanceRepository::TYPE_MERCHANT_AUTH + ]; + } + $data['update_time'] = date('Y-m-d H:i:s',time()); + $this->dao->update($id, $data); + $make = app()->make(RelevanceRepository::class); + $make->batchDelete($id, RelevanceRepository::TYPE_MERCHANT_AUTH); + $make->insertAll($inserts); + //更新未交保证金的商户 + app()->make(MerchantRepository::class)->updateMargin($id, $data['margin'], $data['is_margin']); + }); + } + + public function markForm($id) + { + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $form = Elm::createForm(Route::buildUrl('systemMerchantTypeMark', ['id' => $id])->build()); + $form->setRule([ + Elm::text('mark', '备注', $data['mark'])->required(), + ]); + return $form->setTitle('修改备注'); + } + + public function mark($id, $data) + { + if (!$this->dao->getWhereCount([$this->dao->getPk() => $id])) + throw new ValidateException('数据不存在'); + $this->dao->update($id, $data); + } + + public function detail($id) + { + $find = $this->dao->search(['mer_type_id' => $id])->with(['auth'])->find(); + if (!$find) throw new ValidateException('数据不存在'); + $ids = array_column($find['auth']->toArray(), 'right_id'); + unset($find['auth']); + $options = []; + if ($ids) { + $paths = app()->make(MenuRepository::class)->getAllOptions(1, true,compact('ids'),'path'); + foreach ($paths as $id => $path) { + $ids = array_merge($ids, explode('/', trim($path, '/'))); + array_push($ids, $id); + } + $auth = app()->make(MenuRepository::class)->getAllOptions(1, true, compact('ids')); + $options = formatTree($auth, 'menu_name'); + } + + $find['options'] = $options; + return $find; + } +} diff --git a/app/common/repositories/system/notice/SystemNoticeConfigRepository.php b/app/common/repositories/system/notice/SystemNoticeConfigRepository.php new file mode 100644 index 00000000..a4772cb0 --- /dev/null +++ b/app/common/repositories/system/notice/SystemNoticeConfigRepository.php @@ -0,0 +1,278 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\notice; + + +use app\common\dao\system\notice\SystemNoticeConfigDao; +use app\common\repositories\BaseRepository; +use crmeb\exceptions\WechatException; +use crmeb\services\MiniProgramService; +use crmeb\services\WechatService; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +/** + * Class SystemNoticeConfigRepository + * @package app\common\repositories\system\notice + * @author xaboy + * @day 2020/11/6 + * @mixin SystemNoticeConfigDao + */ +class SystemNoticeConfigRepository extends BaseRepository +{ + public function __construct(SystemNoticeConfigDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page, $limit)->order('create_time ASC')->select(); + return compact('count', 'list'); + } + + public function form(?int $id) + { + $formData = []; + if ($id) { + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $formData = $data->toArray(); + $form = Elm::createForm(Route::buildUrl('systemNoticeConfigUpdate', ['id' => $id])->build()); + } else { + $form = Elm::createForm(Route::buildUrl('systemNoticeConfigCreate')->build()); + } + + $form->setRule([ + Elm::input('notice_title', '通知名称')->required(), + Elm::input('notice_info', '通知说明')->required(), + Elm::input('notice_key', '通知KEY')->required(), + Elm::radio('notice_sys', '站内消息', -1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ['value' => -1, 'label' => '无'], + ])->requiredNum(), + Elm::radio('notice_wechat', '公众号模板消息', -1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ['value' => -1, 'label' => '无'], + ])->requiredNum(), + Elm::radio('notice_routine', '小程序订阅消息', -1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ['value' => -1, 'label' => '无'], + ])->requiredNum(), + Elm::radio('notice_sms', '短信消息', -1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ['value' => -1, 'label' => '无'], + ])->requiredNum(), + Elm::radio('type', '通知类型', 0)->options([ + ['value' => 0, 'label' => '用户'], + ['value' => 1, 'label' => '商户'], + ])->requiredNum(), + Elm::textarea('sms_content','短信内容'), + Elm::textarea('wechat_content','公众号模板内容'), + Elm::textarea('routine_content','小程序订阅消息内容'), + ]); + + return $form->setTitle(is_null($id) ? '添加通知' : '编辑通知')->formData($formData); + } + + public function swithStatus($id, $filed, $status) + { + $data = $this->dao->get($id); + if ($data[$filed] == -1) throw new ValidateException('该消息无此通知类型'); + $data->$filed = $status; + $data->save(); + } + + /** + * TODO + * @param $key + * @return bool + * @author Qinii + * @day 11/19/21 + */ + public function getNoticeSys($key) + { + return $this->dao->getNoticeStatusByKey($key, 'notice_sys'); + } + + /** + * TODO + * @param $key + * @return bool + * @author Qinii + * @day 11/19/21 + */ + public function getNoticeSms($key) + { + return $this->dao->getNoticeStatusByKey($key, 'notice_sms'); + } + + /** + * TODO + * @param $key + * @return bool + * @author Qinii + * @day 11/19/21 + */ + public function getNoticeWechat($key) + { + return $this->dao->getNoticeStatusByKey($key, 'notice_wechat'); + } + + /** + * TODO + * @param $key + * @return bool + * @author Qinii + * @day 11/19/21 + */ + public function getNoticeRoutine($key) + { + return $this->dao->getNoticeStatusByKey($key, 'notice_routine'); + } + + public function getSmsTemplate(string $key) + { + $temp = $this->dao->getWhere(['const_key' => $key]); + + if ($temp && $temp['notice_sms'] == 1) { + return systemConfig('sms_use_type') == 2 ? $temp['sms_ali_tempid'] : $temp['sms_tempid']; + } + return ''; + } + + /** + * TODO 编辑消息模板ID + * @param $id + * @return \FormBuilder\Form + * @author Qinii + * @day 6/9/22 + */ + public function changeForm($id) + { + $formData = $this->dao->get($id); + if (!$formData) throw new ValidateException('数据不存在'); + $form = Elm::createForm(Route::buildUrl('systemNoticeConfigSetChangeTempId', ['id' => $id])->build()); + $children = []; + $value = ''; + if ($formData->notice_sms != -1) { + $value = 'sms'; + if (systemConfig('sms_use_type') == 2) { + $sms = [ + 'type' => 'el-tab-pane', + 'props' => [ + 'label' => '阿里云短信', + 'name' => 'sms' + ], + 'children' =>[ + Elm::input('title','通知类型', $formData->notice_title)->disabled(true), + Elm::input('info','场景说明', $formData->notice_info)->disabled(true), + Elm::input('sms_ali_tempid','短信模板ID'), + Elm::input('notice_info','短信说明')->disabled(true), + Elm::textarea('sms_content','短信内容')->disabled(true), + Elm::switches('notice_sms', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ] + ]; + } else { + $sms = [ + 'type' => 'el-tab-pane', + 'props' => [ + 'label' => '一号通短信', + 'name' => 'sms' + ], + 'children' =>[ + Elm::input('title','通知类型', $formData->notice_title)->disabled(true), + Elm::input('info','场景说明', $formData->notice_info)->disabled(true), + Elm::input('sms_tempid','短信模板ID'), + Elm::input('notice_info','短信说明')->disabled(true), + Elm::textarea('sms_content','短信内容')->disabled(true), + Elm::switches('notice_sms', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ] + ]; + } + $children[] = $sms; + } + if ($formData->notice_wechat != -1 && $formData->wechatTemplate ) { + if (!$value) $value = 'wechat'; + $children[] = [ + 'type' => 'el-tab-pane', + 'props' => [ + 'label' => '模板消息', + 'name' => 'wechat' + ], + 'children' =>[ + Elm::input('title1','通知类型', $formData->wechatTemplate->name)->disabled(true), + Elm::input('info1','场景说明', $formData->notice_info)->disabled(true), + Elm::input('wechat_tempkey','模板消息编号', $formData->wechatTemplate->tempkey)->disabled(true), + Elm::input('wechat_tempid','模板消息ID', $formData->wechatTemplate->tempid), + Elm::textarea('wechat_content','模板消息内容', $formData->wechatTemplate->content)->disabled(true), + Elm::switches('notice_wechat', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ] + ]; + } + if ($formData->notice_routine != -1 && $formData->routineTemplate) { + if (!$value) $value = 'routine'; + $children[] = [ + 'type' => 'el-tab-pane', + 'props' => [ + 'label' => '订阅消息', + 'name' => 'routine' + ], + 'children' =>[ + Elm::input('title2','通知类型', $formData->routineTemplate->name)->disabled(true), + Elm::input('info2','场景说明', $formData->notice_info)->disabled(true), + Elm::input('routine_tempkey','订阅消息编号', $formData->routineTemplate->tempkey)->disabled(true), + Elm::input('routine_tempid','订阅消息ID', $formData->routineTemplate->tempid), + Elm::textarea('routine_content','订阅消息内容', $formData->routineTemplate->content)->disabled(true), + Elm::switches('notice_routine', '是否开启', $formData->notice_routine)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ] + ]; + } + $form->setRule([ + [ + 'type' => 'el-tabs', + 'native' => true, + 'props' => [ + 'value' => $value + ], + 'children' => $children + ] + ]); + return $form->setTitle( '编辑消息模板')->formData($formData->toArray()); + } + + public function save($id, $data) + { + $result = $this->dao->get($id); + if (isset($data['routine_tempid'])) { + $result->routineTemplate->tempid = $data['routine_tempid']; + $result->routineTemplate->save(); + unset($data['routine_tempid']); + } + if (isset($data['wechat_tempid'])) { + $result->wechatTemplate->tempid = $data['wechat_tempid']; + $result->wechatTemplate->save(); + unset($data['wechat_tempid']); + } + if (!empty($data)) $this->dao->update($id,$data); + + } +} diff --git a/app/common/repositories/system/notice/SystemNoticeLogRepository.php b/app/common/repositories/system/notice/SystemNoticeLogRepository.php new file mode 100644 index 00000000..7fd088a1 --- /dev/null +++ b/app/common/repositories/system/notice/SystemNoticeLogRepository.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\notice; + + +use app\common\dao\system\notice\SystemNoticeLogDao; +use app\common\repositories\BaseRepository; + +/** + * Class SystemNoticeLogRepository + * @package app\common\repositories\system\notice + * @author xaboy + * @day 2020/11/6 + * @mixin SystemNoticeLogDao + */ +class SystemNoticeLogRepository extends BaseRepository +{ + public function __construct(SystemNoticeLogDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->order('A.notice_log_id DESC')->select(); + return compact('count', 'list'); + } + +} diff --git a/app/common/repositories/system/notice/SystemNoticeRepository.php b/app/common/repositories/system/notice/SystemNoticeRepository.php new file mode 100644 index 00000000..b032ca2f --- /dev/null +++ b/app/common/repositories/system/notice/SystemNoticeRepository.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\notice; + + +use app\common\dao\system\notice\SystemNoticeDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use think\exception\ValidateException; +use think\facade\Db; + +class SystemNoticeRepository extends BaseRepository +{ + public function __construct(SystemNoticeDao $dao) + { + $this->dao = $dao; + } + + public function create(array $data, $admin_id) + { + $data['admin_id'] = $admin_id; + + $merchantRepository = app()->make(MerchantRepository::class); + if ($data['type'] == 1) { + $ids = (array)$data['mer_id']; + $type_str = implode('/', $merchantRepository->names($ids)); + } else if ($data['type'] == 2) { + $ids = $merchantRepository->search(['is_trader' => (int)$data['is_trader']])->column('mer_id'); + $type_str = $data['is_trader'] ? '自营' : '非自营'; + } else if ($data['type'] == 3) { + $ids = $merchantRepository->search(['category_id' => (array)$data['category_id']])->column('mer_id'); + $type_str = implode('/', app()->make(MerchantCategoryRepository::class)->names((array)$data['category_id'])); + } else if ($data['type'] == 4) { + $ids = $merchantRepository->search([])->column('mer_id'); + $type_str = '全部'; + } else { + throw new ValidateException('商户类型有误'); + } + + if (!count($ids)) throw new ValidateException('没有有效的商户信息'); + $data['type_str'] = $type_str; + unset($data['is_trader'], $data['category_id'], $data['mer_id']); + + return Db::transaction(function () use ($data, $ids) { + $notice = $this->dao->create($data); + $systemNoticeLogRepository = app()->make(SystemNoticeLogRepository::class); + $inserts = []; + foreach ($ids as $id) { + if (!$id) continue; + $inserts[] = [ + 'mer_id' => (int)$id, + 'notice_id' => $notice->notice_id + ]; + } + $systemNoticeLogRepository->insertAll($inserts); + return $notice; + }); + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->order('notice_id DESC')->select(); + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/system/serve/ServeMealRepository.php b/app/common/repositories/system/serve/ServeMealRepository.php new file mode 100644 index 00000000..89065960 --- /dev/null +++ b/app/common/repositories/system/serve/ServeMealRepository.php @@ -0,0 +1,90 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\system\serve; + +use app\common\dao\system\serve\ServeMealDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +class ServeMealRepository extends BaseRepository +{ + protected $dao; + + public function __construct(ServeMealDao $dao) + { + $this->dao = $dao; + } + + + public function getList(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->getSearch($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + public function updateForm($id) + { + $data = $this->dao->get($id); + if(!$data) throw new ValidateException('数据不存在'); + $data = $data->toArray(); + return $this->form($id,$data); + } + + public function form($id = null, array $formData = []) + { + $isCreate = is_null($id); + $action = Route::buildUrl($isCreate ? 'systemServeMealCreate' : 'systemServeMealUpdate', $isCreate ? [] : compact('id'))->build(); + return Elm::createForm($action, [ + Elm::input('name', '套餐名称')->required(), + Elm::radio('type', '套餐类型 ',1)->options([ + ['value' => 1, 'label' => '一号通商品采集'], + ['value' => 2, 'label' => '一号通电子面单'], + ]), + Elm::number('price', '价格')->required(), + Elm::number('num', '数量')->required(), + Elm::radio('status', '状态', 1)->options([ + ['label' => '开启', 'value' => 1], + ['label' => '关闭', 'value' => 0] + ]), + Elm::number('sort', '排序')->required()->precision(0)->max(99999), + + ])->setTitle($isCreate ? '添加套餐' : '编辑套餐')->formData($formData); + } + + public function delete($id) + { + $data = $this->dao->get($id); + if(!$data) throw new ValidateException('数据不存在'); + $data->is_del = 1; + $data->save(); + } + + public function QrCode(int $merId, array $data) + { + $ret = $this->dao->get($data['meal_id']); + if(!$data) throw new ValidateException('数据不存在'); + $param = [ + 'status' => 0, + 'is_del' => 0, + 'mer_id' => $merId, + 'type' => $data['type'], + 'meal_id'=> $ret['meal_id'], + ]; + $this->dao->getSearch($param)->finid(); + + } +} diff --git a/app/common/repositories/system/serve/ServeOrderRepository.php b/app/common/repositories/system/serve/ServeOrderRepository.php new file mode 100644 index 00000000..77dce61d --- /dev/null +++ b/app/common/repositories/system/serve/ServeOrderRepository.php @@ -0,0 +1,234 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\system\serve; + +use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\AddShortUrlResponseBody\data; +use app\common\dao\system\serve\ServeOrderDao; +use app\common\model\system\serve\ServeOrder; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserRepository; +use crmeb\services\CombinePayService; +use crmeb\services\PayService; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Log; + +class ServeOrderRepository extends BaseRepository +{ + protected $dao; + + public function __construct(ServeOrderDao $dao) + { + $this->dao = $dao; + } + //复制商品 + const TYPE_COPY_PRODUCT = 1; + //电子面单 + const TYPE_DUMP = 2; + //保证金 margin + const TYPE_MARGIN = 10; + //同城配送delivery + const TYPE_DELIVERY = 20; + + + /** + * TODO 购买一号通 支付 + * @param $merId + * @param $data + * @return array + * @author Qinii + * @day 1/26/22 + */ + public function meal($merId, $data) + { + $ret = app()->make(ServeMealRepository::class)->get($data['meal_id']); + if(!$ret) throw new ValidateException('数据不存在'); + $key = 'Meal_'.$merId.'_'.$data['meal_id'].'_'.date('YmdH',time()); + $arr = [ + 'meal_id' => $ret['meal_id'], + 'name' => $ret['name'], + 'num' => $ret['num'], + 'price' => $ret['price'], + 'type' => $ret['type'], + ]; + $param = [ + 'status' => 0, + 'is_del' => 0, + 'mer_id' => $merId, + 'type' => $ret['type'], + 'meal_id'=> $ret['meal_id'], + 'pay_type' => $data['pay_type'], + 'attach' => 'meal', + 'order_info' => json_encode($arr,JSON_UNESCAPED_UNICODE), + 'pay_price' => $ret['price'], + ]; + return compact('key', 'param'); + } + + /** + * TODO 商户保证金 支付 + * @param $merId + * @param $data + * @return array + * @author Qinii + * @day 1/26/22 + */ + public function margin($merId, $data) + { + $ret = app()->make(MerchantRepository::class)->get($merId); + if ($ret['is_margin'] !== 1) throw new ValidateException('此商户无需支付保证金'); + $key = 'Margin_'.$merId.'_'.date('YmdH',time()); + $arr = [ + 'type_id' => $ret['type_id'], + 'is_margin' => $ret['is_margin'], + 'margin' => $ret['margin'], + ]; + $param = [ + 'status' => 0, + 'is_del' => 0, + 'mer_id' => $merId, + 'type' => 10, + 'meal_id'=> $ret['type_id'], + 'pay_type' => $data['pay_type'], + 'attach' => 'meal', + 'order_info' => json_encode($arr,JSON_UNESCAPED_UNICODE), + 'pay_price' => $ret['margin'], + ]; + + return compact('key', 'param'); + } + + public function delivery($merId, $data) + { + $key = 'Delivery_'.$merId.'_'.md5(date('YmdH',time()).$data['price']); + $arr = ['price' => $data['price']]; + $param = [ + 'status' => 0, + 'is_del' => 0, + 'mer_id' => $merId, + 'type' => 20, + 'meal_id'=> 0, + 'pay_type' => $data['pay_type'], + 'attach' => 'meal', + 'order_info' => json_encode($arr,JSON_UNESCAPED_UNICODE), + 'pay_price' => $data['price'], + ]; + + return compact('key', 'param'); + } + + public function QrCode(int $merId, string $type, array $data) + { + $res = $this->{$type}($merId, $data); + $key = $res['key']; + $param = $res['param']; + + if(!$result = Cache::store('file')->get($key)){ + $order_sn = app()->make(StoreOrderRepository::class)->getNewOrderId('cs'); + $param['order_sn'] = $order_sn; + $param['body'] = $order_sn; + $payType = $data['pay_type'] == 1 ? 'weixinQr' : 'alipayQr'; + $service = new PayService($payType,$param); + $code = $service->pay(null); + + $endtime = time() + 1800 ; + $result = [ + 'config' => $code['config'], + 'endtime'=> date('Y-m-d H:i:s',$endtime), + 'price' => $param['pay_price'] + ]; + Cache::store('file')->set($key,$result,30); + $param['key'] = $key; + Cache::store('file')->set($order_sn,$param,60 * 24); + } + + return $result; + } + + public function paySuccess($data) + { + $get = $this->dao->getWhere(['order_sn' => $data['order_sn']]); + if(!$get){ + $dat = Cache::store('file')->get($data['order_sn']); + $key = $dat['key']; + unset($dat['attach'],$dat['body'],$dat['key']); + + $dat['status'] = 1; + $dat['pay_time'] = date('y_m-d H:i:s', time()); + Db::transaction(function () use($data, $dat,$key){ + $res = $this->dao->create($dat); + $this->payAfter($dat,$res); + Cache::store('file')->delete($data['order_sn']); + Cache::store('file')->delete($key); + }); + } + } + + public function payAfter($dat, $ret = null) + { + $info = json_decode($dat['order_info']); + switch ($dat['type']) { + case self::TYPE_COPY_PRODUCT: + app()->make(ProductCopyRepository::class)->add([ + 'type' => 'pay_copy', + 'num' => $info->num, + 'info' => $dat['order_info'], + 'message' => '购买复制商品套餐' , + ],$dat['mer_id']); + break; + case self::TYPE_DUMP: + app()->make(ProductCopyRepository::class)->add(['type' => 'pay_dump', 'num' => $info->num, 'info' => $dat['order_info'], 'message' => '购买电子面单套餐',],$dat['mer_id']); + break; + case self::TYPE_MARGIN: + $res = app()->make(MerchantRepository::class)->get($dat['mer_id']); + if (bccomp($res['margin'] , $dat['pay_price'], 2) === 0) { + $res->ot_margin = $res['margin']; + $res->is_margin = 10; + } else { + $res->is_margin = 20; + } + $res->save(); + break; + case self::TYPE_DELIVERY: + $res = app()->make(MerchantRepository::class)->get($dat['mer_id']); + if ($res) { + $res->delivery_balance = bcadd($res->delivery_balance, $dat['pay_price'],2); + $res->save(); + } else { + Log::info('同城配送充值异常 :'. json_encode($dat)); + } + break; + default: + break; + } + return ; + } + + + public function getList(array $where, int $page, int $limit) + { + $where['is_del'] = 0; + $query = $this->dao->search($where)->with([ + 'merchant' => function($query){ + $query->with(['merchantType']); + $query->field('mer_id,mer_name,is_trader,mer_avatar,type_id,mer_phone,mer_address,is_margin,margin,real_name,ot_margin'); + } + ])->order('ServeOrder.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } +} diff --git a/app/common/repositories/system/sms/SmsRecordRepository.php b/app/common/repositories/system/sms/SmsRecordRepository.php new file mode 100644 index 00000000..0e4294db --- /dev/null +++ b/app/common/repositories/system/sms/SmsRecordRepository.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\system\sms; + + +use app\common\dao\system\sms\SmsRecordDao; +use app\common\repositories\BaseRepository; +use crmeb\services\YunxinSmsService; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class SmsRecordRepository + * @package app\common\repositories\system\sms + * @author xaboy + * @day 2020-05-18 + * @mixin SmsRecordDao + */ +class SmsRecordRepository extends BaseRepository +{ + /** + * @var SmsRecordDao + */ + protected $dao; + + /** + * 短信状态 + * @var array + */ + protected static $resultcode = ['100' => '成功', '130' => '失败', '131' => '空号', '132' => '停机', '133' => '关机', '134' => '无状态']; + + + /** + * SmsRecordRepository constructor. + * @param SmsRecordDao $dao + */ + public function __construct(SmsRecordDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-18 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->toArray(); + return compact('list', 'count'); + } + +} diff --git a/app/common/repositories/user/FeedBackCategoryRepository.php b/app/common/repositories/user/FeedBackCategoryRepository.php new file mode 100644 index 00000000..967394e2 --- /dev/null +++ b/app/common/repositories/user/FeedBackCategoryRepository.php @@ -0,0 +1,62 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\user; + + +use app\common\dao\user\FeedbackCateoryDao as dao; +use app\common\repositories\BaseRepository; +use crmeb\traits\CategoresRepository; +use FormBuilder\Form; +use think\facade\Route; +use FormBuilder\Factory\Elm; + +class FeedBackCategoryRepository extends BaseRepository +{ + use CategoresRepository; + /** + * @param FeedbackDao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + public function form(int $merId, $id = null, array $formData = []) + { + $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemUserFeedBackCategoryCreate')->build() : Route::buildUrl('systemUserFeedBackCategoryUpdate', ['id' => $id])->build()); + $form->setRule([ + Elm::cascader('pid','上级分类')->options(function()use($id,$merId){ + $menus = $this->dao->getAllOptions(null); + if ($id && isset($menus[$id])) unset($menus[$id]); + $menus = formatCascaderData($menus, 'cate_name'); + array_unshift($menus, ['label' => '顶级分类', 'value' => 0]); + return $menus; + })->props(['props' => ['checkStrictly' => true, 'emitPath' => false]]), + Elm::input('cate_name', '分类名称')->required(), + Elm::switches('is_show','是否显示', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + Elm::number('sort', '排序', 0)->precision(0)->max(99999), + ]); + + return $form->setTitle(is_null($id) ? '添加分类' : '编辑分类')->formData($formData); + } + + public function updateForm(int $merId,int $id) + { + return $this->form($merId,$id,$this->dao->get($id)->toArray()); + } + + public function switchStatus(int $id,int $status) + { + $this->dao->update($id,['is_show' => $status]); + } +} diff --git a/app/common/repositories/user/FeedbackRepository.php b/app/common/repositories/user/FeedbackRepository.php new file mode 100644 index 00000000..7ed2441d --- /dev/null +++ b/app/common/repositories/user/FeedbackRepository.php @@ -0,0 +1,75 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\FeedbackDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +/** + * Class FeedbackRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020/5/28 + * @mixin FeedbackDao + */ +class FeedbackRepository extends BaseRepository +{ + /** + * FeedbackRepository constructor. + * @param FeedbackDao $dao + */ + public function __construct(FeedbackDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with(['type' => function($query){ + $query->field('feedback_category_id,cate_name'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->withAttr('images',function($val){ + return $val ? json_decode($val, true) : []; + })->select(); + return compact('count', 'list'); + } + + public function get( $id) + { + $data = $this->dao->getWhere([$this->dao->getPk() => $id]); + $type = app()->make(FeedBackCategoryRepository::class)->getWhere(['feedback_category_id' => $data['type']]); + $parent = app()->make(FeedBackCategoryRepository::class)->getWhere(['feedback_category_id' => $type['pid']]); + $data['type'] = $type['cate_name']; + $data['category'] = $parent['cate_name']; + return $data; + } + + public function replyForm($id) + { + $formData = $this->dao->get($id); + if (!$formData) throw new ValidateException('数据不存在'); + if ($formData->status == 1) throw new ValidateException('该问题已回复过了'); + $form = Elm::createForm(Route::buildUrl('systemUserFeedBackReply',['id' => $id])->build()); + $form->setRule([ + Elm::textarea('reply', '回复内容'), + ]); + return $form->setTitle('回复用户')->formData($formData->toArray()); + } + +} diff --git a/app/common/repositories/user/LabelRuleRepository.php b/app/common/repositories/user/LabelRuleRepository.php new file mode 100644 index 00000000..deb1f091 --- /dev/null +++ b/app/common/repositories/user/LabelRuleRepository.php @@ -0,0 +1,144 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\LabelRuleDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\facade\Db; + +/** + * Class LabelRuleRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020/10/20 + * @mixin LabelRuleDao + */ +class LabelRuleRepository extends BaseRepository +{ + /** + * LabelRuleRepository constructor. + * @param LabelRuleDao $dao + */ + public function __construct(LabelRuleDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->with(['label'])->order('label_rule_id DESC')->page($page, $limit)->select()->toArray(); + return compact('count', 'list'); + } + + /** + * @param $data + * @return mixed + * @author xaboy + * @day 2020/10/21 + */ + public function create($data) + { + return Db::transaction(function () use ($data) { + $labelName = $data['label_name']; + unset($data['label_name']); + $label = app()->make(UserLabelRepository::class)->create([ + 'label_name' => $labelName, + 'mer_id' => $data['mer_id'], + 'type' => 1 + ]); + $data['label_id'] = $label->label_id; + return $this->dao->create($data); + }); + } + + /** + * @param $id + * @param $data + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/10/21 + */ + public function update($id, $data) + { + $rule = $this->dao->get($id); + + return Db::transaction(function () use ($data, $rule) { + $labelName = $data['label_name']; + unset($data['mer_id'], $data['label_name']); + app()->make(UserLabelRepository::class)->update($rule->label_id, ['label_name' => $labelName]); + return $rule->save($data); + }); + } + + /** + * @param $id + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/10/21 + */ + public function delete($id) + { + $rule = $this->dao->get($id); + return Db::transaction(function () use ($rule) { + app()->make(UserLabelRepository::class)->delete($rule->label_id); + app()->make(UserRepository::class)->rmLabel($rule->label_id); + return $rule->delete(); + }); + } + + /** + * @param $id + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/10/21 + */ + public function syncUserNum($id) + { + $rule = $this->dao->get($id); + $rule->update_time = date('Y-m-d H:i:s'); + $ids = []; + $userMerchantRepository = app()->make(UserMerchantRepository::class); + //订单金额 + if ($rule->type == 1) { + $ids = $userMerchantRepository->priceUserIds($rule->mer_id, $rule->min, $rule->max); + //订单数 + } else if ($rule->type == 0) { + $ids = $userMerchantRepository->numUserIds($rule->mer_id, $rule->min, $rule->max); + } + $rule->user_num = count($ids); + $idList = array_chunk($ids, 50); + Db::transaction(function () use ($rule, $idList, $userMerchantRepository) { + $userMerchantRepository->rmLabel($rule->label_id); + foreach ($idList as $ids) { + $userMerchantRepository->search(['uids' => $ids])->update([ + 'A.label_id' => Db::raw('trim(BOTH \',\' FROM CONCAT(IFNULL(A.label_id,\'\'),\',' . $rule->label_id . '\'))') + ]); + } + $rule->save(); + }); + } + +} diff --git a/app/common/repositories/user/MemberinterestsRepository.php b/app/common/repositories/user/MemberinterestsRepository.php new file mode 100644 index 00000000..32376369 --- /dev/null +++ b/app/common/repositories/user/MemberinterestsRepository.php @@ -0,0 +1,149 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\MemberInterestsDao; +use app\common\dao\user\UserBrokerageDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Route; + +/** + * @mixin UserBrokerageDao + */ +class MemberinterestsRepository extends BaseRepository +{ + + const TYPE_FREE = 1; + //付费会员 + const TYPE_SVIP = 2; + + const HAS_TYPE_PRICE = 1; + + const HAS_TYPE_SIGN = 2; + + const HAS_TYPE_PAY = 3; + + const HAS_TYPE_SERVICE = 4; + + const HAS_TYPE_MEMBER = 5; + + const HAS_TYPE_COUPON = 6; + + //签到收益 + const INTERESTS_TYPE = [ + 1 => ['label'=> '会员特价', 'msg' => ''], + 2 => ['label'=> '签到返利' , 'msg' => '积分倍数' ], + 3 => ['label'=> '消费返利' , 'msg' => '积分倍数' ], + 4 => ['label'=> '专属客服' , 'msg' => '' ], + 5 => ['label'=> '经验翻倍' , 'msg' => '经验翻倍' ], + 6 => ['label'=> '会员优惠券', 'msg' => ''], + ]; + + public function __construct(MemberInterestsDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, int $page, int $limit) + { + $query = $this->dao->getSearch($where); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count','list'); + } + + public function getSvipInterestVal($has_type) + { + return max(((float)$this->dao->query(['status' => 1])->where('has_type', $has_type)->where('type', 2)->value('value')) ?: 0, 0); + } + + public function form(?int $id = null, $type = self::TYPE_FREE) + { + $formData = []; + if ($id) { + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $form = Elm::createForm(Route::buildUrl('systemUserMemberInterestsUpdate', ['id' => $id])->build()); + $formData = $data->toArray(); + } else { + $form = Elm::createForm(Route::buildUrl('systemUserMemberInterestsCreate')->build()); + } + $rules = [ + Elm::input('name', '权益名称')->required(), + Elm::input('info', '权益简介')->required(), + Elm::frameImage('pic', '图标', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=pic&type=1') + ->value($formData['pic'] ?? '') + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::select('brokerage_level', '会员级别')->options(function () use($type){ + $options = app()->make(UserBrokerageRepository::class)->options(['type' => $type])->toArray(); + return $options; + }), + ]; + $form->setRule($rules); + return $form->setTitle(is_null($id) ? '添加权益' : '编辑权益')->formData($formData); + } + + public function getInterestsByLevel(int $type, $level = 0) + { + if ($type == self::TYPE_FREE) { + $list = $this->dao->getSearch(['type' => $type])->select(); + foreach ($list as $item) { + $item['status'] = 0; + if ($item['brokerage_level'] <= $level) { + $item['status'] = 1; + } + } + } else { + $list = $this->dao->getSearch(['type' => $type,'status' => 1])->select(); + } + return $list; + } + + public function svipForm(int $id) + { + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $form = Elm::createForm(Route::buildUrl('systemUserSvipInterestsUpdate', ['id' => $id])->build()); + $formData = $data->toArray(); + $rules = [ + Elm::select('has_type', '权益名称')->options(function(){ + foreach (self::INTERESTS_TYPE as $k => $v) { + $res[] = ['value' => $k, 'label' => $v['label']]; + } + return $res; + })->disabled(true), + Elm::input('name', '展示名称')->required(), + Elm::input('info', '权益简介')->required(), + Elm::frameImage('pic', '未开通图标', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=pic&type=1') + ->value($formData['pic'] ?? '')->required() + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::frameImage('on_pic', '已开通图标', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=on_pic&type=1') + ->value($formData['on_pic'] ?? '')->required() + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::input('link', '跳转内部链接'), + ]; + $msg = self::INTERESTS_TYPE[$formData['has_type']]['msg']; + if ($msg) $rules[] = Elm::number('value',$msg,0); + $form->setRule($rules); + return $form->setTitle('编辑会员权益')->formData($formData); + } +} diff --git a/app/common/repositories/user/UserAddressRepository.php b/app/common/repositories/user/UserAddressRepository.php new file mode 100644 index 00000000..89a8891a --- /dev/null +++ b/app/common/repositories/user/UserAddressRepository.php @@ -0,0 +1,120 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + +use app\common\repositories\BaseRepository; +use app\common\dao\user\UserAddressDao as dao; +use app\common\repositories\store\shipping\CityRepository; + +/** + * Class UserAddressRepository + * @package app\common\repositories\user + * @day 2020/6/3 + * @mixin dao + */ +class UserAddressRepository extends BaseRepository +{ + /** + * @var dao + */ + protected $dao; + + + /** + * UserAddressRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + + /** + * @param int $id + * @param int $uid + * @return bool + * @author Qinii + */ + public function fieldExists(int $id,int $uid) + { + return $this->dao->userFieldExists($this->dao->getPk(),$id,$uid); + } + + /** + * @param int $uid + * @return bool + * @author Qinii + */ + public function defaultExists(int $uid) + { + return $this->dao->userFieldExists('is_default',1,$uid); + } + + /** + * @param int $id + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author Qinii + */ + public function checkDefault(int $id) + { + $res = $this->dao->getWhere([$this->dao->getPk() => $id]); + return $res['is_default']; + } + + /** + * @param $province + * @param $city + * @return mixed + * @author Qinii + */ + public function getCityId($province,$city) + { + $make = app()->make(CityRepository::class); + $provinceData = $make->getWhere(['name' => $province]); + $cityData = $make->getWhere(['name' => $city,'parent_id' => $provinceData['city_id']]); + if(!$cityData)$cityData = $make->getWhere([['name','like','直辖'.'%'],['parent_id' ,'=', $provinceData['city_id']]]); + return $cityData['city_id']; + } + + /** + * @param $uid + * @param $page + * @param $limit + * @return array + * @author Qinii + */ + public function getList($uid) + { + $list = $this->dao->getAll($uid)->order('is_default desc')->select(); + return compact('list'); + } + + /** + * @param $id + * @param $uid + * @return array|\think\Model|null + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author Qinii + */ + public function get($id,$uid) + { + return $this->dao->getWhere(['address_id' => $id,'uid' => $uid])->append(['area']); + } +} diff --git a/app/common/repositories/user/UserBillRepository.php b/app/common/repositories/user/UserBillRepository.php new file mode 100644 index 00000000..467073d2 --- /dev/null +++ b/app/common/repositories/user/UserBillRepository.php @@ -0,0 +1,266 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\BaseDao; +use app\common\dao\user\UserBillDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductRepository; +use crmeb\jobs\SendSmsJob; +use think\facade\Queue; +use think\Model; + +/** + * Class UserBillRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020-05-07 + * @mixin UserBillDao + */ +class UserBillRepository extends BaseRepository +{ + /** + * @var UserBillDao + */ + protected $dao; + + const TYPE_INFO = [ + 'brokerage/now_money' => '佣金转入余额', + 'brokerage/order_one' => '获得一级推广佣金', + 'brokerage/order_two' => '获得二级推广佣金', + 'brokerage/refund_one' => '退还一级佣金', + 'brokerage/refund_two' => '退还二级佣金', + 'integral/cancel' => '退回积分', + 'integral/deduction' => '购买商品', + 'integral/lock' => '下单赠送积分', + 'integral/refund' => '订单退款', + 'integral/refund_lock' => '扣除赠送积分', + 'integral/sign_integral' => '签到赠送积分', + 'integral/spread' => '邀请好友', + 'integral/sys_dec' => '系统减少积分', + 'integral/sys_inc' => '系统增加积分', + 'integral/timeout' => '积分过期', + 'mer_integral/deduction' => '积分抵扣', + 'mer_integral/refund' => '订单退款', + 'mer_lock_money/order' => '商户佣金冻结', + 'now_money/brokerage' => '佣金转入余额', + 'now_money/pay_product' => '购买商品', + 'now_money/presell' => '支付预售尾款', + 'now_money/recharge' => '余额充值', + 'now_money/sys_dec_money' => '系统减少余额', + 'now_money/sys_inc_money' => '系统增加余额', + ]; + + /** + * UserBillRepository constructor. + * @param UserBillDao $dao + */ + public function __construct(UserBillDao $dao) + { + $this->dao = $dao; + } + + public function userList($where, $uid, $page, $limit) + { + $where['uid'] = $uid; + $query = $this->dao->search($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->setOption('field', [])->field('bill_id,pm,title,number,balance,mark,create_time,status')->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function month(array $where) + { + $group = $this->dao->search($where)->field('FROM_UNIXTIME(unix_timestamp(create_time),"%Y-%m") as time') + ->order('time DESC')->group('time')->select(); + $ret = []; + foreach ($group as $k => $item){ + $ret[$k]['month'] = $item['time']; + $query = $this->dao->getSearch($where)->field('title,number,create_time')->whereMonth('create_time',$item['time']); + $ret[$k]['list'] = $query->order('create_time DESC')->select(); + } + return $ret; + } + + public function getList($where, $page, $limit) + { + $query = $this->dao->searchJoin($where)->order('a.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function getLst($where, $page, $limit) + { + $query = $this->dao->search($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @param int $uid + * @param string $category + * @param string $type + * @param int $pm + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-05-07 + */ + public function bill(int $uid, string $category, string $type, int $pm, array $data) + { + $data['category'] = $category; + $data['type'] = $type; + $data['uid'] = $uid; + $data['pm'] = $pm; + $bill = $this->dao->create($data); + if($category == 'now_money'){ + Queue::push(SendSmsJob::class,['tempId' => 'USER_BALANCE_CHANGE','id' => $bill->bill_id]); + } + return $bill; + } + + /** + * @param int $uid + * @param string $category + * @param string $type + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-05-07 + */ + public function incBill(int $uid, string $category, string $type, array $data) + { + return $this->bill($uid, $category, $type, 1, $data); + } + + /** + * @param int $uid + * @param string $category + * @param string $type + * @param array $data + * @return BaseDao|Model + * @author xaboy + * @day 2020-05-07 + */ + public function decBill(int $uid, string $category, string $type, array $data) + { + return $this->bill($uid, $category, $type, 0, $data); + } + + public function type() + { + $data = []; + foreach (self::TYPE_INFO as $type => $title) { + $data[] = compact('type', 'title'); + } + return $data; + } + + /** + * TODO 积分日志头部统计 + * @return array + * @author Qinii + * @day 6/9/21 + */ + public function getStat($merId = 0) + { + if($merId){ + $isusd = app()->make(ProductRepository::class)->getSearch(['mer_id' => $merId])->sum('integral_total'); + $refund = $this->dao->search(['category' => 'mer_integral','type' => 'refund','mer_id' => $merId])->sum('number'); + $numb = app()->make(ProductRepository::class)->getSearch(['mer_id' => $merId])->sum('integral_price_total'); + return [ + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $isusd, + 'field' => '个', + 'name' => '已使用积分(分)' + ], + [ + 'className' => 'el-icon-edit', + 'count' => $refund, + 'field' => '次', + 'name' => '退款订单返回积分(分)' + ], + [ + 'className' => 'el-icon-edit', + 'count' => $numb, + 'field' => '次', + 'name' => '积分抵扣金额(元)' + ], + ]; + } + // 总积分 + $integral = app()->make(UserRepository::class)->search(['status' => 1])->sum('integral'); + // 客户签到次数 + $sign = app()->make(UserSignRepository::class)->getSearch([])->count('*'); + // 签到送出积分 + $sign_integral = $this->dao->search(['type' => 'sign_integral'])->sum('number'); + // 使用积分 + $isusd = $this->dao->search(['category' => 'integral','type' => 'deduction'])->sum('number'); + $refund = $this->dao->search(['category' => 'mer_integral','type' => 'refund'])->sum('number'); + $order = $isusd - $refund; + + // 下单赠送积分 + $order_integral1 = $this->dao->search(['category' => 'integral','type' => 'lock'])->sum('number'); + $order_integral2 = $this->dao->search(['category' => 'integral','type' => 'refund_lock'])->sum('number'); + $order_integral = $order_integral1 - $order_integral2; + $order_integral = $order_integral < 0 ? 0 : $order_integral; + // 冻结积分 + $freeze_integral = $this->dao->lockIntegral(); + + return [ + [ + 'className' => 'el-icon-s-cooperation', + 'count' => $integral, + 'field' => '个', + 'name' => '总积分' + ], + [ + 'className' => 'el-icon-edit', + 'count' => $sign, + 'field' => '次', + 'name' => '客户签到次数' + ], + [ + 'className' => 'el-icon-s-goods', + 'count' => $sign_integral , + 'field' => '个', + 'name' => '签到送出积分' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $order, + 'field' => '个', + 'name' => '使用积分' + ], + [ + 'className' => 'el-icon-present', + 'count' => $order_integral, + 'field' => '个', + 'name' => '下单赠送积分' + ], + [ + 'className' => 'el-icon-warning', + 'count' => $freeze_integral, + 'field' => '', + 'name' => '冻结积分' + ], + ]; + } + + +} diff --git a/app/common/repositories/user/UserBrokerageRepository.php b/app/common/repositories/user/UserBrokerageRepository.php new file mode 100644 index 00000000..970c58cf --- /dev/null +++ b/app/common/repositories/user/UserBrokerageRepository.php @@ -0,0 +1,259 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserBrokerageDao; +use app\common\model\user\User; +use app\common\model\user\UserBrokerage; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\CacheRepository; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Route; + +/** + * @mixin UserBrokerageDao + */ +class UserBrokerageRepository extends BaseRepository +{ + + public const BROKERAGE_RULE_TYPE = ['spread_user', 'pay_money', 'pay_num', 'spread_money', 'spread_pay_num']; + + public function __construct(UserBrokerageDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->order('brokerage_level DESC,create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('list', 'count'); + } + + public function getNextLevel($level,$type = 0) + { + return $this->search(['next_level' => $level,'type' => $type])->order('brokerage_level ASC,create_time DESC')->find(); + } + + public function options(array $where) + { + return $this->dao->search($where)->field('brokerage_level as value,brokerage_name as label')->order('brokerage_level ASC,create_time DESC')->select(); + } + + public function all(int $type) + { + return $this->dao->search(['type' => $type])->order('brokerage_level ASC,create_time DESC')->select(); + } + + public function inc(User $user, $type, $inc) + { + $nextLevel = $this->getNextLevel($user->brokerage_level); + if (!$nextLevel) return false; + $make = app()->make(UserBillRepository::class); + $bill = $make->getWhere(['uid' => $user->uid, 'link_id' => $nextLevel->user_brokerage_id, 'category' => 'sys_brokerage', 'type' => $type]); + if ($bill) { + $bill->number = bcadd($bill->number, $inc, 2); + $bill->save(); + } else { + $make->incBill($user->uid, 'sys_brokerage', $type, [ + 'number' => $inc, + 'title' => $type, + 'balance' => 0, + 'status' => 0, + 'link_id' => $nextLevel->user_brokerage_id + ]); + } + + return $this->checkLevel($user, $nextLevel); + } + + public function checkLevel(User $user, UserBrokerage $nextLevel) + { + $info = app()->make(UserBillRepository::class)->search(['uid' => $user->uid, 'category' => 'sys_brokerage', 'link_id' => $nextLevel->user_brokerage_id]) + ->column('number', 'type'); + foreach ($nextLevel['brokerage_rule'] as $k => $rule) { + if (!isset($info[$k]) && $rule['num'] > 0) return false; + if ($rule['num'] > 0 && $rule['num'] > $info[$k]) return false; + } + $nextLevel->user_num++; + Db::transaction(function () use ($nextLevel, $user) { + $nextLevel->save(); + if ($user->brokerage && $user->brokerage->user_num > 0) { + $user->brokerage->user_num--; + $user->brokerage->save(); + } + $user->brokerage_level = $nextLevel->brokerage_level; + $user->save(); + + $key = 'notice_brokerage_level_' . $user->uid; + app()->make(CacheRepository::class)->save($key,$nextLevel->brokerage_level); + }); + return true; + } + + public function getLevelRate(User $user, UserBrokerage $nextLevel) + { + $info = app()->make(UserBillRepository::class)->search(['uid' => $user->uid, 'category' => 'sys_brokerage', 'link_id' => $nextLevel->user_brokerage_id]) + ->column('number', 'type'); + $brokerage_rule = $nextLevel['brokerage_rule']; + foreach ($nextLevel['brokerage_rule'] as $k => $rule) { + if ($rule['num'] <= 0) { + unset($brokerage_rule[$k]); + continue; + } + if (!isset($info[$k])) { + $rate = 0; + } else if ($rule['num'] > $info[$k]) { + $rate = bcdiv($info[$k], $rule['num'], 2) * 100; + } else { + $rate = 100; + } + $brokerage_rule[$k]['rate'] = $rate; + $brokerage_rule[$k]['task'] = (float)(min($info[$k] ?? 0, $rule['num'])); + } + return $brokerage_rule; + } + + public function form(?int $id = null) + { + $formData = []; + if ($id) { + $form = Elm::createForm(Route::buildUrl('systemUserMemberUpdate', ['id' => $id])->build()); + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + $formData = $data->toArray(); + + } else { + $form = Elm::createForm(Route::buildUrl('systemUserMemberCreate')->build()); + } + + $rules = [ + Elm::number('brokerage_level', '会员等级')->required(), + Elm::input('brokerage_name', '会员名称')->required(), + Elm::frameImage('brokerage_icon', '会员图标', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=brokerage_icon&type=1') + ->required() + ->value($formData['brokerage_icon'] ?? '') + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::number('value', ' 所需成长值',$formData['brokerage_rule']['value'] ?? 0)->required(), + Elm::frameImage('image', '背景图', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=image&type=1') + ->value($formData['brokerage_rule']['image']??'') + ->required() + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + ]; + $form->setRule($rules); + return $form->setTitle(is_null($id) ? '添加会员等级' : '编辑会员等级')->formData($formData); + } + + public function incMemberValue(int $uid, string $type, int $id) + { + if (!systemConfig('member_status')) return ; + $make = app()->make(UserBillRepository::class); + $count = $make->getWhereCount(['type' => $type, 'link_id' => $id]); + if ($count) return ; + $config = [ + 'member_pay_num' => '下单获得成长值', + 'member_sign_num' => '签到获得成长值', + 'member_reply_num' => '评价获得成长值', + 'member_share_num' => '邀请获得成长值', + 'member_community_num' => '种草图文获得成长值', + ]; + $inc = systemConfig($type) > 0 ? systemConfig($type) : 0; + $user = app()->make(UserRepository::class)->getWhere(['uid' => $uid],'*',['member']); + $svip_status = $user->is_svip > 0 && systemConfig('svip_switch_status') == '1'; + if ($svip_status) { + $svipRate = app()->make(MemberinterestsRepository::class)->getSvipInterestVal(MemberinterestsRepository::HAS_TYPE_MEMBER); + if ($svipRate > 0) { + $inc = bcmul($svipRate, $inc, 0); + } + } + $this->checkMemberValue($user, $inc); + $make->incBill($user->uid, 'sys_members', $type, [ + 'number' => $inc, + 'title' => $config[$type], + 'balance' => $user->member_value, + 'status' => 0, + 'link_id' => $id, + 'mark' => $config[$type].':'.$user->member_value, + ]); + } + + /** + * TODO 连续升级 + * @param $nextLevel + * @param $num + * @return array + * @author Qinii + * @day 1/11/22 + */ + public function upUp($nextLevel, $num) + { + $newLevel = $this->getNextLevel($nextLevel->brokerage_level, 1); + if ($newLevel) { + $newNum = $num - $newLevel->brokerage_rule['value']; + if ($newNum > 0) { + [$nextLevel,$num] = $this->upUp($newLevel, $newNum); + } + } + return [$nextLevel,$num]; + } + + /** + * TODO 升级操作 + * @param User $user + * @param int $inc + * @author Qinii + * @day 1/11/22 + */ + public function checkMemberValue(User $user, int $inc) + { + /** + * 下一级所需经验值 + * 当前的经验值加上增加经验值是否够升级 + */ + Db::transaction(function () use ($inc, $user) { + $nextLevel = $this->getNextLevel($user->member_level, 1); + if (!$nextLevel) return ; + if (($user->member_value + $inc) >= $nextLevel->brokerage_rule['value']) { + + $num = ($user->member_value + $inc) - $nextLevel->brokerage_rule['value']; + if ($num > 0) { + [$nextLevel,$num] = $this->upUp($nextLevel, $num); + } + if ($user->member) { + $user->member->user_num--; + $user->member->save(); + } + + $nextLevel->user_num++; + $nextLevel->save(); + + $user->member_level = $nextLevel->brokerage_level; + + $key = 'notice_member_level_' . $user->uid; + app()->make(CacheRepository::class)->save($key,$nextLevel->brokerage_level); + } else { + $num = ($user->member_value + $inc); + } + $user->member_value = $num; + $user->save(); + }); + } +} diff --git a/app/common/repositories/user/UserExtractRepository.php b/app/common/repositories/user/UserExtractRepository.php new file mode 100644 index 00000000..93f8685f --- /dev/null +++ b/app/common/repositories/user/UserExtractRepository.php @@ -0,0 +1,195 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\user; + +use app\common\repositories\BaseRepository; +use app\common\dao\user\UserExtractDao as dao; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\MiniProgramService; +use crmeb\services\SwooleTaskService; +use crmeb\services\WechatService; +use think\exception\ValidateException; +use think\facade\Db; +use think\facade\Queue; + +class UserExtractRepository extends BaseRepository +{ + + /** + * @var dao + */ + protected $dao; + + + /** + * UserExtractRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + + /** + * TODO + * @param $id + * @return bool + * @author Qinii + * @day 2020-06-16 + */ + public function getWhereCount($id) + { + $where['extract_id'] = $id; + $where['status'] = 0; + return $this->dao->getWhereCount($where) > 0; + } + + /** + * TODO + * @param array $where + * @param $page + * @param $limit + * @return array + * @author Qinii + * @day 2020-06-16 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with(['user' => function ($query) { + $query->field('uid,avatar,nickname'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function getTotalExtractPrice() + { + return $this->dao->search(['status' => 1])->sum('extract_price'); + } + + /** + * @param $uid + * @return mixed + * @author xaboy + * @day 2020/6/22 + */ + public function userTotalExtract($uid) + { + return $this->dao->search(['status' => 1, 'uid' => $uid])->sum('extract_price'); + } + + /** + * TODO + * @param $user + * @param $data + * @author Qinii + * @day 2020-06-16 + */ + public function create($user,$data) + { + event('user.extract.before',compact('user','data')); + $userExtract = Db::transaction(function()use($user,$data){ + if($user['brokerage_price'] < (systemConfig('user_extract_min'))) + throw new ValidateException('可提现金额不足'); + if($data['extract_price'] < (systemConfig('user_extract_min'))) + throw new ValidateException('提现金额不得小于最低额度'); + if($user['brokerage_price'] < $data['extract_price']) + throw new ValidateException('提现金额不足'); + if($data['extract_type'] == 3) { + $make = app()->make(WechatUserRepository::class); + $openid = $make->idByOpenId((int)$user['wechat_user_id']); + if (!$openid){ + $openid = $make->idByRoutineId((int)$user['wechat_user_id']); + if(!$openid) throw new ValidateException('openID获取失败,请确认是微信用户'); + } + } + $brokerage_price = bcsub($user['brokerage_price'],$data['extract_price'],2); + $user->brokerage_price = $brokerage_price; + $user->save(); + + $data['extract_sn'] = $this->createSn(); + $data['uid'] = $user['uid']; + $data['balance'] = $brokerage_price; + + return $this->dao->create($data); + }); + event('user.extract',compact('userExtract')); + SwooleTaskService::admin('notice', [ + 'type' => 'extract', + 'title' => '您有一条新的提醒申请', + 'id' => $userExtract->extract_id + ]); + } + + public function switchStatus($id,$data) + { + $extract = $this->dao->getWhere(['extract_id' => $id]); + $user = app()->make(UserRepository::class)->get($extract['uid']); + if(!$user) throw new ValidateException('用户不存在'); + $brokerage_price = 0; + if($data['status'] == -1) + $brokerage_price = bcadd($user['brokerage_price'] ,$extract['extract_price'],2); + $type = systemConfig('sys_extension_type'); + $ret = []; + $service = null; + $func = null; + if ($data['status'] == 1 && $extract['extract_type'] == 3 && in_array($type,[1,2])) { + $func = $type == 1 ? 'merchantPay' : 'companyPay'; + $ret = [ + 'sn' => $extract['extract_sn'], + 'price' => $extract['extract_price'], + 'mark' => '企业付款给用户:'.$user->nickname, + 'batch_name' => '企业付款给用户:'.$user->nickname + ]; + $openid = app()->make(WechatUserRepository::class)->idByOpenId((int)$user['wechat_user_id']); + if ($openid) { + $ret['openid'] = $openid; + $service = WechatService::create(); + } else { + $routineOpenid = app()->make(WechatUserRepository::class)->idByRoutineId((int)$user['wechat_user_id']); + if (!$routineOpenid) throw new ValidateException('非微信用户不支持付款到零钱'); + $ret['openid'] = $routineOpenid; + $service = MiniProgramService::create(); + } + } + + Db::transaction(function()use($id,$data,$user,$brokerage_price,$ret,$service,$func){ + event('user.extractStatus.before',compact('id','data')); + if ($ret) $service->{$func}($ret); + if($brokerage_price){ + $user->brokerage_price = $brokerage_price; + $user->save(); + } + $userExtract = $this->dao->update($id,$data); + event('user.extractStatus',compact('id','userExtract')); + }); + + Queue::push(SendSmsJob::class,['tempId' => 'EXTRACT_NOTICE', 'id' =>$id]); + } + + public function createSn() + { + list($msec, $sec) = explode(' ', microtime()); + $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', ''); + $sn = 'ue' . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369)); + return $sn; + } + + public function getHistoryBank($uid) + { + return $this->dao->getSearch(['uid' => $uid,'extract_type' => 0])->order('create_time DESC')->field('real_name,bank_code,bank_address,bank_name')->find(); + } +} diff --git a/app/common/repositories/user/UserGroupRepository.php b/app/common/repositories/user/UserGroupRepository.php new file mode 100644 index 00000000..dd22ee28 --- /dev/null +++ b/app/common/repositories/user/UserGroupRepository.php @@ -0,0 +1,100 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserGroupDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; + +/** + * Class UserGroupRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020-05-07 + * @mixin UserGroupDao + */ +class UserGroupRepository extends BaseRepository +{ + /** + * @var UserGroupDao + */ + protected $dao; + + /** + * UserGroupRepository constructor. + * @param UserGroupDao $dao + */ + public function __construct(UserGroupDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @param null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function form($id = null, array $formData = []) + { + $isCreate = is_null($id); + $action = Route::buildUrl($isCreate ? 'systemUserGroupCreate' : 'systemUserGroupUpdate', $isCreate ? [] : compact('id'))->build(); + return Elm::createForm($action, [ + Elm::input('group_name', '用户分组名称')->required() + ])->setTitle($isCreate ? '添加用户分组' : '编辑用户分组')->formData($formData); + } + + /** + * @param $id + * @return Form + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function updateForm($id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } +} diff --git a/app/common/repositories/user/UserHistoryRepository.php b/app/common/repositories/user/UserHistoryRepository.php new file mode 100644 index 00000000..82799d01 --- /dev/null +++ b/app/common/repositories/user/UserHistoryRepository.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\user; + +use think\facade\Log; +use app\common\repositories\BaseRepository; +use app\common\dao\user\UserHistoryDao; +use app\common\repositories\store\product\SpuRepository; + +class UserHistoryRepository extends BaseRepository +{ + + protected $dao; + + /** + * UserHistoryRepository constructor. + * @param UserHistoryDao $dao + */ + public function __construct(UserHistoryDao $dao) + { + $this->dao = $dao; + } + + public function getApiList($page,$limit,$uid,$type) + { + $with = []; + if($type == 1)$with = ['spu']; + + $query = $this->dao->search($uid,$type); + $query->with($with)->order('update_time DESC'); + $count = $query->count(); + $data = $query->page($page,$limit)->select(); + $res = []; + foreach ($data as $item) { + + if ($item['spu']) { + $time = date('m月d日',strtotime($item['update_time'])); + $res[$time][] = $item; + } + } + $list = []; + foreach ($res as $k => $v) { + $list[] = [ + 'date' => $k, + 'list' => $v + ]; + } + + + return compact('count','list'); + } + + public function createOrUpdate(array $data) + { + $make = app()->make(SpuRepository::class); + $where['product_type'] = $data['product_type']; + switch ($data['product_type']) { + case 0: + $where['product_id'] = $data['id']; + break; + case 1: + $where['product_id'] = $data['id']; + break; + default: + $where['activity_id'] = $data['id']; + break; + } + try { + $ret = $make->getSearch($where)->find(); + if ($ret && $ret['spu_id']) { + $arr = [ + 'res_type' => $data['res_type'], + 'res_id' => $ret['spu_id'], + 'uid' => $data['uid'] + ]; + $this->dao->createOrUpdate($arr); + } + return $ret; + } catch (\Exception $exception) { + Log::info('浏览记录添加失败,ID:' . $data['id'] . '类型:' . $data['product_type']); + } + } + + /** + * TODO 商品推荐列表 + * @param int|null $uid + * @return array + * @author Qinii + * @day 4/9/21 + */ + public function getRecommend(?int $uid) + { + $ret = $this->dao->search($uid,1)->with(['spu.product'])->limit(10)->select(); + if(!$ret) return []; + $i = []; + foreach ($ret as $item){ + if(isset($item['spu']['product']['cate_id'])) $i[] = $item['spu']['product']['cate_id']; + } + if($i) $i = array_unique($i); + return $i; + } + + public function historyLst($where,$page,$limit) + { + $query = $this->dao->joinSpu($where); + $query->with([ + 'spu' + ])->order('update_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit) + ->setOption('field',[])->field('uid,product_id,product_type,spu_id,image,store_name,price') + ->select(); + return compact('count','list'); + } +} diff --git a/app/common/repositories/user/UserLabelRepository.php b/app/common/repositories/user/UserLabelRepository.php new file mode 100644 index 00000000..4f79b1a9 --- /dev/null +++ b/app/common/repositories/user/UserLabelRepository.php @@ -0,0 +1,100 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserLabelDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Route; + +/** + * Class UserLabelRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020-05-07 + * @mixin UserLabelDao + */ +class UserLabelRepository extends BaseRepository +{ + /** + * @var UserLabelDao + */ + protected $dao; + + /** + * UserGroupRepository constructor. + * @param UserLabelDao $dao + */ + public function __construct(UserLabelDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->order('label_id DESC')->page($page, $limit)->select(); + return compact('count', 'list'); + } + + /** + * @param null $id + * @param array $formData + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function form($id = null, array $formData = []) + { + $isCreate = is_null($id); + $action = Route::buildUrl($isCreate ? 'systemUserLabelCreate' : 'systemUserLabelUpdate', $isCreate ? [] : compact('id'))->build(); + return Elm::createForm($action, [ + Elm::input('label_name', '用户标签名称')->required() + ])->setTitle($isCreate ? '添加用户标签' : '编辑用户标签')->formData($formData); + } + + /** + * @param $id + * @return Form + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function updateForm($id) + { + return $this->form($id, $this->dao->get($id)->toArray()); + } +} diff --git a/app/common/repositories/user/UserMerchantRepository.php b/app/common/repositories/user/UserMerchantRepository.php new file mode 100644 index 00000000..27d326a5 --- /dev/null +++ b/app/common/repositories/user/UserMerchantRepository.php @@ -0,0 +1,131 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserMerchantDao; +use app\common\repositories\BaseRepository; +use FormBuilder\Factory\Elm; +use think\facade\Db; +use think\facade\Route; + +/** + * Class UserMerchantRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020/10/20 + * @mixin UserMerchantDao + */ +class UserMerchantRepository extends BaseRepository +{ + /** + * UserMerchantRepository constructor. + * @param UserMerchantDao $dao + */ + public function __construct(UserMerchantDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $make = app()->make(UserLabelRepository::class); + $list = $query->setOption('field', [])->field('A.uid,A.user_merchant_id,B.avatar,B.nickname,B.user_type,A.last_pay_time,A.first_pay_time,A.label_id,A.create_time,A.last_time,A.pay_num,A.pay_price,B.phone,B.is_svip,B.svip_endtime') + ->page($page, $limit)->order('A.user_merchant_id DESC')->select()->each(function ($item) use ($where, $make) { + return $item->label = count($item['label_id']) ? $make->labels($item['label_id'], $where['mer_id']) : []; + }); + return compact('count', 'list'); + } + + /** + * @param $uid + * @param $merId + * @return \app\common\dao\BaseDao|\think\Model + * @author xaboy + * @day 2020/10/20 + */ + public function create($uid, $merId) + { + return $this->dao->create([ + 'uid' => $uid, + 'mer_id' => $merId, + ]); + } + + /** + * @param $uid + * @param $mer_id + * @return \app\common\dao\BaseDao|array|\think\Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/10/20 + */ + public function getInfo($uid, $mer_id) + { + $user = $this->dao->getWhere(compact('uid', 'mer_id')); + if (!$user) $user = $this->create($uid, $mer_id); + return $user; + } + + /** + * @param $uid + * @param $merId + * @param $pay_price + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/10/21 + */ + public function updatePayTime($uid, $merId, $pay_price, $flag = true) + { + $user = $this->getInfo($uid, $merId); + $time = date('Y-m-d H:i:s'); + $user->last_pay_time = $time; + if ($flag) + $user->pay_num++; + $user->pay_price = bcadd($user->pay_price, $pay_price, 2); + if (!$user->first_pay_time) $user->first_pay_time = $time; + $user->save(); + } + + public function rmLabel($id) + { + return $this->dao->search(['label_id' => $id])->update([ + 'A.label_id' => Db::raw('(trim(BOTH \',\' FROM replace(CONCAT(\',\',A.label_id,\',\'),\',' . $id . ',\',\',\')))') + ]); + } + + public function changeLabelForm($merId, $id) + { + $user = $this->dao->get($id); + + /** @var UserLabelRepository $make */ + $userLabelRepository = app()->make(UserLabelRepository::class); + $data = $userLabelRepository->allOptions($merId); + return Elm::createForm(Route::buildUrl('merchantUserChangeLabel', compact('id'))->build(), [ + Elm::selectMultiple('label_id', '用户标签', $userLabelRepository->intersection($user->label_id, $merId, 0))->options(function () use ($data) { + $options = []; + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + }) + ])->setTitle('修改用户标签'); + } +} diff --git a/app/common/repositories/user/UserOrderRepository.php b/app/common/repositories/user/UserOrderRepository.php new file mode 100644 index 00000000..6c2a7d37 --- /dev/null +++ b/app/common/repositories/user/UserOrderRepository.php @@ -0,0 +1,171 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\LabelRuleDao; +use app\common\dao\user\UserOrderDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\PayService; +use FormBuilder\Factory\Elm; +use think\facade\Db; +use think\facade\Log; +use think\facade\Queue; + +/** + * Class LabelRuleRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020/10/20 + * @mixin LabelRuleDao + */ +class UserOrderRepository extends BaseRepository +{ + + //付费会员 + const TYPE_SVIP = 'S-'; + + /** + * LabelRuleRepository constructor. + * @param LabelRuleDao $dao + */ + public function __construct(UserOrderDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->with([ + 'user' => function($query){ + $query->field('uid,nickname,avatar,phone,is_svip,svip_endtime'); + } + ])->order('create_time DESC')->page($page, $limit)->select()->toArray(); + return compact('count', 'list'); + } + + /** + * @param $data + * @return mixed + * @author xaboy + * @day 2020/10/21 + */ + public function add($res, $user, $params) + { + $order_sn = app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_USER_ORDER); + $data = [ + 'title' => $res['value']['svip_name'], + 'link_id' => $res->group_data_id, + 'order_sn' => $order_sn, + 'pay_price' => $res['value']['price'], + 'order_info' => json_encode($res['value'],JSON_UNESCAPED_UNICODE), + 'uid' => $user->uid, + 'order_type' => self::TYPE_SVIP.$res['value']['svip_type'], + 'pay_type' => $res['value']['price'] == 0 ? 'free' : $params['pay_type'], + 'status' => 1, + 'other' => $user->is_svip == -1 ? 'first' : '', + ]; + $body = [ + 'order_sn' => $order_sn, + 'pay_price' => $data['pay_price'], + 'attach' => 'user_order', + 'body' =>'付费会员' + ]; + $type = $params['pay_type']; + if (in_array($type, ['weixin', 'alipay'], true) && $params['is_app']) { + $type .= 'App'; + } + if ($params['return_url'] && $type === 'alipay') $body['return_url'] = $params['return_url']; + $info = $this->dao->create($data); + if ($data['pay_price']){ + try { + $service = new PayService($type,$body, 'user_order'); + $config = $service->pay($user); + return app('json')->status($type, $config + ['order_id' => $info->order_id]); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $info->order_id]); + } + } else { + $res = $this->paySuccess($data); + return app('json')->status('success', ['order_id' => $info->order_id]); + } + } + + public function paySuccess($data) + { + /* + array ( + 'order_sn' => 'wxs167090166498470921', + 'data' => + EasyWeChat\Support\Collection::__set_state(array( + 'items' => + array ( + 'appid' => 'wx4409eaedbd62b213', + 'attach' => 'user_order', + 'bank_type' => 'OTHERS', + 'cash_fee' => '1', + 'fee_type' => 'CNY', + 'is_subscribe' => 'N', + 'mch_id' => '1288093001', + 'nonce_str' => '6397efa100165', + 'openid' => 'oOdvCvjvCG0FnCwcMdDD_xIODRO0', + 'out_trade_no' => 'wxs167090166498470921', + 'result_code' => 'SUCCESS', + 'return_code' => 'SUCCESS', + 'sign' => '125C56DE030A461E45D421E44C88BC30', + 'time_end' => '20221213112118', + 'total_fee' => '1', + 'trade_type' => 'JSAPI', + 'transaction_id' => '4200001656202212131458556229', + ), + )), + */ + $res = $this->dao->getWhere(['order_sn' => $data['order_sn']]); + $type = explode('-',$res['order_type'])[0].'-'; + // 付费会员充值 + if ($type == self::TYPE_SVIP) { + return Db::transaction(function () use($data, $res) { + $res->paid = 1; + $res->pay_time = date('y_m-d H:i:s', time()); + $res->save(); + return $this->payAfter($res, $res); + }); + } + } + + public function payAfter($data, $ret) + { + $info = json_decode($data['order_info']); + $user = app()->make(UserRepository::class)->get($ret['uid']); + $day = $info->svip_type == 3 ? 0 : $info->svip_number; + $endtime = ($user['svip_endtime'] && $user['is_svip'] != 0) ? $user['svip_endtime'] : date('Y-m-d H:i:s',time()); + $svip_endtime = date('Y-m-d H:i:s',strtotime("$endtime +$day day" )); + + $user->is_svip = $info->svip_type; + $user->svip_endtime = $svip_endtime; + $user->save(); + $ret->status = 1; + $ret->pay_time = date('Y-m-d H:i:s',time()); + $ret->end_time = $svip_endtime; + $ret->save(); + $date = $info->svip_type == 3 ? '终身会员' : $svip_endtime; + if ($user->phone) Queue::push(SendSmsJob::class,['tempId' => 'SVIP_PAY_SUCCESS','id' => ['phone' => $user->phone, 'date' => $date]]); + return ; + } +} diff --git a/app/common/repositories/user/UserReceiptRepository.php b/app/common/repositories/user/UserReceiptRepository.php new file mode 100644 index 00000000..6ea598dd --- /dev/null +++ b/app/common/repositories/user/UserReceiptRepository.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\user; + +use app\common\repositories\BaseRepository; +use app\common\dao\user\UserReceiptDao; + +class UserReceiptRepository extends BaseRepository +{ + protected $dao; + + public function __construct(UserReceiptDao $dao) + { + $this->dao = $dao; + } + + public function uidExists(int $id,int $uid) + { + return $this->dao->getWhereCount(['uid' => $uid,$this->dao->getPk() => $id,'is_del' => 0]); + } + + public function getIsDefault(int $uid) + { + return $this->dao->getWhere(['uid' => $uid,'is_default' => 1]); + } + + public function getList(array $where) + { + $where['is_del'] = 0; + return $this->dao->getSearch($where)->order('is_default DESC , create_time ASC')->select(); + } + + public function detail(array $where) + { + return $this->dao->getSearch($where)->find(); + } +} diff --git a/app/common/repositories/user/UserRechargeRepository.php b/app/common/repositories/user/UserRechargeRepository.php new file mode 100644 index 00000000..87546ebc --- /dev/null +++ b/app/common/repositories/user/UserRechargeRepository.php @@ -0,0 +1,133 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + +use app\common\dao\user\UserRechargeDao; +use app\common\model\user\User; +use app\common\model\user\UserRecharge; +use app\common\repositories\BaseRepository; +use crmeb\jobs\SendSmsJob; +use crmeb\services\PayService; +use think\facade\Db; +use think\facade\Queue; + +/** + * Class UserRechargeRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020/6/2 + * @mixin UserRechargeDao + */ +class UserRechargeRepository extends BaseRepository +{ + const TYPE_WECHAT = 'weixin'; + const TYPE_ROUTINE = 'routine'; + /** + * UserRechargeRepository constructor. + * @param UserRechargeDao $dao + */ + public function __construct(UserRechargeDao $dao) + { + $this->dao = $dao; + } + + public function create($uid, float $price, float $givePrice, string $type) + { + return $this->dao->create([ + 'uid' => $uid, + 'price' => $price, + 'give_price' => $givePrice, + 'recharge_type' => $type, + 'paid' => 0, + 'order_id' => $this->dao->createOrderId($uid) + ]); + } + + public function getList($where, $page, $limit) + { + $query = $this->dao->searchJoinQuery($where)->order('a.pay_time DESC,a.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + + public function priceByGive($price) + { + $quota = systemGroupData('user_recharge_quota'); + $give = 0; + foreach ($quota as $item) { + $min = floatval($item['price']); + $_give = floatval($item['give']); + if ($price > $min) $give = $_give; + } + return $give; + } + + /** + * @param string $type + * @param User $user + * @param UserRecharge $recharge + * @param string $return_url + * @return mixed + * @author xaboy + * @day 2020/10/22 + */ + public function pay(string $type, User $user, UserRecharge $recharge, $return_url = '', $isApp = false) + { + if (in_array($type, ['weixin', 'alipay'], true) && $isApp) { + $type .= 'App'; + } + event('user.recharge.before', compact('user', 'recharge', 'type', 'isApp')); + $service = new PayService($type, $recharge->getPayParams($type === 'alipay' ? $return_url : '')); + $config = $service->pay($user); + return $config + ['recharge_id' => $recharge['recharge_id'], 'type' => $type]; + } + + /** + * //TODO 余额充值成功 + * + * @param $orderId + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/19 + */ + public function paySuccess($orderId) + { + $recharge = $this->dao->getWhere(['order_id' => $orderId]); + if ($recharge->paid == 1) return; + $recharge->paid = 1; + $recharge->pay_time = date('Y-m-d H:i:s'); + + Db::transaction(function () use ($recharge) { + $price = bcadd($recharge->price, $recharge->give_price, 2); + $mark = '成功充值余额' . floatval($recharge->price) . '元' . ($recharge->give_price > 0 ? ',赠送' . $recharge->give_price . '元' : ''); + app()->make(UserBillRepository::class)->incBill($recharge->user->uid, 'now_money', 'recharge', [ + 'link_id' => $recharge->recharge_id, + 'status' => 1, + 'title' => '余额充值', + 'number' => $price, + 'mark' => $mark, + 'balance' => $recharge->user->now_money + ]); + $recharge->user->now_money = bcadd($recharge->user->now_money, $price, 2); + $recharge->user->save(); + $recharge->save(); + }); + Queue::push(SendSmsJob::class,['tempId' => 'USER_BALANCE_CHANGE', 'id' =>$orderId]); + event('user.recharge',compact('recharge')); + } +} diff --git a/app/common/repositories/user/UserRelationRepository.php b/app/common/repositories/user/UserRelationRepository.php new file mode 100644 index 00000000..0ba5c8b3 --- /dev/null +++ b/app/common/repositories/user/UserRelationRepository.php @@ -0,0 +1,257 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + +use app\common\dao\user\UserRelationDao as dao; +use app\common\repositories\BaseRepository; +use app\common\repositories\store\product\ProductAssistRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use think\exception\ValidateException; +use think\facade\Db; + +/** + * Class UserRelationRepository + * @package app\common\repositories\user + * @mixin dao + */ +class UserRelationRepository extends BaseRepository +{ + + protected $dao; + + /** + * UserRelationRepository constructor. + * @param dao $dao + */ + public function __construct(dao $dao) + { + $this->dao = $dao; + } + + /** + * @param $params + * @return bool + * @author Qinii + */ + public function fieldExists($params) + { + switch ($params['type']) { + case 0: //普通商品, + return app()->make(ProductRepository::class)->apiExists(0, $params['type_id']); + break; + case 1: //秒杀商品 + return app()->make(ProductRepository::class)->apiExists(0, $params['type_id']); + break; + case 2: //预售商品 + return app()->make(ProductPresellRepository::class)->getWhereCount(['product_presell_id' => $params['type_id']]); + break; + case 3: //助力商品 + return app()->make(ProductAssistRepository::class)->getWhereCount(['product_assist_id' => $params['type_id']]); + break; + case 4: //拼团商品 + return app()->make(ProductGroupRepository::class)->getWhereCount(['product_group_id' => $params['type_id']]); + break; + case 10: //商铺 + return app()->make(MerchantRepository::class)->apiGetOne($params['type_id']); + break; + default: + return false; + break; + } + } + + /** + * @param array $params + * @param int $uid + * @return bool + * @author Qinii + */ + public function getUserRelation(array $params, int $uid) + { + if(in_array($params['type'],[0,1,2,3,4])) { + $spu = $this->getSpu($params);; + $params['type_id'] = $spu['spu_id']; + $params['type'] = 1; + } + return ($this->dao->apiFieldExists('type_id', $params['type_id'], $params['type'], $uid)->count()) > 0; + } + + /** + * @param array $where + * @param int $page + * @param int $limit + * @return array|bool + * @author Qinii + */ + public function search(array $where, int $page, int $limit) + { + $with = []; + if($where['type'] == 1) $with = [ + 'spu' + ]; + if($where['type'] == 10) $with = [ + 'merchant' => function($query){ + $query->where('status',1)->where('mer_state',1)->where('is_del',0)->field('mer_id,type_id,mer_name,mer_avatar,sales,mer_info,care_count,status,is_del,mer_state'); + } + ]; + $query = $this->dao->search($where); + $query->with($with)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as &$item) { + if ($item['type'] == 1) { + if(isset($item['spu']['product_type']) && $item['spu']['product_type'] == 1){ + $item['spu']['stop_time'] = $item->stop_time; + unset($item['spu']['seckillActive']); + } + } else { + if (isset($item['merchant']) && $item['merchant']) { + $item['merchant']['showProduct'] = $item['merchant']['AllRecommend']; + } + } + } + return compact('count', 'list'); + } + + + /** + * @param int $uid + * @param array $data + * @author Qinii + */ + public function batchCreate(int $uid, array $data) + { + Db::transaction(function () use ($data, $uid) { + foreach ($data['type_id'] as $item) { + $param = ['type' => $data['type'], 'type_id' => $item, 'uid' => $uid]; + if(!$this->dao->getWhereCount($param)) $this->dao->create($param); + } + }); + } + + /** + * @param array $data + * @return \app\common\dao\BaseDao|\think\Model + * @author Qinii + */ + public function create(array $params) + { + + if($params['type'] == 10) { + $id = $params['type_id']; + app()->make(UserMerchantRepository::class)->getInfo($params['uid'], $params['type_id']); + $make = app()->make(MerchantRepository::class); + }else{ + $spu = $this->getSpu($params); + $params['type_id'] = $spu->spu_id; + $params['type'] = 1; + $make = app()->make(ProductRepository::class); + $id = $spu->product_id; + } + return Db::transaction(function()use($params,$make,$id){ + $make->incCareCount($id); + $this->dao->create($params); + }); + } + + /** + * TODO 批量删除 + * @param array $ids + * @param $uid + * @param $type + * @author Qinii + * @day 2023/2/16 + */ + public function batchDestory(array $ids,$uid, $type = 1) + { + if ($type == 10) { + app()->make(MerchantRepository::class)->decCareCount($ids); + $type_id = $ids; + } else { + foreach ($ids as $id) { + $spu = $this->getSpu(['type_id' => $id, 'type' => $type]); + $type_id[] = $spu->spu_id; + } + $type = 1; + app()->make(ProductRepository::class)->decCareCount($ids); + } + return $this->dao->search(['uid' => $uid,'type' => $type])->where('type_id','in',$type_id)->delete(); + } + + /** + * @param $uid + * @param array $merIds + * @author xaboy + * @day 2020/10/20 + */ + public function payer($uid, array $merIds) + { + $isset = $this->dao->intersectionPayer($uid, $merIds); + $merIds = array_diff($merIds, $isset); + if (!count($merIds)) return; + $data = []; + foreach ($merIds as $merId) { + $data[] = [ + 'type_id' => $merId, + 'type' => 12, + 'uid' => $uid + ]; + } + $this->dao->insertAll($data); + } + + + public function getSpu(array $data) + { + $make = app()->make(SpuRepository::class); + $where['product_type'] = $data['type']; + switch ($data['type']) { + case 0: + $where['product_id'] = $data['type_id']; + break; + case 1: + $where['product_id'] = $data['type_id']; + break; + default: + $where['activity_id'] = $data['type_id']; + break; + } + $ret = $make->getSearch($where)->find(); + if(!$ret) throw new ValidateException('SPU不存在'); + return $ret; + } + + /** + * TODO + * @param string|null $keyword + * @param int $uid + * @param int $page + * @param int $limit + * @return array + * @author Qinii + * @day 10/28/21 + */ + public function getUserProductToCommunity(?string $keyword, int $uid, int $page, int $limit) + { + $query = $this->dao->getUserProductToCommunity($keyword, $uid)->group('product_id'); + $count = $query->count(); + $list = $query->setOption('field',[])->field('uid,product_id,product_type,spu_id,image,store_name,price') + ->page($page, $limit)->select(); + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/user/UserRepository.php b/app/common/repositories/user/UserRepository.php new file mode 100644 index 00000000..745a1e26 --- /dev/null +++ b/app/common/repositories/user/UserRepository.php @@ -0,0 +1,1475 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\user; + + +use app\common\dao\BaseDao; +use app\common\dao\user\UserDao; +use app\common\model\user\User; +use app\common\model\wechat\WechatUser; +use app\common\repositories\BaseRepository; +use app\common\repositories\community\CommunityRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\exceptions\AuthException; +use crmeb\jobs\SendNewPeopleCouponJob; +use crmeb\jobs\UserBrokerageLevelJob; +use crmeb\services\JwtTokenService; +use crmeb\services\QrcodeService; +use crmeb\services\WechatService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Config; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; +use think\Model; + +/** + * Class UserRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020-04-28 + * @mixin UserDao + */ +class UserRepository extends BaseRepository +{ + /** + * UserRepository constructor. + * @param UserDao $dao + */ + public function __construct(UserDao $dao) + { + $this->dao = $dao; + } + + public function promoter($uid) + { + return $this->dao->update($uid, ['is_promoter' => 1, 'promoter_time' => date('Y-m-d H:i:s')]); + } + + public function createForm() + { + return Elm::createForm(Route::buildUrl('systemUserCreate')->build(), [ + Elm::input('account', '手机号(账号)')->required(), + Elm::password('pwd', '密码')->required(), + Elm::password('repwd', '确认密码')->required(), + Elm::input('nickname', '用户昵称')->required(), + Elm::frameImage('avatar', '头像', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=avatar&type=1') + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::input('real_name', '真实姓名'), + Elm::input('phone', '手机号'), + + Elm::input('card_id', '身份证'), + Elm::radio('sex', '性别', 0)->options([ + ['value' => 0, 'label' => '保密'], + ['value' => 1, 'label' => '男'], + ['value' => 2, 'label' => '女'], + ]), + Elm::radio('status', '状态', 1)->options([ + ['value' => 0, 'label' => '禁用'], + ['value' => 1, 'label' => '正常'], + ])->requiredNum(), + + Elm::radio('is_promoter', '推广员', 1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ])->requiredNum() + ])->setTitle('添加用户')->formData([]); + } + + + public function changePasswordForm(int $id) + { + $formData = $this->dao->get($id); + if (!$formData) throw new ValidateException('用户不存在'); + return Elm::createForm(Route::buildUrl('systemUserChangePassword',['id' => $id])->build(), [ + Elm::input('account', '账号', $formData->account)->disabled(true), + Elm::password('pwd', '新密码')->required(), + Elm::password('repwd', '确认新密码')->required(), + ])->setTitle('修改密码')->formData([]); + } + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-09 + */ + public function userForm($id) + { + $user = $this->dao->get($id); + $user['uid'] = (string)$user['uid']; + return Elm::createForm(Route::buildUrl('systemUserUpdate', compact('id'))->build(), [ + Elm::input('uid', '用户 ID', '')->disabled(true)->required(true), + Elm::input('real_name', '真实姓名'), + Elm::input('phone', '手机号'), + Elm::date('birthday', '生日'), + Elm::input('card_id', '身份证'), + Elm::input('addres', '用户地址'), + Elm::textarea('mark', '备注'), + Elm::select('group_id', '用户分组')->options(function () { + $data = app()->make(UserGroupRepository::class)->allOptions(); + $options = [['value' => 0, 'label' => '请选择']]; + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + }), + Elm::selectMultiple('label_id', '用户标签')->options(function () { + $data = app()->make(UserLabelRepository::class)->allOptions(); + $options = []; + foreach ($data as $value => $label) { + $value = (string)$value; + $options[] = compact('value', 'label'); + } + return $options; + }), + Elm::radio('status', '状态', 1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ])->requiredNum(), + Elm::radio('is_promoter', '推广员', 1)->options([ + ['value' => 0, 'label' => '关闭'], + ['value' => 1, 'label' => '开启'], + ])->requiredNum() + ])->setTitle('编辑')->formData($user->toArray()); + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where)->with([ + 'spread' => function ($query) { + $query->field('uid,nickname,spread_uid'); + }, + 'member' => function ($query) { + $query->field('user_brokerage_id,brokerage_level,brokerage_name,brokerage_icon'); + }, + 'group']); + $make = app()->make(UserLabelRepository::class); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->select()->each(function ($item) use ($make) { + return $item->label = count($item['label_id']) ? $make->labels($item['label_id']) : []; + }); + + return compact('count', 'list'); + } + + public function getPulbicLst(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->setOption('field',[])->field('uid,nickname,avatar')->select(); + return compact('count', 'list'); + } + + public function promoterCount() + { + $total = $this->dao->search(['is_promoter' => 1]) + ->field('sum(spread_count) as spread_count,sum(spread_pay_count) as spread_pay_count,sum(spread_pay_price) as spread_pay_price,count(uid) as total_user,sum(brokerage_price) as brokerage_price')->find(); + $total = $total ? $total->toArray() : ['spread_count' => 0, 'spread_pay_count' => 0, 'spread_pay_price' => 0, 'total_user' => 0, 'brokerage_price' => 0]; + $total['total_extract'] = app()->make(UserExtractRepository::class)->getTotalExtractPrice(); + return [ + [ + 'className' => 'el-icon-s-goods', + 'count' => $total['total_user'] ?? 0, + 'name' => '分销员人数(人)' + ], + [ + 'className' => 'el-icon-s-order', + 'count' => $total['spread_count'] ?? 0, + 'name' => '推广人数(人)' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (int)($total['spread_pay_count'] ?? 0), + 'name' => '推广订单数' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)($total['spread_pay_price'] ?? 0), + 'name' => '推广订单金额' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)($total['total_extract'] ?? 0), + 'name' => '已提现金额(元)' + ], + [ + 'className' => 'el-icon-s-cooperation', + 'count' => (float)($total['brokerage_price'] ?? 0), + 'name' => '未提现金额(元)' + ], + ]; + } + + public function promoterList(array $where, $page, $limit) + { + $where['is_promoter'] = 1; + $query = $this->dao->search($where)->with(['spread' => function ($query) { + $query->field('uid,nickname,spread_uid'); + }, 'brokerage' => function ($query) { + $query->field('brokerage_level,brokerage_name,brokerage_icon'); + }]); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->select()->toArray(); + if (count($list)) { + $promoterInfo = app()->make(UserExtractRepository::class)->getPromoterInfo(array_column($list, 'uid')); + if (count($promoterInfo)) { + $promoterInfo = array_combine(array_column($promoterInfo, 'uid'), $promoterInfo); + } + foreach ($list as $k => $item) { + $list[$k]['total_extract_price'] = $promoterInfo[$item['uid']]['total_price'] ?? 0; + $list[$k]['total_extract_num'] = $promoterInfo[$item['uid']]['total_num'] ?? 0; + $list[$k]['total_brokerage_price'] = (float)bcadd($item['brokerage_price'], $list[$k]['total_extract_num'], 2); + } + } + return compact('list', 'count'); + } + + public function merList(string $keyword, $page, $limit) + { + $query = $this->dao->searchMerUser($keyword); + $count = $query->count($this->dao->getPk()); + $list = $query->page($page, $limit)->setOption('field', [])->field('uid,nickname,avatar,user_type,sex')->select(); + return compact('count', 'list'); + } + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function changeGroupForm($id) + { + $isArray = is_array($id); + if (!$isArray) + $user = $this->dao->get($id); + + /** @var UserGroupRepository $make */ + $data = app()->make(UserGroupRepository::class)->allOptions(); + return Elm::createForm(Route::buildUrl($isArray ? 'systemUserBatchChangeGroup' : 'systemUserChangeGroup', $isArray ? [] : compact('id'))->build(), [ + Elm::hidden('ids', $isArray ? $id : [$id]), + Elm::select('group_id', '用户分组', $isArray ? '' : $user->group_id)->options(function () use ($data) { + $options = [['label' => '不设置', 'value' => '0']]; + foreach ($data as $value => $label) { + $options[] = compact('value', 'label'); + } + return $options; + }) + ])->setTitle('修改用户分组'); + } + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function changeLabelForm($id) + { + $isArray = is_array($id); + if (!$isArray) + $user = $this->dao->get($id); + + /** @var UserLabelRepository $make */ + $data = app()->make(UserLabelRepository::class)->allOptions(); + return Elm::createForm(Route::buildUrl($isArray ? 'systemUserBatchChangeLabel' : 'systemUserChangeLabel', $isArray ? [] : compact('id'))->build(), [ + Elm::hidden('ids', $isArray ? $id : [$id]), + Elm::selectMultiple('label_id', '用户标签', $isArray ? [] : $user->label_id)->options(function () use ($data) { + $options = []; + foreach ($data as $value => $label) { + $value = (string)$value; + $options[] = compact('value', 'label'); + } + return $options; + }) + ])->setTitle('修改用户标签'); + } + + /** + * @param $id + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function changeNowMoneyForm($id) + { + return Elm::createForm(Route::buildUrl('systemUserChangeNowMoney', compact('id'))->build(), [ + Elm::radio('type', '修改余额', 1)->options([ + ['label' => '增加', 'value' => 1], + ['label' => '减少', 'value' => 0], + ])->requiredNum(), + Elm::number('now_money', '金额')->required()->min(0)->max(999999) + ])->setTitle('修改用户余额'); + } + + public function changeIntegralForm($id) + { + return Elm::createForm(Route::buildUrl('systemUserChangeIntegral', compact('id'))->build(), [ + Elm::radio('type', '修改积分', 1)->options([ + ['label' => '增加', 'value' => 1], + ['label' => '减少', 'value' => 0], + ])->requiredNum(), + Elm::number('now_money', '积分')->required()->min(0)->max(999999) + ])->setTitle('修改用户积分'); + } + + /** + * @param $id + * @param $adminId + * @param $type + * @param $nowMoney + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function changeNowMoney($id, $adminId, $type, $nowMoney) + { + $user = $this->dao->get($id); + Db::transaction(function () use ($id, $adminId, $user, $type, $nowMoney) { + $balance = $type == 1 ? bcadd($user->now_money, $nowMoney, 2) : bcsub($user->now_money, $nowMoney, 2); + $user->save(['now_money' => $balance]); + /** @var UserBillRepository $make */ + $make = app()->make(UserBillRepository::class); + if ($type == 1) { + $make->incBill($id, 'now_money', 'sys_inc_money', [ + 'link_id' => $adminId, + 'status' => 1, + 'title' => '系统增加余额', + 'number' => $nowMoney, + 'mark' => '系统增加了' . floatval($nowMoney) . '余额', + 'balance' => $balance + ]); + } else { + $make->decBill($id, 'now_money', 'sys_dec_money', [ + 'link_id' => $adminId, + 'status' => 1, + 'title' => '系统减少余额', + 'number' => $nowMoney, + 'mark' => '系统减少了' . floatval($nowMoney) . '余额', + 'balance' => $balance + ]); + } + }); + } + + /** + * @param $id + * @param $adminId + * @param $type + * @param $integral + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function changeIntegral($id, $adminId, $type, $integral) + { + $user = $this->dao->get($id); + Db::transaction(function () use ($id, $adminId, $user, $type, $integral) { + $integral = (int)$integral; + $balance = $type == 1 ? bcadd($user->integral, $integral, 0) : bcsub($user->integral, $integral, 0); + $user->save(['integral' => $balance]); + /** @var UserBillRepository $make */ + $make = app()->make(UserBillRepository::class); + if ($type == 1) { + $make->incBill($id, 'integral', 'sys_inc', [ + 'link_id' => $adminId, + 'status' => 1, + 'title' => '系统增加积分', + 'number' => $integral, + 'mark' => '系统增加了' . $integral . '积分', + 'balance' => $balance + ]); + } else { + $make->decBill($id, 'integral', 'sys_dec', [ + 'link_id' => $adminId, + 'status' => 1, + 'title' => '系统减少积分', + 'number' => $integral, + 'mark' => '系统减少了' . $integral . '积分', + 'balance' => $balance + ]); + } + }); + } + + /** + * @param $password + * @return false|string|null + * @author xaboy + * @day 2020/6/22 + */ + public function encodePassword($password) + { + return password_hash($password, PASSWORD_BCRYPT); + } + + public function userType($type) + { + if ($type === 'apple') { + return 'app'; + } + if (!$type) + return 'h5'; + return $type; + } + + public function syncBaseAuth(array $auth, User $user) + { + $wechatUser = app()->make(WechatUserRepository::class)->get($auth['id']); + if ($wechatUser) { + $data = ['wechat_user_id' => $auth['id'], 'user_type' => $auth['type']]; + if ($wechatUser['nickname']) { + $data['nickname'] = $wechatUser['nickname']; + } + if ($wechatUser['headimgurl']) { + $data['avatar'] = $wechatUser['headimgurl']; + } + $data['sex'] = $wechatUser['sex'] ?? 0; + $user->save($data); + } + } + + /** + * @param WechatUser $wechatUser + * @return BaseDao|array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function syncWechatUser(WechatUser $wechatUser, $userType = 'wechat') + { + $user = $this->dao->wechatUserIdBytUser($wechatUser->wechat_user_id); + $request = request(); + + if ($user) { +// if ($wechatUser['nickname'] == '微信用户') { +// unset($wechatUser['nickname'],$wechatUser['headimgurl']); +// } + $user->save(array_filter([ + 'nickname' => $wechatUser['nickname'] ?? '', + 'avatar' => $wechatUser['headimgurl'] ?? '', + 'sex' => $wechatUser['sex'] ?? 0, + 'last_time' => date('Y-m-d H:i:s'), + 'last_ip' => $request->ip(), + ])); + } else { + $user = $this->create($userType, [ + 'account' => 'wx' . $wechatUser->wechat_user_id . time(), + 'wechat_user_id' => $wechatUser->wechat_user_id, + 'pwd' => $this->encodePassword($this->dao->defaultPwd()), + 'nickname' => $wechatUser['nickname'] ?? '', + 'avatar' => $wechatUser['headimgurl'] ?? '', + 'sex' => $wechatUser['sex'] ?? 0, + 'spread_uid' => 0, + 'is_promoter' => 0, + 'last_time' => date('Y-m-d H:i:s'), + 'last_ip' => $request->ip() + ]); + } + return $user; + } + + /** + * @param string $type + * @param array $userInfo + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-28 + */ + public function create(string $type, array $userInfo) + { + $userInfo['user_type'] = $this->userType($type); + if (!isset($userInfo['status'])) { + $userInfo['status'] = 1; + } + $user = $this->dao->create($userInfo); + try { + Queue::push(SendNewPeopleCouponJob::class, $user->uid); + } catch (\Exception $e) { + } + $user->isNew = true; + return $user; + } + + /** + * @param User $user + * @return array + * @author xaboy + * @day 2020-04-29 + */ + public function createToken(User $user) + { + $service = new JwtTokenService(); + $exp = intval(Config::get('admin.user_token_valid_exp', 15)); + $token = $service->createToken($user->uid, 'user', strtotime("+ {$exp}day")); + $this->cacheToken($token['token'], $token['out']); + return $token; + } + + /** + * //TODO 登录成功后 + * @param User $user + * @author xaboy + * @day 2020/6/22 + */ + public function loginAfter(User $user) + { + $user->last_time = date('Y-m-d H:i:s', time()); + $user->last_ip = request()->ip(); + $user->save(); + } + + + /** + * @param string $token + * @param int $exp + * @author xaboy + * @day 2020-04-29 + */ + public function cacheToken(string $token, int $exp) + { + Cache::store('file')->set('user_' . $token, time() + $exp, $exp); + } + + + /** + * @param string $token + * @author xaboy + * @day 2020-04-29 + */ + public function checkToken(string $token) + { + $cache = Cache::store('file'); + $has = $cache->has('user_' . $token); + if (!$has) + throw new AuthException('无效的token'); + $lastTime = $cache->get('user_' . $token); + if (($lastTime + (intval($cache->get('admin.user_token_valid_exp', 15))) * 24 * 60 * 60) < time()) + throw new AuthException('token 已过期'); + } + + + /** + * @param string $token + * @author xaboy + * @day 2020-04-29 + */ + public function updateToken(string $token) + { + Cache::store('file')->set('user_' . $token, time(), intval(Config::get('admin.user_token_valid_exp', 15)) * 24 * 60 * 60); + } + + + /** + * @param string $token + * @author xaboy + * @day 2020-04-29 + */ + public function clearToken(string $token) + { + Cache::delete('user_' . $token); + } + + /** + * @param string $key + * @param string $code + * @author xaboy + * @day 2020/6/1 + */ + public function checkCode(string $key, string $code) + { + $_code = Cache::get('am_captcha' . $key); + if (!$_code) { + throw new ValidateException('验证码过期'); + } + + if (strtolower($_code) != strtolower($code)) { + throw new ValidateException('验证码错误'); + } + + //删除code + Cache::delete('am_captcha' . $key); + } + + + /** + * @param string $code + * @return string + * @author xaboy + * @day 2020/6/1 + */ + public function createLoginKey(string $code) + { + $key = uniqid(microtime(true), true); + Cache::set('am_captcha' . $key, $code, Config::get('admin.captcha_exp', 5) * 60); + return $key; + } + + public function registr(string $phone, ?string $pwd, $user_type = 'h5') + { + $pwd = $pwd ? $this->encodePassword($pwd) : $this->encodePassword($this->dao->defaultPwd()); + $data = [ + 'account' => $phone, + 'pwd' => $pwd, + 'nickname' => substr($phone, 0, 3) . '****' . substr($phone, 7, 4), + 'avatar' => '', + 'phone' => $phone, + 'last_ip' => app('request')->ip() + ]; + return $this->create($user_type, $data); + } + + public function routineSpreadImage(User $user) + { + //小程序 + $name = md5('surt' . $user['uid'] . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $attachmentRepository = app()->make(AttachmentRepository::class); + $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]); + $spreadBanner = systemGroupData('spread_banner'); + if (!count($spreadBanner)) return []; + $siteName = systemConfig('site_name'); + $siteUrl = systemConfig('site_url'); + $uploadType = (int)systemConfig('upload_type') ?: 1; + + $urlCode = app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/index/index', 'spid=' . $user['uid']); + if (!$urlCode) + throw new ValidateException('二维码生成失败'); + $filelink = [ + 'Bold' => 'public/font/Alibaba-PuHuiTi-Regular.otf', + 'Normal' => 'public/font/Alibaba-PuHuiTi-Regular.otf', + ]; + if (!file_exists($filelink['Bold'])) throw new ValidateException('缺少字体文件Bold'); + if (!file_exists($filelink['Normal'])) throw new ValidateException('缺少字体文件Normal'); + $resRoutine = true; + foreach ($spreadBanner as $key => &$item) { + $posterInfo = '海报生成失败:('; + $config = array( + 'image' => array( + array( + 'url' => $urlCode, //二维码资源 + 'stream' => 0, + 'left' => 114, + 'top' => 790, + 'right' => 0, + 'bottom' => 0, + 'width' => 120, + 'height' => 120, + 'opacity' => 100 + ) + ), + 'text' => array( + array( + 'text' => $user['nickname'], + 'left' => 250, + 'top' => 840, + 'fontPath' => $filelink['Bold'], //字体文件 + 'fontSize' => 16, //字号 + 'fontColor' => '40,40,40', //字体颜色 + 'angle' => 0, + ), + array( + 'text' => '邀请您加入' . $siteName, + 'left' => 250, + 'top' => 880, + 'fontPath' => $filelink['Normal'], //字体文件 + 'fontSize' => 16, //字号 + 'fontColor' => '40,40,40', //字体颜色 + 'angle' => 0, + ) + ), + 'background' => $item['pic'] + ); + $resRoutine = $resRoutine && $posterInfo = setSharePoster($config, 'routine/spread/poster'); + if (!is_array($posterInfo)) throw new ValidateException($posterInfo); + $posterInfo['dir'] = tidy_url($posterInfo['dir'], 0, $siteUrl); + if ($resRoutine) { + $attachmentRepository->create($uploadType, -1, $user->uid, [ + 'attachment_category_id' => 0, + 'attachment_name' => $posterInfo['name'], + 'attachment_src' => $posterInfo['dir'] + ]); + $item['poster'] = $posterInfo['dir']; + } + } + return $spreadBanner; + } + + public function wxQrcode(User $user) + { + $name = md5('uwx_i' . $user['uid'] . date('Ymd')) . '.jpg'; + $key = 'home_' . $user['uid']; + return app()->make(QrcodeService::class)->getWechatQrcodePath($name, rtrim(systemConfig('site_url'), '/') . '?spread=' . $user['uid'] . '&spid=' . $user['uid'], false, $key); + } + + public function mpQrcode(User $user) + { + $name = md5('surt_i' . $user['uid'] . $user['is_promoter'] . date('Ymd')) . '.jpg'; + + return app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/index/index', 'spid=' . $user['uid']); + } + + public function wxSpreadImage(User $user) + { + $name = md5('uwx' . $user['uid'] . $user['is_promoter'] . date('Ymd')) . '.jpg'; + $spreadBanner = systemGroupData('spread_banner'); + if (!count($spreadBanner)) return []; + $siteName = systemConfig('site_name'); + $attachmentRepository = app()->make(AttachmentRepository::class); + $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]); + $siteUrl = rtrim(systemConfig('site_url'), '/'); + $uploadType = (int)systemConfig('upload_type') ?: 1; + $resWap = true; + //检测远程文件是否存在 + if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) { + $imageInfo->delete(); + $imageInfo = null; + } + if (!$imageInfo) { + $codeUrl = $siteUrl . '?spread=' . $user['uid'] . '&spid=' . $user['uid'];//二维码链接 + if (systemConfig('open_wechat_share')) { + $qrcode = WechatService::create(false)->qrcodeService(); + $codeUrl = $qrcode->forever('_scan_url_home_' . $user['uid'])->url; + } + $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($codeUrl, $name); + if (is_string($imageInfo)) throw new ValidateException('二维码生成失败'); + + $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl); + + $attachmentRepository->create(systemConfig('upload_type') ?: 1, -1, $user->uid, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $urlCode = $imageInfo['dir']; + } else $urlCode = $imageInfo['attachment_src']; + $filelink = [ + 'Bold' => 'public/font/Alibaba-PuHuiTi-Regular.otf', + 'Normal' => 'public/font/Alibaba-PuHuiTi-Regular.otf', + ]; + if (!file_exists($filelink['Bold'])) throw new ValidateException('缺少字体文件Bold'); + if (!file_exists($filelink['Normal'])) throw new ValidateException('缺少字体文件Normal'); + foreach ($spreadBanner as $key => &$item) { + $posterInfo = '海报生成失败:('; + $config = array( + 'image' => array( + array( + 'url' => $urlCode, //二维码资源 + 'stream' => 0, + 'left' => 114, + 'top' => 790, + 'right' => 0, + 'bottom' => 0, + 'width' => 120, + 'height' => 120, + 'opacity' => 100 + ) + ), + 'text' => array( + array( + 'text' => $user['nickname'], + 'left' => 250, + 'top' => 840, + 'fontPath' => $filelink['Bold'], //字体文件 + 'fontSize' => 16, //字号 + 'fontColor' => '40,40,40', //字体颜色 + 'angle' => 0, + ), + array( + 'text' => '邀请您加入' . $siteName, + 'left' => 250, + 'top' => 880, + 'fontPath' => $filelink['Normal'], //字体文件 + 'fontSize' => 16, //字号 + 'fontColor' => '40,40,40', //字体颜色 + 'angle' => 0, + ) + ), + 'background' => $item['pic'] + ); + $resWap = $resWap && $posterInfo = setSharePoster($config, 'wap/spread/poster'); + if (!is_array($posterInfo)) throw new ValidateException('海报生成失败'); + $posterInfo['dir'] = tidy_url($posterInfo['dir'], null, $siteUrl); + $attachmentRepository->create($uploadType, -1, $user->uid, [ + 'attachment_category_id' => 0, + 'attachment_name' => $posterInfo['name'], + 'attachment_src' => $posterInfo['dir'] + ]); + if ($resWap) { + $item['wap_poster'] = $posterInfo['dir']; + } + } + return $spreadBanner; + } + + public function getUsername($uid) + { + return User::getDB()->where('uid', $uid)->value('nickname'); + } + + /** + * @param $uid + * @param $inc + * @param string $type + * @author xaboy + * @day 2020/6/22 + */ + public function incBrokerage($uid, $inc, $type = '+') + { + $moneyKey = 'b_top_' . date('Y-m'); + $weekKey = 'b_top_' . monday(); + //TODO 佣金周榜 + $brokerage = Cache::zscore($weekKey, $uid); + $brokerage = $type == '+' ? bcadd($brokerage, $inc, 2) : bcsub($brokerage, $inc, 2); + Cache::zadd($weekKey, $brokerage, $uid); + + //TODO 佣金月榜 + $brokerage = Cache::zscore($moneyKey, $uid); + $brokerage = $type == '+' ? bcadd($brokerage, $inc, 2) : bcsub($brokerage, $inc, 2); + Cache::zadd($moneyKey, $brokerage, $uid); + } + + /** + * TODO 删除排行榜中的个人排行 + * @param $uid + * @author Qinii + * @day 2022/10/18 + */ + public function delBrokerageTop($uid) + { + $moneyKey = 'b_top_' . date('Y-m'); + $weekKey = 'b_top_' . monday(); + Cache::zrem($weekKey,$uid); + Cache::zrem($moneyKey,$uid); + } + + public function brokerageWeekTop($uid, $page, $limit) + { + $key = 'b_top_' . monday(); + return $this->topList($key, $page, $limit) + ['position' => $this->userPosition($key, $uid)]; + } + + public function brokerageMonthTop($uid, $page, $limit) + { + $key = 'b_top_' . date('Y-m'); + return $this->topList($key, $page, $limit) + ['position' => $this->userPosition($key, $uid)]; + } + + /** + * //TODO 绑定上下级关系 + * @param User $user + * @param int $spreadUid + * @throws DbException + * @author xaboy + * @day 2020/6/22 + */ + public function bindSpread(User $user, int $spreadUid) + { + if ($spreadUid && !$user->spread_uid && $user->uid != $spreadUid && ($spread = $this->dao->get($spreadUid)) && $spread->spread_uid != $user->uid && !$spread->cancel_time) { + $config = systemConfig(['extension_limit', 'extension_limit_day', 'integral_user_give']); + event('user.spread.before', compact('user','spreadUid')); + Db::transaction(function () use ($spread, $spreadUid, $user, $config) { + $user->spread_uid = $spreadUid; + $user->spread_time = date('Y-m-d H:i:s'); + if ($config['extension_limit'] && $config['extension_limit_day']) { + $user->spread_limit = date('Y-m-d H:i:s', strtotime('+ ' . $config['extension_limit_day'] . ' day')); + } + $spread->spread_count++; + if ($config['integral_user_give'] > 0 && $user->isNew) { + $integral = (int)$config['integral_user_give']; + $spread->integral += $integral; + app()->make(UserBillRepository::class)->incBill($spreadUid, 'integral', 'spread', [ + 'link_id' => $user->uid, + 'status' => 1, + 'title' => '邀请好友', + 'number' => $integral, + 'mark' => '邀请好友奖励' . $integral . '积分', + 'balance' => $spread->integral + ]); + } + $spread->save(); + $user->save(); + //TODO 推广人月榜 + Cache::zincrby('s_top_' . date('Y-m'), 1, $spreadUid); + //TODO 推广人周榜 + Cache::zincrby('s_top_' . monday(), 1, $spreadUid); + }); + Queue::push(UserBrokerageLevelJob::class, ['uid' => $spreadUid, 'type' => 'spread_user', 'inc' => 1]); + app()->make(UserBrokerageRepository::class)->incMemberValue($user->uid, 'member_share_num', 0); + event('user.spread', compact('user','spreadUid')); + } + } + + public function userPosition($key, $uid) + { + $index = Cache::zrevrank($key, $uid); + if ($index === false) + return 0; + else + return $index + 1; + } + + public function topList($key, $page, $limit) + { + $res = Cache::zrevrange($key, ($page - 1) * $limit, $limit, true); + $ids = array_keys($res); + $count = Cache::zcard($key); + $list = count($ids) ? $this->dao->users($ids, 'uid,avatar,nickname')->toArray() : []; + foreach ($list as $k => $v) { + $list[$k]['count'] = $res[$v['uid']] ?? 0; + } + $sort = array_column($list, 'count'); + array_multisort($sort, SORT_DESC, $list); + return compact('count', 'list'); + } + + public function spreadWeekTop($page, $limit) + { + $key = 's_top_' . monday(); + return $this->topList($key, $page, $limit); + } + + public function spreadMonthTop($page, $limit) + { + $key = 's_top_' . date('Y-m'); + return $this->topList($key, $page, $limit); + } + + /** + * @param $uid + * @param $nickname + * @param $sort + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function getOneLevelList($uid, $nickname, $sort, $page, $limit) + { + $query = $this->search(['spread_uid' => $uid, 'nickname' => $nickname, 'sort' => $sort]); + $count = $query->count(); + $list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select(); + return compact('list', 'count'); + } + + /** + * @param $uid + * @param $nickname + * @param $sort + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function getTwoLevelList($uid, $nickname, $sort, $page, $limit) + { + $ids = $this->dao->getSubIds($uid); + if (count($ids)) { + $query = $this->search(['spread_uids' => $ids, 'nickname' => $nickname, 'sort' => $sort]); + $count = $query->count(); + $list = $query->setOption('field', [])->field('uid,avatar,nickname,pay_count,pay_price,spread_count,spread_time')->page($page, $limit)->select(); + } else { + $list = []; + $count = 0; + } + return compact('list', 'count'); + } + + public function getLevelList($uid, array $where, $page, $limit) + { + if (!$where['level']) { + $ids = $this->dao->getSubIds($uid); + $ids[] = $uid; + $where['spread_uids'] = $ids; + } else if ($where['level'] == 2) { + $ids = $this->dao->getSubIds($uid); + if (!count($ids)) return ['list' => [], 'count' => 0]; + $where['spread_uids'] = $ids; + } else { + $where['spread_uid'] = $uid; + } + $query = $this->search($where); + $count = $query->count(); + $list = $query->setOption('field', [])->field('uid,avatar,nickname,is_promoter,pay_count,pay_price,spread_count,create_time,spread_time,spread_limit')->page($page, $limit)->select(); + return compact('list', 'count'); + } + + + /** + * @param $uid + * @param $page + * @param $limit + * @param array $where + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/26 + */ + public function subOrder($uid, $page, $limit, array $where = []) + { + if (isset($where['level'])) { + if (!$where['level']) { + $ids = $this->dao->getSubIds($uid); + $subIds = $ids ? $this->dao->getSubAllIds($ids) : []; + } else if ($where['level'] == 2) { + $ids = $this->dao->getSubIds($uid); + $subIds = $ids ? $this->dao->getSubAllIds($ids) : []; + $ids = []; + } else if ($where['level'] == -1) { + $ids = []; + $subIds = []; + } else { + $ids = $this->dao->getSubIds($uid); + $subIds = []; + } + } else { + $ids = $this->dao->getSubIds($uid); + $subIds = $ids ? $this->dao->getSubAllIds($ids) : []; + } + $all = array_unique(array_merge($ids, $subIds)); + $all[] = -1; + $query = app()->make(StoreOrderRepository::class)->usersOrderQuery($where, $all, (!isset($where['level']) || !$where['level'] || $where['level'] == -1) ? $uid : 0); + $count = $query->count(); + $list = $query->page($page, $limit)->field('uid,order_sn,pay_time,extension_one,extension_two,is_selfbuy')->with(['user' => function ($query) { + $query->field('avatar,nickname,uid'); + }])->select()->toArray(); + foreach ($list as $k => $item) { + if ($item['is_selfbuy']) { + if ($item['uid'] == $uid) { + $list[$k]['brokerage'] = $item['extension_one']; + } else if (in_array($item['uid'], $ids)) { + $list[$k]['brokerage'] = $item['extension_two']; + } else { + $list[$k]['brokerage'] = 0; + } + } else { + $list[$k]['brokerage'] = in_array($item['uid'], $ids) ? $item['extension_one'] : $item['extension_two']; + } + unset($list[$k]['extension_one'], $list[$k]['extension_two']); + } + return compact('count', 'list'); + } + + /** + * @param User $user + * @return User + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/7/2 + */ + public function mainUser(User $user): User + { + if (!$user->main_uid || $user->uid == $user->main_uid) return $user; + $switchUser = $this->dao->get($user->main_uid); + if (!$switchUser) return $user; + if ($user->wechat_user_id && !$switchUser->wechat_user_id) { + $switchUser->wechat_user_id = $user->wechat_user_id; + $switchUser->save(); + } + return $switchUser; + } + + public function switchUser(User $user, $uid) + { + if ($user->uid == $uid || !$this->dao->existsWhere(['uid' => $uid, 'phone' => $user->phone])) + throw new ValidateException('操作失败'); + $this->dao->update($user->uid, ['main_uid' => $uid]); + $this->dao->getSearch([])->where('main_uid', $user->uid)->update(['main_uid' => $uid]); + + $switchUser = $this->dao->get($uid); + if (!$switchUser->wechat_user_id) { + $switchUser->wechat_user_id = $user->wechat_user_id; + $switchUser->save(); + } + + return $switchUser; + } + + public function returnToken($user, $tokenInfo) + { + if (!$user->status) { + throw new ValidateException('账号已被禁用'); + } + $user = $user->hidden(['label_id', 'group_id', 'main_uid', 'pwd', 'addres', 'card_id', 'last_time', 'last_ip', 'create_time', 'mark', 'status', 'spread_uid', 'spread_time', 'real_name', 'birthday', 'brokerage_price'])->toArray(); + return [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'expires_time' => strtotime('+ '.$tokenInfo['out']. 'seconds'), + 'user' => $user + ]; + } + + public function switchBrokerage(User $user, $brokerage) + { + $user->now_money = bcadd($user->now_money, $brokerage, 2); + $user->brokerage_price = bcsub($user->brokerage_price, $brokerage, 2); + Db::transaction(function () use ($brokerage, $user) { + $user->save(); + app()->make(UserBillRepository::class)->incBill($user->uid, 'now_money', 'brokerage', [ + 'link_id' => 0, + 'status' => 1, + 'title' => '佣金转入余额', + 'number' => $brokerage, + 'mark' => '成功转入余额' . floatval($brokerage) . '元', + 'balance' => $user->now_money + ]); + app()->make(UserBillRepository::class)->decBill($user->uid, 'brokerage', 'now_money', [ + 'link_id' => 0, + 'status' => 1, + 'title' => '佣金转入余额', + 'number' => $brokerage, + 'mark' => '成功转入余额' . floatval($brokerage) . '元', + 'balance' => $user->brokerage_price + ]); + }); + } + + public function rmLabel($id) + { + return $this->search(['label_id' => $id])->update([ + 'label_id' => Db::raw('trim(BOTH \',\' FROM replace(CONCAT(\',\',label_id,\',\'),\',' . $id . ',\',\',\'))') + ]); + } + + public function changeSpreadForm($id) + { + $user = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemUserSpreadChange', compact('id'))->build(), [ + [ + 'type' => 'span', + 'title' => '用户昵称', + 'children' => [$user->nickname] + ], [ + 'type' => 'span', + 'title' => '上级推荐人 Id', + 'children' => [$user->spread ? (string)$user->spread->uid : '无'] + ], [ + 'type' => 'span', + 'title' => '上级推荐人昵称', + 'children' => [$user->spread ? (string)$user->spread->nickname : '无'] + ], Elm::frameImage('spid', '上级推荐人', '/' . config('admin.admin_prefix') . '/setting/referrerList?field=spid')->prop('srcKey', 'src')->value($user->spread ? [ + 'src' => $user->spread->avatar, + 'id' => $user->spread->uid, + ] : [])->modal(['modal' => false])->width('896px')->height('480px'), + ]); + return $form->setTitle('修改推荐人'); + } + + public function changeSpread($uid, $spread_id, $admin = 0) + { + $spreadLogRepository = app()->make(UserSpreadLogRepository::class); + $user = $this->dao->get($uid); + if ($user->spread_uid == $spread_id) + return; + $config = systemConfig(['extension_limit', 'extension_limit_day']); + Db::transaction(function () use ($config, $user, $spreadLogRepository, $spread_id, $admin) { + $old = $user->spread_uid ?: 0; + $spreadLogRepository->add($user->uid, $spread_id, $old, $admin); + $user->spread_time = $spread_id ? date('Y-m-d H:i:s') : null; + if ($spread_id && $config['extension_limit'] && $config['extension_limit_day']) { + $user->spread_limit = date('Y-m-d H:i:s', strtotime('+ ' . $config['extension_limit_day'] . ' day')); + } else { + $user->spread_limit = null; + } + $user->spread_uid = $spread_id; + if ($spread_id) { + $this->dao->incSpreadCount($spread_id); + } + if ($old) { + $this->dao->decSpreadCount($old); + } + $user->save(); + }); + } + + public function syncSpreadStatus() + { + if (systemConfig('extension_limit')) { + $this->dao->syncSpreadStatus(); + } + } + + /** + * TODO 积分增加 + * @param int $uid + * @param int $number + * @param $title + * @param $type + * @param $data + * @author Qinii + * @day 6/9/21 + */ + public function incIntegral(int $uid,int $number,$title,$type,$data) + { + Db::transaction(function() use($uid,$number,$title,$type,$data){ + + $user = $this->dao->get($uid); + $user->integral = $user->integral + $number; + $user->save(); + + app()->make(UserBillRepository::class) + ->incBill($uid, 'integral', $type, + [ + 'link_id' => 0, + 'status' => 1, + 'title' => $title, + 'number' => $data['number'], + 'mark' => $data['mark'], + 'balance' =>$data['balance'], + ]); + }); + } + + + public function memberForm(int $id ,int $type) + { + if ($type) { + $form = Elm::createForm(Route::buildUrl('systemUserMemberSave', ['id' => $id])->build()); + $field = 'member_level'; + } else { + $form = Elm::createForm(Route::buildUrl('systemUserSpreadSave', ['id' => $id])->build()); + $field = 'brokerage_level'; + } + + $data = $this->dao->get($id); + if (!$data) throw new ValidateException('数据不存在'); + if (!$type && !$data['is_promoter']) throw new ValidateException('用户不是分销员'); + $rules = [ + Elm::select($field, '级别',$data->$field)->options(function () use($type){ + $options = app()->make(UserBrokerageRepository::class)->options(['type' => $type])->toArray(); + return $options; + }), + ]; + $form->setRule($rules); + return $form->setTitle($type ? '编辑会员等级' : '编辑分销等级'); + } + + public function updateLevel(int $id, array $data, int $type) + { + $make = app()->make(UserBrokerageRepository::class); + $user = $this->dao->get($id); + $field = $type ? 'member_level' : 'brokerage_level'; + if ($data[$field] == $user->$field) return true; + $has = $make->fieldExists('brokerage_level', $data[$field], null, $type); + if (!$has) throw new ValidateException('等级不存在'); + Db::transaction(function() use($id, $data, $field, $user, $type){ + $user->$field = $data[$field]; + if ($type) $user->member_value = 0; + $user->save(); + + if ($type == 0) app()->make(UserBillRepository::class)->search(['category' => 'sys_brokerage'])->where('uid', $id)->delete(); + + }); + + } + + public function cancel(User $user) + { + Db::transaction(function () use ($user) { + $uid = $user->uid; + $name = '已注销用户' . substr(uniqid(true, true), -6); + if ($user->wechat) { + $user->wechat->save([ + 'unionid' => '', + 'openid' => '', + 'routine_openid' => '', + 'nickname' => $name, + 'headimgurl' => '', + 'city' => '', + 'province' => '', + 'country' => '', + ]); + } + $user->save([ + 'account' => '', + 'real_name' => '', + 'nickname' => $name, + 'avatar' => '', + 'phone' => '', + 'address' => '', + 'card_id' => '', + 'main_uid' => 0, + 'label_id' => '', + 'group_id' => 0, + 'spread_uid' => 0, + 'status' => 0, + 'is_promoter' => 0, + 'wechat_user_id' => 0, + 'cancel_time' => date('Y-m-d H:i:s') + ]); + $this->getSearch([])->where('main_uid', $uid)->update(['main_uid' => 0]); + app()->make(UserAddressRepository::class)->getSearch([])->where('uid', $uid)->delete(); + app()->make(UserMerchantRepository::class)->getSearch([])->where('uid', $uid)->delete(); + app()->make(UserReceiptRepository::class)->getSearch([])->where('uid', $uid)->delete(); + app()->make(StoreServiceRepository::class)->getSearch([])->where('uid', $uid)->update(['uid' => 0, 'status' => 0, 'is_open' => 0]); + $this->getSearch([])->where('spread_uid', $uid)->update(['spread_uid' => 0]); + $this->delBrokerageTop($uid); + //TODO 推广人月榜 + Cache::zrem('s_top_' . date('Y-m'), $uid); + //TODO 推广人周榜 + Cache::zrem('s_top_' . monday(), $uid); + app()->make(CommunityRepository::class)->destoryByUid($uid); + }); + } + + public function svipForm(int $id) + { + $formData = $this->dao->get($id); + if (!$formData) throw new ValidateException('数据不存在'); + $form = Elm::createForm(Route::buildUrl('systemUserSvipUpdate', ['id' => $id])->build()); + $rule = [ + Elm::switches('is_svip', '付费会员', $formData->is_svip > 0 ? 1 : 0)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]; + if ($formData->is_svip == 3) { + $rule[] = Elm::input('is_svip_type', '会员类型','永久会员')->disabled(true)->appendRule('suffix', [ + 'type' => 'div', + 'style' => ['color' => '#999999'], + 'domProps' => [ + 'innerHTML' =>'永久会员,若关闭后再次开启将不再是永久会员,请谨慎操作', + ] + ]); + } else { + $rule[] = Elm::radio('type', '修改类型', 1)->options([ + ['label' => '增加', 'value' => 1], + ['label' => '减少', 'value' => 0], + ])->requiredNum(); + $rule[] = Elm::number('add_time', '会员期限(天)')->required()->min(1); + $rule[] = Elm::input('end_time', '当前有效期期限', $formData->is_svip > 0 ? $formData->svip_endtime : 0)->disabled(true); + } + $form->setRule($rule); + return $form->setTitle( '编辑付费会员期限'); + } + + /** + * TODO 设置付费会员 + * @param $id + * @param $data + * @author Qinii + * @day 2022/11/22 + */ + public function svipUpdate($id, $data,$adminId) + { + $user = app()->make(UserRepository::class)->get($id); + if (!$user) throw new ValidateException('用户不存在'); + if ($user['is_svip'] < 1 && ($data['is_svip'] == 0 || !$data['type'])) + throw new ValidateException('该用户还不是付费会员'); + if ($user['is_svip'] == 3 && $data['is_svip'] == 1) + throw new ValidateException('该用户已是永久付费会员'); + if ($data['is_svip']) { + $day = ($data['type'] == 1 ? '+ ' : '- ').$data['add_time']; + $endtime = ($user['svip_endtime'] && $user['is_svip'] != 0) ? $user['svip_endtime'] : date('Y-m-d H:i:s',time()); + $is_svip = 1; + $svip_endtime = date('Y-m-d H:i:s',strtotime("$endtime $day day" )); + //结束时间小于当前 就关闭付费会员 + if (strtotime($svip_endtime) <= time()) { + $is_svip = 0; + } + } else { + $is_svip = 0; + $svip_endtime = date('Y-m-d H:i:s', time()); + } + $make = app()->make(UserOrderRepository::class); + $res = [ + 'title' => $data['is_svip'] == 0 ? '平台取消会员资格' : ($data['type'] ? '平台赠送' : '平台扣除'), + 'link_id' => 0, + 'order_sn' => app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_USER_ORDER), + 'pay_price' => 0, + 'order_info' => json_encode($data,JSON_UNESCAPED_UNICODE), + 'uid' => $id, + 'order_type' => UserOrderRepository::TYPE_SVIP . $is_svip, + 'pay_type' => 'sys', + 'status' => 1, + 'pay_time' => date('Y-m-d H:i:s',time()), + 'admin_id' => $adminId, + 'end_time' => $svip_endtime, + 'other' => $user->is_svip == -1 ? 'first' : '', + ]; + + Db::transaction(function () use($user, $res, $is_svip, $svip_endtime,$make) { + $make->create($res); + $user->is_svip = $is_svip; + $user->svip_endtime = $svip_endtime; + $user->save(); + }); + } + + public function updateBaseInfo($data, $user) + { + Db::transaction(function() use($data, $user){ + $user->save(array_filter([ + 'nickname' => $data['nickname'] ?? '', + 'avatar' => $data['avatar'] ?? '', + ])); + if (isset($user->wechat) ) { + $user->wechat->save(array_filter([ + 'nickname' => $data['nickname'] ?? '', + 'headimgurl' => $data['avatar'] ?? '', + ])); + } + }); + } +} diff --git a/app/common/repositories/user/UserSignRepository.php b/app/common/repositories/user/UserSignRepository.php new file mode 100644 index 00000000..6f7ce703 --- /dev/null +++ b/app/common/repositories/user/UserSignRepository.php @@ -0,0 +1,209 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserSignDao; +use app\common\repositories\BaseRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\groupData\GroupRepository; +use think\exception\ValidateException; +use think\facade\Db; + + +class UserSignRepository extends BaseRepository +{ + /** + * @var UserSignDao + */ + protected $dao; + + /** + * UserSignRepository constructor. + * @param UserSignDao $dao + */ + public function __construct(UserSignDao $dao) + { + $this->dao = $dao; + } + + /** + * TODO 获取指定日期 用户的连续签到数 + * @param int $uid + * @param string $day + * @return array + * @author Qinii + * @day 6/8/21 + */ + public function getSign(int $uid,string $day) + { + return $this->dao->getSearch(['uid' => $uid,'day' => $day])->value('sign_num'); + } + + public function getDay(int $num) + { + if($num > 7) { + $yu = ($num % 7); + $num = ($yu == 0) ? 6 : $yu - 1; + } else { + $num = (($num -1) < 0) ? 0 : ($num -1); + } + + $title = $this->signConfig(); + if(empty($title)) throw new ValidateException('未开启签到功能'); + if (isset($title[$num]['value'])) { + $dat = $title[$num]['value']; + } else { + $dat = [ + 'sign_day' => '无', + 'sign_integral' => 0, + ]; + } + return $dat; + } + + /** + * TODO 签到操作 + * @param int $uid + * @author Qinii + * @day 6/8/21 + */ + public function create(int $uid) + { + /** + * 用户昨天的签到情况,如果有就是连续签到,如果没有就是第一天签到 + * 根据签到天数计算签到积分等操作 + * 计算用户剩余积分 + * + */ + $yesterday = date("Y-m-d",strtotime("-1 day")); + $sign_num = ($this->getSign($uid,$yesterday) ?: 0) + 1; + //签到规则计算 + $sign_task = $this->getDay($sign_num); + $user = app()->make(UserRepository::class)->get($uid); + $integral = $sign_task['sign_integral']; + if ($user->is_svip > 0) { + $makeInteres = app()->make(MemberinterestsRepository::class); + $integral = $integral * $makeInteres->getSvipInterestVal($makeInteres::HAS_TYPE_SIGN);; + } + $user_make = app()->make(UserRepository::class); + $user = $user_make->get($uid); + $integral_ = $user['integral'] + $integral; + $data = [ + 'uid' => $uid, + 'sign_num' => $sign_num, + 'number' => $integral, + 'integral' => $integral_, + 'title' => '签到', + ]; + //增加记录 + $arr = [ + 'status' => 1, + 'mark' => '签到,获得积分'. $integral, + 'number' => $integral, + 'balance'=> $integral_, + ]; + return Db::transaction(function() use($uid,$data,$user_make,$sign_task,$arr,$integral){ + $ret = $this->dao->create($data); + $user_make->incIntegral($uid,$integral,'签到'.$sign_task['sign_day'],'sign_integral',$arr); + app()->make(UserBrokerageRepository::class)->incMemberValue($uid, 'member_sign_num', $ret->sign_id); + return compact('integral'); + }); + } + + public function getList(array $where,int $page,int $limit) + { + $query = $this->dao->getSearch($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + public function info(int $uid) + { + /** + * 连续签到日期展示 1 - 7天 + * 是否签到 + * 累计签到数 + */ + + $ret = $this->signStatus($uid); + $is_sign = $ret['is_sign']; + $sign_num = $ret['sign_num']; + $title = $this->signConfig(); + $userInfo = app()->make(UserRepository::class)->getWhere(['uid' => $uid],'uid,avatar,nickname,integral'); + $count = $this->dao->getSearch(['uid' => $uid])->count('*'); + return compact('userInfo','is_sign','sign_num','count','title'); + + } + + public function signConfig(){ + $group_make = app()->make(GroupRepository::class); + $sign_day_config = $group_make->keyById('sign_day_config'); + $title = app()->make(GroupDataRepository::class) + ->getGroupDataWhere(0,$sign_day_config) + ->where('status',1)->limit(7) + ->hidden(['group_data_id','group_id','create_time','mer_id'])->select()->toArray(); + return $title; + } + + /** + * TODO 连续签到 获取 1- 7 天 + * @param $uid + * @return array + * @author Qinii + * @day 6/10/21 + */ + public function signStatus($uid) + { + $day = date('Y-m-d',time()); + $sign_num = 0; + $sign_num = $this->getSign($uid,$day); + $is_sign = $sign_num ? 1 : 0; + + if($sign_num > 7){ + $sign_num = ($sign_num % 7); + if(!$sign_num) $sign_num = 7; + } + + if(!$is_sign){ + $yesterday = date("Y-m-d",strtotime("-1 day")); + $sign_num = $this->getSign($uid,$yesterday) ?: 0; + if($sign_num > 7){ + $sign_num = ($sign_num % 7); + } + } + return compact('is_sign','sign_num'); + } + + /** + * TODO 按月显示签到记录 + * @param array $where + * @return array + * @author Qinii + * @day 6/10/21 + */ + public function month(array $where) + { + $group = $this->dao->getSearch($where)->field('FROM_UNIXTIME(unix_timestamp(create_time),"%Y-%m") as time') + ->order('time DESC')->group('time')->select(); + $ret = []; + foreach ($group as $k => $item){ + $ret[$k]['month'] = $item['time']; + $query = $this->dao->getSearch($where)->field('title,number,create_time')->whereMonth('create_time',$item['time']); + $ret[$k]['list'] = $query->order('create_time DESC')->select(); + } + return $ret; + } +} diff --git a/app/common/repositories/user/UserSpreadLogRepository.php b/app/common/repositories/user/UserSpreadLogRepository.php new file mode 100644 index 00000000..1b5cb873 --- /dev/null +++ b/app/common/repositories/user/UserSpreadLogRepository.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserSpreadLogDao; +use app\common\repositories\BaseRepository; + +/** + * @mixin UserSpreadLogDao + */ +class UserSpreadLogRepository extends BaseRepository +{ + public function __construct(UserSpreadLogDao $dao) + { + $this->dao = $dao; + } + + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->page($page, $limit)->with(['spread' => function ($query) { + $query->field('uid,nickname,avatar'); + }])->select(); + + return compact('count', 'list'); + } +} diff --git a/app/common/repositories/user/UserVisitRepository.php b/app/common/repositories/user/UserVisitRepository.php new file mode 100644 index 00000000..c51889f4 --- /dev/null +++ b/app/common/repositories/user/UserVisitRepository.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\user; + + +use app\common\dao\user\UserVisitDao; +use app\common\repositories\BaseRepository; + +/** + * Class UserVisitRepository + * @package app\common\repositories\user + * @author xaboy + * @day 2020/5/27 + * @mixin UserVisitDao + */ +class UserVisitRepository extends BaseRepository +{ + /** + * @var UserVisitDao + */ + protected $dao; + + /** + * UserVisitRepository constructor. + * @param UserVisitDao $dao + */ + public function __construct(UserVisitDao $dao) + { + $this->dao = $dao; + } + + public function getRecommend(?int $uid) + { + $data = $this->dao->search(['uid' => $uid, 'type' => 'product'])->with(['product' => function ($query) { + $query->field('product_id,cate_id'); + }])->limit(7)->select(); + $i = []; + if (is_array($data)) { + foreach ($data as $item) { + $i[] = $item['product']['cate_id']; + } + } + return $i; + } + + public function getHistory($uid,$page, $limit) + { + $query = $this->dao->search(['uid' => $uid, 'type' => 'product']); + $query->with(['product'=>function($query){ + $query->field('product_id,image,store_name,slider_image,price,is_show,status,sales'); + }]); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + return compact('count','list'); + } + + public function getSearchLog(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $query->with(['user' => function ($query) { + $query->field('uid,nickname,avatar,user_type'); + }]); + $count = $query->count(); + $list = $query->page($page, $limit)->order('create_time DESC')->select(); + return compact('count', 'list'); + } + + +} diff --git a/app/common/repositories/wechat/CustomTemplate.php b/app/common/repositories/wechat/CustomTemplate.php new file mode 100644 index 00000000..3d41b855 --- /dev/null +++ b/app/common/repositories/wechat/CustomTemplate.php @@ -0,0 +1,22 @@ +sendTemplate($openid,$tempid,$data,$stie_url,$color,[ + 'appid' => systemConfig('routine_appId'), + ]); + } catch (\Exception $e) { + Log::error('发送给openid为:' . $openid . '微信模板消息失败,模板id为:' . $tempid . ';错误原因为:' . $e->getMessage()); + return $e->getMessage(); + } + } +} \ No newline at end of file diff --git a/app/common/repositories/wechat/RoutineQrcodeRepository.php b/app/common/repositories/wechat/RoutineQrcodeRepository.php new file mode 100644 index 00000000..0f448dbc --- /dev/null +++ b/app/common/repositories/wechat/RoutineQrcodeRepository.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\wechat; + + +use app\common\dao\wechat\RoutineQrcodeDao; +use app\common\repositories\BaseRepository; +use crmeb\services\MiniProgramService; + +/** + * Class RoutineQrcodeRepository + * @package app\common\repositories\wechat + * @author xaboy + * @day 2020/6/18 + * @mixin RoutineQrcodeDao + */ +class RoutineQrcodeRepository extends BaseRepository +{ + /** + * RoutineQrcodeRepository constructor. + * @param RoutineQrcodeDao $dao + */ + public function __construct(RoutineQrcodeDao $dao) + { + $this->dao = $dao; + } + + + /** + * TODO 获取小程序二维码 + * @param $thirdId + * @param $thirdType + * @param $page + * @param $imgUrl + * @return array|bool + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getShareCode($thirdId, $thirdType, $page, $imgUrl) + { + $res = $this->dao->routineQrCodeForever($thirdId, $thirdType, $page, $imgUrl); + $resCode = MiniProgramService::create()->qrcodeService()->appCodeUnlimit($res->routine_qrcode_id, '', 280); + if ($resCode) + return ['res' => $resCode, 'id' => $res->routine_qrcode_id]; + else return false; + } + + /** + * TODO 获取小程序页面带参数二维码不保存数据库 + * @param string $page + * @param string $pramam + * @param int $width + * @return mixed + */ + public function getPageCode($page = '', $pramam = "", $width = 280) + { + return MiniProgramService::create()->qrcodeService()->appCodeUnlimit($pramam, $page, $width); + } +} diff --git a/app/common/repositories/wechat/TemplateMessageRepository.php b/app/common/repositories/wechat/TemplateMessageRepository.php new file mode 100644 index 00000000..20d25740 --- /dev/null +++ b/app/common/repositories/wechat/TemplateMessageRepository.php @@ -0,0 +1,239 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\wechat; + +use app\common\dao\wechat\TemplateMessageDao; +use app\common\repositories\BaseRepository; +use crmeb\exceptions\WechatException; +use crmeb\services\MiniProgramService; +use crmeb\services\WechatService; +use FormBuilder\Factory\Elm; +use think\exception\ValidateException; +use think\facade\Config; +use think\facade\Route; + +/** + * Class TemplateMessageRepository + * @package app\common\repositories\wechat + * @mixin TemplateMessageDao + */ +class TemplateMessageRepository extends BaseRepository +{ + + /** + * @var TemplateMessageDao + */ + public $dao; + + /** + * TemplateMessageRepository constructor. + * @param TemplateMessageDao $dao + */ + public function __construct(TemplateMessageDao $dao) + { + $this->dao = $dao; + } + + + public function getList($wereh,$page,$limit) + { + $query = $this->dao->search($wereh); + $count = $query->count(); + $list = $query->page($page,$limit)->order('template_id DESC')->select(); + return compact('count','list'); + } + + /** + * TODO + * @param int|null $id + * @param int $type + * @return \FormBuilder\Form + * @author Qinii + * @day 2020-06-19 + */ + public function form(?int $id = null,$type = 0) + { + $form = Elm::createForm(Route::buildUrl('systemTemplateMessageCreate')->build()); + $form->setRule([ + Elm::hidden('type',$type), + Elm::input('tempkey','模板编号'), + Elm::input('name','模板名'), + Elm::input('tempid','模板ID'), + Elm::textarea('content','回复内容'), + Elm::switches('status','状态',1)->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]); + return $form->setTitle(is_null($id) ? '添加' : '编辑'); + } + + /** + * TODO + * @param $id + * @return \FormBuilder\Form + * @author Qinii + * @day 2020-06-19 + */ + public function updateForm($id) + { + $tem = $this->dao->get($id); + $form = Elm::createForm(Route::buildUrl('systemTemplateMessageUpdate',['id' => $id])->build()); + $form->setRule([ + Elm::hidden('type',$tem['type']), + Elm::input('tempkey','模板编号',$tem['tempkey'])->disabled(1), + Elm::input('name','模板名',$tem['name'])->disabled(1), + Elm::input('tempid','模板ID',$tem['tempid']), + Elm::switches('status','状态',$tem['status'])->activeValue(1)->inactiveValue(0)->inactiveText('关')->activeText('开'), + ]); + return $form->setTitle('编辑'); + } + + public function getSubscribe() + { + $res = []; + $data = $this->dao->search(['type' => 0])->column('tempid','tempkey'); + $arr = Config::get('template.stores.subscribe.template_id'); + foreach ($arr as $k => $v){ + $res[$k] = $data[$v] ?? ''; + } + return $res; + } + + public function getTemplateList(array $where) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->select(); + foreach ($list as &$item) { + if ($item['content']) $item['content'] = explode("\n", $item['content']); + } + return compact('list', 'count'); + } + + + /** + * TODO 同步订阅消息 + * @return string + * @author Qinii + * @day 11/24/21 + */ + public function syncMinSubscribe() + { + if (!systemConfig('routine_appId') || !systemConfig('routine_appsecret')) { + throw new ValidateException('请先配置小程序appid、appSecret等参数'); + } + + $all = $this->getTemplateList(['type' => 0]); + $errData = []; + $errMessage = [ + '-1' => '系统繁忙,此时请稍候再试', + '40001' => 'AppSecret错误或者AppSecret不属于这个小程序,请确认AppSecret 的正确性', + '40002' => '请确保grant_type字段值为client_credential', + '40013' => '不合法的AppID,请检查AppID的正确性,避免异常字符,注意大小写', + '40125' => '小程序配置无效,请检查配置', + '41002' => '缺少appid参数', + '41004' => '缺少secret参数', + '43104' => 'appid与openid不匹配', + '45009' => '达到微信api每日限额上限', + '200011' => '此账号已被封禁,无法操作', + '200012' => '个人模版数已达上限,上限25个', + ]; + if ($all['list']) { + $time = time(); + foreach ($all['list'] as $template) { + if ($template['tempkey']) { + if (!isset($template['kid'])) { + throw new ValidateException('数据库模版表(template_message)缺少字段:kid'); + } + if (isset($template['kid']) && $template['kid']) { + continue; + } + $works = []; + try { + $works = MiniProgramService::create()->getSubscribeTemplateKeyWords($template['tempkey']); + } catch (\Throwable $e) { + $wechatErr = $e->getMessage(); + if (is_string($wechatErr)) + throw new WechatException('模板ID:'.$template['tempkey'].',错误信息'.$wechatErr); + if (in_array($wechatErr->getCode(), array_keys($errMessage))) { + throw new WechatException($errMessage[$wechatErr->getCode()]); + } + $errData[1] = '获取关键词列表失败:' . $wechatErr->getMessage(); + } + $kid = []; + if ($works) { + $works = array_combine(array_column($works, 'name'), $works); + $content = is_array($template['content']) ? $template['content'] : explode("\n", $template['content']); + foreach ($content as $c) { + $name = explode('{{', $c)[0] ?? ''; + if ($name && isset($works[$name])) { + $kid[] = $works[$name]['kid']; + } + } + } + if ($kid && isset($template['kid']) && !$template['kid']) { + $tempid = ''; + try { + $tempid = MiniProgramService::create()->addSubscribeTemplate($template['tempkey'], $kid, $template['name']); + } catch (\Throwable $e) { + $wechatErr = $e->getMessage(); + if ($wechatErr->getCode() == 200022) continue; + if (is_string($wechatErr)) throw new WechatException($wechatErr); + if (in_array($wechatErr->getCode(), array_keys($errMessage))) { + throw new WechatException($errMessage[$wechatErr->getCode()]); + } + $errData[2] = '添加订阅消息模版失败:' . $wechatErr->getMessage(); + } + + if ($tempid != $template['tempid'] && $tempid) { + $this->dao->update($template['template_id'], ['tempid' => $tempid, 'kid' => json_encode($kid), 'create_time' => $time]); + } + } + } + } + } + return $errData ? implode('\n', $errData) : '同步成功'; + } + + /** + * 同步模板消息 + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function syncWechatSubscribe() + { + if (!systemConfig('wechat_appid') || !systemConfig('wechat_appsecret')) { + throw new WechatException('请先配置微信公众号appid、appSecret等参数'); + } + $tempall = $this->getTemplateList(['type' => 1]); + /* + * 删除所有模版ID + */ + //获取微信平台已经添加的模版 + $list = WechatService::create()->getPrivateTemplates();//获取所有模版 + foreach ($list->template_list as $v) { + //删除已有模版 + WechatService::create()->deleleTemplate($v['template_id']); + } + + foreach ($tempall['list'] as $temp) { + //添加模版消息 + $res = WechatService::create()->addTemplateId($temp['tempkey']); + if (!$res->errcode && $res->template_id) { + $this->dao->update($temp['template_id'], ['tempid' => $res->template_id]); + } + } + + return '模版消息一键设置成功'; + } +} diff --git a/app/common/repositories/wechat/WechatNewsRepository.php b/app/common/repositories/wechat/WechatNewsRepository.php new file mode 100644 index 00000000..de8ab593 --- /dev/null +++ b/app/common/repositories/wechat/WechatNewsRepository.php @@ -0,0 +1,111 @@ + +// +---------------------------------------------------------------------- + +namespace app\common\repositories\wechat; + +use app\common\dao\wechat\WechatNewsDao; +use app\common\repositories\article\ArticleRepository; +use app\common\repositories\BaseRepository; +use think\facade\Db; +use app\common\dao\article\ArticleDao; + +class WechatNewsRepository extends BaseRepository +{ + public function __construct(WechatNewsDao $dao) + { + $this->dao = $dao; + } + + public function create(array $data,int $merId,int $adminId) + { + Db::transaction(function () use($adminId,$merId,$data){ + $wechatNews = $this->dao->create([ + 'status' => $data['status'] ?? 1, + 'mer_id' => $merId + ]); + $make = app()->make(ArticleRepository::class); + $wechat_news_id = $wechatNews->wechat_news_id; + foreach ($data['data'] as $v) { + $result = [ + 'admin_id' => $adminId, + 'mer_id' => $merId, + 'wechat_news_id' => $wechat_news_id, + 'title' => $v['title'], + "author" => $v['author'], + "synopsis" => $v['synopsis'], + "image_input" => $v['image_input'], + 'content' => $v['content'], + ]; + $make->create($result); + } + }); + } + + public function update(int $id , array $data,int $merId,int $adminId) + { + Db::transaction(function () use($id,$adminId,$merId,$data){ + $this->dao->update($id,['status' => $data['status']]); + $make = app()->make(ArticleRepository::class); + $make->clearByNewId($id); + foreach ($data['data'] as $v) { + $result = [ + 'admin_id' => $adminId, + 'mer_id' => $merId, + 'wechat_news_id' => $id, + 'title' => $v['title'], + "author" => $v['author'], + "synopsis" => $v['synopsis'], + "image_input" => $v['image_input'], + 'content' => $v['content']['content'] ?? $v['content'], + ]; + $make->create($result); + } + }); + + } + + /** + * @param int $id + * @param int $merId + * @author Qinii + */ + public function delete(int $id,int $merId) + { + Db::transaction(function()use($id,$merId){ + $make = app()->make(ArticleRepository::class); + $ids = $make->getKey($id,'wechat_news_id'); + foreach ($ids as $id) {$make->delete($id,$merId);} + $this->dao->delete($id); + }); + } + + /** + * @param int $merId + * @param $page + * @param $limit + * @return array + * @author Qinii + */ + public function search(array $where, $page, $limit) + { + $query = $this->dao->getAll($where); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + return compact('count', 'list'); + } + + public function git(int $id,int $merId) + { + return $this->dao->get($id,$merId); + } + +} diff --git a/app/common/repositories/wechat/WechatQrcodeRepository.php b/app/common/repositories/wechat/WechatQrcodeRepository.php new file mode 100644 index 00000000..1818cc43 --- /dev/null +++ b/app/common/repositories/wechat/WechatQrcodeRepository.php @@ -0,0 +1,131 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\wechat; + + +use app\common\dao\BaseDao; +use app\common\dao\wechat\WechatQrcodeDao; +use app\common\repositories\BaseRepository; +use crmeb\services\WechatService; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\Model; + +/** + * Class WechatQrcodeRepository + * @package app\common\repositories\wechat + * @author xaboy + * @day 2020-04-28 + * @mixin WechatQrcodeDao + */ +class WechatQrcodeRepository extends BaseRepository +{ + /** + * WechatQrcodeRepository constructor. + * @param WechatQrcodeDao $dao + */ + public function __construct(WechatQrcodeDao $dao) + { + $this->dao = $dao; + } + + /** + * @param $id + * @param $type + * @param null $qtcode_id + * @return BaseDao|int|Model + * @throws DbException + * @author xaboy + * @day 2020-04-28 + */ + public function createTemporaryQrcode($id, $type, $qtcode_id = null) + { + $qrcode = WechatService::create()->getApplication()->qrcode; + $data = $qrcode->temporary($id, 30 * 24 * 3600)->toArray(); + $data['qrcode_url'] = $data['url']; + $data['expire_seconds'] = $data['expire_seconds'] + time(); + $data['url'] = $qrcode->url($data['ticket']); + $data['status'] = 1; + $data['third_id'] = $id; + $data['third_type'] = $type; + if ($qtcode_id) { + return $this->dao->update($qtcode_id, $data); + } else { + return $this->dao->create($data); + } + } + + /** + * @param $id + * @param $type + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-28 + */ + public function createForeverQrcode($id, $type) + { + $qrcode = WechatService::create()->getApplication()->qrcode; + $data = $qrcode->forever($id)->toArray(); + $data['qrcode_url'] = $data['url']; + $data['url'] = $qrcode->url($data['ticket']); + $data['expire_seconds'] = 0; + $data['status'] = 1; + $data['third_id'] = $id; + $data['third_type'] = $type; + return self::create($data); + } + + /** + * @param $type + * @param $id + * @return BaseDao|array|int|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function getTemporaryQrcode($type, $id) + { + $qrInfo = $this->dao->getTemporaryQrcode($type, $id); + if (!$qrInfo || (!$qrInfo['expire_seconds'] || $qrInfo['expire_seconds'] < time())) { + $qrInfo = $this->createTemporaryQrcode($type, $id); + } + if (!isset($qrInfo['ticket']) || !$qrInfo['ticket']) throw new ValidateException('临时二维码获取错误'); + return $qrInfo; + } + + /** + * @param $type + * @param $id + * @return BaseDao|array|Model|null + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function getForeverQrcode($type, $id) + { + $qrInfo = $this->dao->getForeverQrcode($type, $id); + if (!$qrInfo) { + $qrInfo = $this->createForeverQrcode($id, $type); + } + if (!isset($qrInfo['ticket']) || !$qrInfo['ticket']) throw new ValidateException('二维码获取错误'); + return $qrInfo; + } + +} diff --git a/app/common/repositories/wechat/WechatReplyRepository.php b/app/common/repositories/wechat/WechatReplyRepository.php new file mode 100644 index 00000000..6331cbd5 --- /dev/null +++ b/app/common/repositories/wechat/WechatReplyRepository.php @@ -0,0 +1,256 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\wechat; + + +use app\common\dao\BaseDao; +use app\common\dao\wechat\WechatReplyDao; +use app\common\model\wechat\WechatReply; +use app\common\repositories\BaseRepository; +use crmeb\services\WechatService; +use EasyWeChat\Message\Image; +use EasyWeChat\Message\News; +use EasyWeChat\Message\Text; +use EasyWeChat\Message\Voice; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\Model; + +/** + * Class WechatReplyRepository + * @package app\common\repositories\wechat + * @author xaboy + * @day 2020-04-24 + * @mixin WechatReplyDao + */ +class WechatReplyRepository extends BaseRepository +{ + /** + * WechatReplyRepository constructor. + * @param WechatReplyDao $dao + */ + public function __construct(WechatReplyDao $dao) + { + $this->dao = $dao; + } + + /** + * @param array $where + * @param int $page + * @param int $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function getLst(array $where, int $page, int $limit) + { + $query = $this->dao->search($where); + $count = $query->count(); + $list = $query->setOption('field', [])->field('wechat_reply_id,key,type,status,create_time')->page($page, $limit)->select(); + + return compact('list', 'count'); + } + + /** + * @param string $key + * @param string $type + * @param array $data + * @param int $status + * @param int $hidden + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-24 + */ + public function save(string $key, string $type, array $data, int $status = 1, int $hidden = 0) + { + $method = 'tidy' . ucfirst($type); + $reply = $this->dao->keyByReply($key); + $data = $this->{$method}($data, $reply); + if ($reply) { + $reply->save(compact('status', 'data', 'hidden', 'type')); + } else { + $this->dao->create(compact('key', 'type', 'data', 'status', 'hidden')); + } + } + + /** + * @param $id + * @param array $data + * @param int $hidden + * @return bool + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function updateReply($id, array $data, int $hidden = 0) + { + + $method = 'tidy' . ucfirst($data['type']); + $reply = $this->dao->get($id); + $data['data'] = $this->{$method}($data['data'], $reply); + $data['hidden'] = $hidden; + return $reply->save($data); + } + + /** + * @param array $data + * @param int $hidden + * @return BaseDao|Model + * @author xaboy + * @day 2020-04-27 + */ + public function create(array $data, int $hidden = 0) + { + $method = 'tidy' . ucfirst($data['type']); + $data['data'] = $this->{$method}($data['data'], null); + $data['hidden'] = $hidden; + return $this->dao->create($data); + } + + /** + * @param string $key + * @return array|News|Text|Image|Voice|void + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function reply(string $key) + { + $reply = $this->dao->keyByValidData($key); + if (!$reply && $key != 'default') + $reply = $this->dao->keyByValidData('default'); + if (!$reply) return; + if ($reply['type'] == 'voice') + return WechatService::voiceMessage($reply['data']['media_id']); + else if ($reply['type'] == 'image') + return WechatService::imageMessage($reply['data']['media_id']); + else if ($reply['type'] == 'news') + return WechatService::newsMessage($reply['data']['list']); + else if (isset($reply['data']['content'])) { + return WechatService::textMessage($reply['data']['content']); + } + } + + /** + * @param $data + * @param WechatReply|null $reply + * @return array + * @author xaboy + * @day 2020-04-24 + */ + public function tidyText($data, ?WechatReply $reply) + { + $res = []; + if (!isset($data['content']) || !$data['content']) + throw new ValidateException('请输入回复信息内容'); + $res['content'] = $data['content']; + return $res; + } + + /** + * @param $data + * @param WechatReply|null $reply + * @return array|mixed|null + * @author xaboy + * @day 2020-04-24 + */ + public function tidyImage($data, ?WechatReply $reply) + { + if (!isset($data['src']) || !$data['src']) + throw new ValidateException('请上传回复的图片'); + $res = null; + if ($reply) { + $replyData = $reply->getAttr('data'); + if (isset($replyData['src']) && $replyData['src'] == $data['src']) + $res = $replyData; + } + if (is_null($res)) { + $res = [ + 'src' => $data['src'] + ]; + + if (!file_exists(app()->getRootPath() . 'public' . $data['src'])) + throw new ValidateException('图片文件不存在'); + + $material = WechatService::create()->getApplication()->material->uploadImage(app()->getRootPath() . 'public' . $data['src']); + $res['media_id'] = $material->media_id; + } + return $res; + } + + /** + * @param $data + * @param WechatReply|null $reply + * @return array|mixed|null + * @author xaboy + * @day 2020-04-24 + */ + public static function tidyVoice($data, ?WechatReply $reply) + { + if (!isset($data['src']) || !$data['src']) + throw new ValidateException('请上传回复的声音'); + $res = null; + if ($reply) { + $replyData = $reply->getAttr('data'); + if (isset($replyData['src']) && $replyData['src'] == $data['src']) + $res = $replyData; + } + + if (is_null($res)) { + $res = [ + 'src' => $data['src'] + ]; + + if (!file_exists(app()->getRootPath() . 'public' . $data['src'])) + throw new ValidateException('声音文件不存在'); + + $material = WechatService::create()->getApplication()->material->uploadVoice(app()->getRootPath() . 'public' . $data['src']); + $res['media_id'] = $material->media_id; + } + + return $res; + } + + /** + * @param $params + * @param WechatReply|null $reply + * @return mixed + * @author xaboy + * @day 2020-04-24 + */ + public static function tidyNews($params, ?WechatReply $reply) + { + if (!isset($params['list']) || !count($params['list'])) + throw new ValidateException('请选择图文消息'); + $siteUrl = systemConfig('site_url'); + $data = $params['list']; + foreach ($data as $k => $v) { + if (empty($v['url'])) $data[$k]['url'] = rtrim($siteUrl, '/') . '/pages/news_details/index?id=' . $v['article_id']; + if ($v['image_input']) $data[$k]['image'] = $v['image_input']; + } + $params['list'] = $data; + return $params; + } +} diff --git a/app/common/repositories/wechat/WechatUserRepository.php b/app/common/repositories/wechat/WechatUserRepository.php new file mode 100644 index 00000000..50b1c1d3 --- /dev/null +++ b/app/common/repositories/wechat/WechatUserRepository.php @@ -0,0 +1,331 @@ + +// +---------------------------------------------------------------------- + + +namespace app\common\repositories\wechat; + + +use app\common\dao\wechat\WechatUserDao; +use app\common\repositories\article\ArticleRepository; +use app\common\repositories\BaseRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\SendNewsJob; +use crmeb\services\WechatUserGroupService; +use crmeb\services\WechatUserTagService; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +/** + * Class WechatUserRepository + * @package app\common\repositories\wechat + * @author xaboy + * @day 2020-04-28 + * @mixin WechatUserDao + */ +class WechatUserRepository extends BaseRepository +{ + /** + * WechatUserRepository constructor. + * @param WechatUserDao $dao + */ + public function __construct(WechatUserDao $dao) + { + $this->dao = $dao; + } + + /** + * @param string $openId + * @param array $userInfo + * @param bool $mode + * @return mixed|void + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-28 + */ + public function syncUser(string $openId, array $userInfo, bool $mode = false, $createUser = true) + { + if (($mode && (!isset($userInfo['subscribe']) || !$userInfo['subscribe'])) || !isset($userInfo['openid'])) + return; + $wechatUser = null; + $userInfo['nickname'] = filter_emoji(($userInfo['nickname'] ?? '') ?: ('微信用户U' . substr(uniqid(true, true), -6))); + if (isset($userInfo['unionid'])) + $wechatUser = $this->dao->unionIdByWechatUser($userInfo['unionid']); + if (!$wechatUser) + $wechatUser = $this->dao->openIdByWechatUser($openId); + + unset($userInfo['qr_scene'], $userInfo['qr_scene_str'], $userInfo['qr_scene_str'], $userInfo['subscribe_scene']); + + if (isset($userInfo['tagid_list'])) { + $userInfo['tagid_list'] = implode(',', $userInfo['tagid_list']); + } + + return Db::transaction(function () use ($createUser, $mode, $userInfo, $wechatUser) { + if ($wechatUser) { + if ($mode) { + unset($userInfo['nickname']); + } + $wechatUser->save($userInfo); + } else { + $wechatUser = $this->dao->create($userInfo); + } + if (!$createUser) return [$wechatUser]; + /** @var UserRepository $userRepository */ + $userRepository = app()->make(UserRepository::class); + $user = $userRepository->syncWechatUser($wechatUser); + return [$wechatUser, $user]; + }); + } + + /** + * @param string $routineOpenid + * @param array $routine + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-11 + */ + public function syncRoutineUser(string $routineOpenid, array $routine, $createUser = true) + { + $routineInfo = []; + $routineInfo['nickname'] = filter_emoji($routine['nickName']);//姓名 + $routineInfo['sex'] = $routine['gender'] ?? 0;//性别 + $routineInfo['language'] = $routine['language'] ?? '';//语言 + $routineInfo['city'] = $routine['city'] ?? '';//城市 + $routineInfo['province'] = $routine['province'] ?? '';//省份 + $routineInfo['country'] = $routine['country'] ?? '';//国家 + $routineInfo['headimgurl'] = $routine['avatarUrl'];//头像 + $routineInfo['routine_openid'] = $routineOpenid;//openid + $routineInfo['session_key'] = $routine['session_key'] ?? '';//会话密匙 + $routineInfo['unionid'] = $routine['unionId'];//用户在开放平台的唯一标识符 + $routineInfo['user_type'] = 'routine';//用户类型 + $wechatUser = null; + if ($routineInfo['unionid']) + $wechatUser = $this->dao->unionIdByWechatUser($routineInfo['unionid']); + if (!$wechatUser) + $wechatUser = $this->dao->routineIdByWechatUser($routineOpenid); + return Db::transaction(function () use ($createUser, $routineInfo, $wechatUser) { + if ($wechatUser) { + $routineInfo['nickname'] = $wechatUser['nickname']; + $routineInfo['headimgurl'] = $wechatUser['headimgurl']; + $wechatUser->save($routineInfo); + } else { + $wechatUser = $this->dao->create($routineInfo); + } + if (!$createUser) return [$wechatUser]; + /** @var UserRepository $userRepository */ + $userRepository = app()->make(UserRepository::class); + $user = $userRepository->syncWechatUser($wechatUser, 'routine'); + return [$wechatUser, $user]; + }); + } + + /** + * @param string $routineOpenid + * @param array $routine + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-11 + */ + public function syncAppUser(string $unionId, array $userInfo, $type = 'wechat', $createUser = true) + { + $wechatInfo = []; + $wechatInfo['nickname'] = filter_emoji($userInfo['nickName'] ?? ($userInfo['nickname'] ?? ''));//姓名 + $wechatInfo['sex'] = $userInfo['gender'] ?? 0;//性别 + $wechatInfo['city'] = $userInfo['city'] ?? '';//城市 + $wechatInfo['province'] = $userInfo['province'] ?? '';//省份 + $wechatInfo['country'] = $userInfo['country'] ?? '';//国家 + $wechatInfo['headimgurl'] = $userInfo['avatarUrl'] ?? ($userInfo['headimgurl'] ?? '');//头像 + $wechatInfo['unionid'] = $unionId;//用户在开放平台的唯一标识符 + $wechatInfo['user_type'] = 'app';//用户类型 + $wechatUser = $this->dao->unionIdByWechatUser($unionId); + + return Db::transaction(function () use ($createUser, $type, $wechatInfo, $wechatUser) { + if ($wechatUser) { + unset($wechatInfo['nickname']); + $wechatUser->save($wechatInfo); + } else { + $wechatUser = $this->dao->create($wechatInfo); + } + if (!$createUser) { + return [$wechatUser]; + } + /** @var UserRepository $userRepository */ + $userRepository = app()->make(UserRepository::class); + $user = $userRepository->syncWechatUser($wechatUser, $type); + return [$wechatUser, $user]; + }); + } + + /** + * @param array $where + * @param $page + * @param $limit + * @return array + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function getList(array $where, $page, $limit) + { + $query = $this->dao->search($where); + $count = $query->count($this->dao->getPk()); + $list = $query->setOption('field', [])->field('uid,openid,nickname,headimgurl,sex,country,province,city,subscribe') + ->page($page, $limit)->select()->each(function ($item) { + $item['subscribe_time'] = $item['subscribe_time'] ? date('Y-m-d H:i', $item['subscribe_time']) : ''; + return $item; + }); + return compact('count', 'list'); + } + + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function updateUserTagForm($id) + { + $wechatUserTagService = new WechatUserTagService(); + $lst = $wechatUserTagService->lst(); + $user = $this->dao->get($id); + return Elm::createForm(Route::buildUrl('wechat/user/tag', ['id' => $id]), [ + Elm::select('tag_id', '用户标签', explode(',', $user->tagid_list))->options(function () use ($lst) { + $options = []; + foreach ($lst as $item) { + $options[] = ['value' => $item['id'], 'label' => $item['name']]; + } + return $options; + })->multiple(true) + ])->setTitle('编辑用户标签'); + } + + /** + * @param $id + * @param array $tags + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function updateTag($id, array $tags) + { + $user = $this->dao->get($id); + $oTags = explode(',', $user->tagid_list); + $user->save(['tagid_list' => implode(',', $tags)]); + $wechatUserTagService = (new WechatUserTagService())->userTag(); + foreach ($oTags as $tag) { + $wechatUserTagService->batchUntagUsers([$user->openid], $tag); + } + foreach ($tags as $tag) { + $wechatUserTagService->batchTagUsers([$user->openid], $tag); + } + } + + + /** + * @param $id + * @return Form + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function updateUserGroupForm($id) + { + $wechatUserGroupService = new WechatUserGroupService(); + $lst = $wechatUserGroupService->lst(); + $user = $this->dao->get($id); + return Elm::createForm(Route::buildUrl('wechat/user/group', ['id' => $id]), [ + Elm::select('group_id', '用户标签', (string)$user->groupid)->options(function () use ($lst) { + $options = []; + foreach ($lst as $item) { + $options[] = ['value' => $item['id'], 'label' => $item['name']]; + } + return $options; + }) + ])->setTitle('编辑用户分组'); + } + + /** + * @param $id + * @param $groupid + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function updateGroup($id, $groupid) + { + $user = $this->dao->get($id); + $user->save(['groupid' => $groupid]); + $wechatUserGroupService = (new WechatUserGroupService())->userGroup(); + $wechatUserGroupService->moveUser($user->openid, $groupid); + } + + + /** + * @param $id + * @param array $ids + * @author xaboy + * @day 2020-05-11 + */ + public function sendNews($id, array $ids) + { + if (!count($ids)) return; + /** @var ArticleRepository $make */ + $make = app()->make(ArticleRepository::class); + $articles = $make->wechatNewIdByData($id); + $news = []; + foreach ($articles as $article) { + $news[] = [ + 'title' => $article['title'], + 'image' => $article['image_input'], + 'date' => $article['create_time'], + 'description' => $article['synopsis'], + 'id' => $article['article_id'] + ]; + } + $make = app()->make(UserRepository::class); + foreach ($ids as $_id) { + $user = $make->get($_id); + if ($this->dao->isSubscribeWechatUser($user->wechat_user_id)) { + Queue::push(SendNewsJob::class, [$user->wechat_user_id, $news]); + } + } + } + +} diff --git a/app/controller/Install.php b/app/controller/Install.php new file mode 100644 index 00000000..55e331e0 --- /dev/null +++ b/app/controller/Install.php @@ -0,0 +1,854 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller; + +use crmeb\basic\BaseController; +use Redis; +use think\App; +use think\Exception; +use think\exception\ValidateException; +use think\facade\Config; +use think\facade\View; +use think\Request; +use think\Response; +use Throwable; +use ZipArchive; +use ZipStream\ZipStream; + +class Install //extends BaseController +{ + + /** + * Request实例 + * @var Request + */ + protected $request; + + /** + * 应用实例 + * @var App + */ + protected $app; + /** + * sql文件 + * @var App + */ + public $sqlFile = 'crmeb_merchant.sql'; + /** + * 配置文件 + * @var App + */ + public $configFile = '.env'; + public $env; + public $installHost; + public $_url; + + public function __construct(App $app) + { + if (file_exists(__DIR__ . '/../../install/install.lock')) { + throw new ValidateException('你已经安装过该系统,如果想重新安装,请先删除install目录下的 install.lock 文件,然后再安装。'); + } + if (!file_exists(__DIR__ . '/../../install/' . $this->sqlFile)) { + throw new ValidateException('缺少数据库文件:"install/'.$this->sqlFile.'"'); + } + if (!file_exists(__DIR__ . '/../../install/' . $this->configFile)) { + throw new ValidateException('缺少配置文件:"install/'.$this->configFile.'"'); + } + $this->app = $app; + $this->request = $this->app->request; + $this->env = []; + $this->installHost = $this->request->domain(); + if (substr($this->installHost, 0, 5) == 'https'){ + $this->_url = str_replace('//' ,'\\\/\\\/', $this->installHost); + } else { + $this->_url = str_replace('http://' ,'http:\\\/\\\/', $this->installHost); + } + } + + /** + * TODO 1 开始安装 + * @return string + * @author Qinii + * @day 2020-07-16 + */ + public function begin() + { + return View::fetch('/install/step1'); + } + + /** + * TODO 2 环境检测 + * @return string + * @author Qinii + * @day 2020-07-16 + */ + public function environment() + { + $phpv = @ phpversion(); + $os = PHP_OS; + $tmp = function_exists('gd_info') ? gd_info() : array(); + $max_execution_time = ini_get('max_execution_time'); + $allow_reference = (ini_get('allow_call_time_pass_reference') ? '[√]On' : '[×]Off'); + $allow_url_fopen = (ini_get('allow_url_fopen') ? '[√]On' : '[×]Off'); + $safe_mode = (ini_get('safe_mode') ? '[×]On' : '[√]Off'); + + + + $err = 0; + if (empty($tmp['GD Version'])) { + $gd = '[×]Off'; + $err++; + } else { + $gd = '[√]On ' . $tmp['GD Version']; + } + if (function_exists('mysqli_connect')) { + $mysql = ' 已安装'; + } else { + $mysql = ' 请安装mysqli扩展'; + $err++; + } + if (ini_get('file_uploads')) { + $uploadSize = ' ' . ini_get('upload_max_filesize'); + } else { + $uploadSize = '禁止上传'; + } + if (function_exists('session_start')) { + $session = ' 支持'; + } else { + $session = ' 不支持'; + $err++; + } + if (extension_loaded('zip')) { + $zip = '[√]支持 '; + } else { + $zip = '[×]不支持'; + $err++; + } + if (extension_loaded(('redis'))) { + $redis = '[√]支持 '; + } else { + $redis = '[×]不支持'; + $err++; + } + if (extension_loaded('swoole')) { + $swoole = '[√]支持 '; + } else { + $swoole = '[×]不支持'; + $err++; + } + if (extension_loaded('swoole_loader')) { + $swooleCompiler = '[√]支持 '; + } else { + $swooleCompiler = ' 请安装swoole_loader扩展'; + $err++; + } + + if (function_exists('curl_init')) { + $curl = '[√]支持 '; + } else { + $curl = '[×]不支持'; + $err++; + } + + if (function_exists('bcadd')) { + $bcmath = '[√]支持 '; + } else { + $bcmath = '[×]不支持'; + $err++; + } + if (function_exists('openssl_encrypt')) { + $openssl = '[√]支持 '; + } else { + $openssl = '[×]不支持'; + $err++; + } + if (function_exists('finfo_open')) { + $finfo_open = '[√]支持 '; + } else { + $finfo_open = '[×]不支持'; + $err++; + } + $folder = array( + 'public/install', + 'public/uploads', + 'runtime', + '.env', + ); + //必须开启函数 + if (function_exists('file_put_contents')) { + $file_put_contents = '[√]开启 '; + } else { + $file_put_contents = '[×]关闭'; + $err++; + } + if (function_exists('imagettftext')) { + $imagettftext = '[√]开启 '; + } else { + $imagettftext = '[×]关闭'; + $err++; + } + if (function_exists('pcntl_alarm')) { + $pcntl_alarm = '[√]开启 '; + } else { + $pcntl_alarm = '[×]关闭'; + $err++; + } + if (function_exists('proc_open')) { + $proc_open = '[√]开启 '; + } else { + $proc_open = '[×]关闭'; + $err++; + } + if (function_exists('pcntl_signal')) { + $pcntl_signal = '[√]开启 '; + } else { + $pcntl_signal = '[×]关闭'; + $err++; + } + View::assign([ + 'max_execution_time' => $max_execution_time, + 'allow_reference' => $allow_reference, + 'swooleCompiler' => $swooleCompiler, + 'phpv' => $phpv, + 'allow_url_fopen' => $allow_url_fopen, + 'safe_mode' => $safe_mode, + 'gd' => $gd, + 'mysql' => $mysql, + 'uploadSize' => $uploadSize, + 'redis' => $redis, + 'session' => $session, + 'swoole' => $swoole, + 'curl' => $curl, + 'bcmath' => $bcmath, + 'openssl' => $openssl, + 'finfo_open' => $finfo_open, + 'file_put_contents' => $file_put_contents, + 'imagettftext' => $imagettftext, + 'folder' => $folder, + 'zip' => $zip, + 'proc_open' => $proc_open, + 'pcntl_alarm' => $pcntl_alarm, + 'pcntl_signal' => $pcntl_signal, + ]); + return View::fetch('/install/step2', ['err' => $err]); + } + + /** + * TODO 3 数据库填写表单 + * @return string + * @author Qinii + * @day 2020-07-15 + */ + public function databases() + { + return View::fetch('/install/step3'); + } + /** + * TODO 4 安装数据库 + * @return string + * @author Qinii + * @day 2020-07-16 + */ + public function create() + { + $data = $this->request->params(['dbhost', 'dbport', 'dbname', 'dbuser', 'dbpw', ['dbprefix','eb_'], 'manager', 'manager_pwd', ['rbhost', '127.0.0.1'], ['rbport', 6379], 'rbpw', ['rbselect', 0], 'demo']); + $mysql = $this->checkDatabsaces($data); + if ($mysql !== 1) throw new ValidateException('数据库链接失败' . $mysql); + return View::fetch('/install/step4', ['data' => $data]); + } + + /** + * TODO 5 安装完成 + * @return string + * @author Qinii + * @day 2020-07-16 + */ + public function end() + { + $ip = $this->get_client_ip(); + $server = $this->request->server(); + $host = $server['HTTP_HOST']; + $version = get_crmeb_version('未知'); + $this->installlog(); + @touch(__DIR__ . '/../../install/install.lock'); + $this->unzip(); + return View::fetch('/install/step5', [ + 'host' => $host, + 'ip' => $ip, + 'version' => $version, + 'merchant' => Config::get('admin.merchant_prefix'), + 'system' => Config::get('admin.admin_prefix'), + ]); + } + + /** + * TODO 链接数据库 读取sql + * @param $n + * @return array + * @author Qinii + * @day 2020-07-16 + */ + public function perform($n) + { + $data = $this->request->param(); + $dbName = strtolower(trim($data['dbname'])); + $conn = @mysqli_connect($data['dbhost'], $data['dbuser'], $data['dbpw'], NULL, $data['dbport']); + if (mysqli_connect_errno($conn)) { + throw new ValidateException("连接数据库失败!" . mysqli_connect_error($conn)); + } + if (!mysqli_select_db($conn, $dbName)) { + //创建数据时同时设置编码 + if (!mysqli_query($conn, "CREATE DATABASE IF NOT EXISTS `" . $dbName . "` DEFAULT CHARACTER SET utf8;")) { + throw new ValidateException('数据库 ' . $dbName . ' 不存在,也没权限创建新的数据库!'); + } + } + mysqli_select_db($conn, $dbName); + mysqli_query($conn, 'SET NAMES utf8;'); + //读取数据文件 + $sqldata = file_get_contents(__DIR__ . '/../../install/' . $this->sqlFile); + $sqlFormat = $this->sql_split($sqldata, $data['dbprefix']); + $counts = count($sqlFormat); + if ($n <= $counts && isset($sqlFormat[$n])) { + $sql = trim($sqlFormat[$n]); + $message = $this->install($sql, $conn, $data['dbprefix']); + $n++; + } else { + if ($data['demo'] == '') + $this->clear($conn, $data['dbprefix']); + $this->setConfig($data); + $message = $this->setDatabase($conn, $data); + $n = -1; + } + return [ + 'n' => $n, + 'msg' => $message + ]; + } + + + /** + * TODO 执行数据库文件安装 + * @param $sql + * @param $conn + * @param $dbPrefix + * @return string + * @author Qinii + * @day 2020-07-16 + */ + public function install($sql, $conn, $dbPrefix) + { + // 建表 + if (strstr($sql, 'CREATE TABLE')) { + preg_match('/CREATE TABLE `eb_([^ ]*)`/is', $sql, $matches); + mysqli_query($conn, "DROP TABLE IF EXISTS `$matches[1]"); + $sql = str_replace('`eb_', '`' . $dbPrefix, $sql);//替换表前缀 + $ret = mysqli_query($conn, $sql); + if ($ret) { + $message = '
  • 创建数据表[' . $dbPrefix . $matches[1] . ']完成!' . date('Y-m-d H:i:s') . '
  • '; + } else { + $message = '
  • 创建数据表[' . $dbPrefix . $matches[1] . ']失败!' . date('Y-m-d H:i:s') . '
  • '; + } + + } //插入数据 + else { + $message = ''; + if (trim($sql) !== '') { + $sql = str_replace('`eb_', '`' . $dbPrefix, $sql);//替换表前缀 + $sql = str_replace('https://mer1.crmeb.net', $this->installHost , $sql); + $sql = str_replace('https:\\\/\\\/mer1.crmeb.net', $this->_url , $sql); + $ret = mysqli_query($conn, $sql); + $sql = htmlspecialchars($sql); + $msg = substr($sql, 0, 30); + if ($ret) { + $message = '
  • 执行 [' . $msg . '...]成功!' . date('Y-m-d H:i:s') . '
  • '; + } else { + $message = '
  • 执行[' . $msg . '..]失败!' . date('Y-m-d H:i:s') . '
  • '; + } + } + } + return $message; + } + + /** + * TODO 清除测试数据 + * @param $conn + * @param $dbPrefix + * @author Qinii + * @day 2020-07-16 + */ + public function clear($conn, $dbPrefix) + { + $result = mysqli_query($conn, "show tables"); + $tables = mysqli_fetch_all($result);//参数MYSQL_ASSOC、MYSQLI_NUM、MYSQLI_BOTH规定产生数组类型 + $bl_table = array( + 'eb_system_admin', + 'eb_system_menu', + 'eb_system_role', + 'eb_system_group', + 'eb_system_group_data', + 'eb_system_city', + 'eb_express', + 'eb_system_config', + 'eb_system_config_classify', + 'eb_system_config_value', + 'eb_template_message', + 'system_notice_config', + 'eb_city_area', + 'eb_diy', + 'eb_page_category', + 'eb_page_link', + 'eb_system_notice_config' + ); + foreach ($bl_table as $k => $v) { + $bl_table[$k] = str_replace('eb_', $dbPrefix, $v); + } + + foreach ($tables as $key => $val) { + if (!in_array($val[0], $bl_table)) { + mysqli_query($conn, "truncate table " . $val[0]); + } + } + } + + /** + * TODO 创建.env文件 + * @param $data + * @author Qinii + * @day 2020-07-16 + */ + public function setConfig($data) + { + //读取配置文件,并替换真实配置数据1 + $strConfig = file_get_contents(__DIR__ . '/../../install/' . $this->configFile); + //'dbhost', 'dbport', 'dbname', 'dbuser', 'dbpw', 'dbprefix', 'manager', 'manager_pwd', ['rbhost', '127.0.0.1'], ['rbport', 6379], 'rbpw', ['rbselect', 0] + $strConfig = str_replace('#DB_HOST#', $data['dbhost'], $strConfig); + $strConfig = str_replace('#DB_NAME#', $data['dbname'], $strConfig); + $strConfig = str_replace('#DB_USER#', $data['dbuser'], $strConfig); + $strConfig = str_replace('#DB_PWD#', $data['dbpw'], $strConfig); + $strConfig = str_replace('#DB_PORT#', $data['dbport'], $strConfig); + $strConfig = str_replace('#DB_PREFIX#', $data['dbprefix'], $strConfig); + $strConfig = str_replace('#DB_CHARSET#', 'utf8', $strConfig); + //redis数据库信息 + $strConfig = str_replace('#RB_HOST#', $data['rbhost'], $strConfig); + $strConfig = str_replace('#RB_PORT#', $data['rbport'], $strConfig); + $strConfig = str_replace('#RB_PWD#', $data['rbpw'], $strConfig); + $strConfig = str_replace('#RB_SELECT#', $data['rbselect'], $strConfig); + $strConfig = str_replace('#APP_KEY#', md5(time() . random_int(10000000, 99999999)), $strConfig); + @chmod(__DIR__ . '/../../.env', 0777); + @file_put_contents(__DIR__ . '/../../.env', $strConfig); //数据库配置文件的地址 + } + + /** + * TODO 修改后台管理员用户 + * @param $conn + * @param $data + * @return string + * @author Qinii + * @day 2020-07-16 + */ + public function setDatabase($conn, $data) + { + $time = date('Y-m-d H:i:s'); + $ip = $this->get_client_ip(); + $ip = empty($ip) ? "0.0.0.0" : $ip; + $password = password_hash(trim($data['manager_pwd']), PASSWORD_BCRYPT); + mysqli_query($conn, "truncate table {$data['dbprefix']}system_admin"); + $addadminsql = "INSERT INTO `{$data['dbprefix']}system_admin` (`admin_id`, `account`, `pwd`, `real_name`, `roles`, `last_ip`, `last_time`, `create_time`, `login_count`, `level`, `status`, `is_del`) VALUES +(1, '" . $data['manager'] . "', '" . $password . "', '', '1', '" . $ip . "','$time' , '$time', 0, 0, 1, 0)"; + $res = mysqli_query($conn, $addadminsql); + if ($res) { + $message = '成功添加管理员
    成功写入配置文件
    安装完成.'; + } else { + $message = '添加管理员失败
    成功写入配置文件
    安装完成.'; + } + return $message; + } + + /** + * TODO 检测数据库链接是否成功以及版本 + * @param $data + * @return false|int|string + * @author Qinii + * @day 2020-07-16 + */ + public function checkDatabsaces($data) + { + $dbName = strtolower(trim($data['dbname'])); + $conn = @mysqli_connect($data['dbhost'], $data['dbuser'], $data['dbpw'], NULL, $data['dbport']); + if (mysqli_connect_errno($conn)) return 0; + $result = mysqli_query($conn, "SELECT @@global.sql_mode"); + $result = $result->fetch_array(); + $version = mysqli_get_server_info($conn); + if ($version < 5.6) return (json_encode(-4)); + + if (strstr($result[0], 'STRICT_TRANS_TABLES') || strstr($result[0], 'STRICT_ALL_TABLES') || strstr($result[0], 'TRADITIONAL') || strstr($result[0], 'ANSI')) + return ($version < 8.0) ? -1 : -2; + + $result = mysqli_query($conn, "select count(table_name) as c from information_schema.`TABLES` where table_schema='$dbName'"); + $result = $result->fetch_array(); + if ($result['c'] > 0) return -3; + return 1; + } + + /** + * TODO 验证数据库及redis是否正常 + * @return false|int|string + * @author Qinii + * @day 2020-07-15 + */ + public function databasesCheck() + { + $data = $this->request->params(['dbhost', 'dbport', 'dbname', 'dbuser', 'dbpw',['dbprefix','eb_'], ['rbhost', '127.0.0.1'], ['rbport', 6379], 'rbpw', ['rbselect', 0]]); + // mysql 检测 + $mysql = $this->checkDatabsaces($data); + if ($mysql !== 1) return $mysql; + // redis检测 + try { + $redis = new Redis(); + $redis->connect($data['rbhost'], $data['rbport']); + if ($data['rbpw']) $redis->auth($data['rbpw']); + if ($data['rbselect']) $redis->select($data['rbselect']); + $res = $redis->set('install', 1, 10); + return $res ? 1 : -5; + } catch (Throwable $e) { + return -5; + } + } + + /** + * TODO 安装记录文件生成 + * @author Qinii + * @day 2020-07-16 + */ + public function installlog() + { + $mt_rand_str = $this->sp_random_string(6); + $str_constant = "request->server(); + if (isset($server['REMOTE_ADDR'])) + $ip = $server['REMOTE_ADDR']; + // IP地址合法验证 + $ip = (false !== ip2long($ip)) ? $ip : '0.0.0.0'; + return $ip; + } + + /** + * 生成基础文件 + * @Author:Qinii + * @Date: 2020/8/31 + */ + public function unzip() + { + update_crmeb_compiled(); + } + + + /** + * TODO swoole_loader 安装向导 + * @Author:Qinii + * @Date: 2020/9/10 + */ + public function swooleCompiler() + { + // Check os type + $this->env['os'] = []; + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $this->env['os']['name'] = "windows"; + $this->env['os']['raw_name'] = php_uname(); + } else { + $this->env['os']['name'] = "unix"; + $this->env['os']['raw_name'] = php_uname(); + } + // Check php + $this->env['php'] = []; + $this->env['php']['version'] = phpversion(); + // Check run mode + $sapi_type = php_sapi_name(); + if ("cli" == $sapi_type) { + $this->env['php']['run_mode'] = "cli"; + } else { + $this->env['php']['run_mode'] = "web"; + } + // Check php bit + if (PHP_INT_SIZE == 4) { + $this->env['php']['bit'] = 32; + } else { + $this->env['php']['bit'] = 64; + } + $this->env['php']['sapi'] = $sapi_type; + $this->env['php']['ini_loaded_file'] = php_ini_loaded_file(); + $this->env['php']['ini_scanned_files'] = php_ini_scanned_files(); + $this->env['php']['loaded_extensions'] = get_loaded_extensions(); + $this->env['php']['incompatible_extensions'] = ['xdebug', 'ionCube', 'zend_loader']; + $this->env['php']['loaded_incompatible_extensions'] = []; + $this->env['php']['extension_dir'] = ini_get('extension_dir'); + // Check incompatible extensions + if (is_array($this->env['php']['loaded_extensions'])) { + foreach ($this->env['php']['loaded_extensions'] as $loaded_extension) { + foreach ($this->env['php']['incompatible_extensions'] as $incompatible_extension) { + if (strpos(strtolower($loaded_extension), strtolower($incompatible_extension)) !== false) { + $this->env['php']['loaded_incompatible_extensions'][] = $loaded_extension; + } + } + } + } + $this->env['php']['loaded_incompatible_extensions'] = array_unique($this->env['php']['loaded_incompatible_extensions']); + // Parse System Environment Info + $sysInfo = $this->w_getSysInfo(); + // Check php thread safety + $this->env['php']['raw_thread_safety'] = isset($sysInfo['thread_safety']) ? $sysInfo['thread_safety'] : false; + if (isset($sysInfo['thread_safety'])) { + $this->env['php']['thread_safety'] = $sysInfo['thread_safety'] ? '线程安全' : '非线程安全'; + } else { + $this->env['php']['thread_safety'] = '未知'; + } + // Check swoole loader installation + if (isset($sysInfo['swoole_loader']) and isset($sysInfo['swoole_loader_version'])) { + $this->env['php']['swoole_loader']['status'] = $sysInfo['swoole_loader'] ? "已安装" + : '未安装'; + if ($sysInfo['swoole_loader_version'] !== false) { + $this->env['php']['swoole_loader']['version'] = "" . $sysInfo['swoole_loader_version'] . ""; + } else { + $this->env['php']['swoole_loader']['version'] = '未知'; + } + } else { + $this->env['php']['swoole_loader']['status'] = '未安装'; + $this->env['php']['swoole_loader']['version'] = '未知'; + } + $this->html($sysInfo); + } + + /** + * 页面输出内容 + * @Author:Qinii + * @Date: 2020/9/10 + * @param $this ->>env + * @param $sysInfo + */ + public function html($sysInfo) + { + $html = ''; + // Header + $html_header = ' + + + + + + + + %s + + + + '; + $html_header = sprintf($html_header, 'CRMEB Swoole Compiler 安装向导'); + $html_body = '
    '; + $html_body_nav = '
    '; + $html_body_nav .= '

    CRMEB Swoole Compiler 安装向导

    '; + $html_body_nav .= '

    Version:2.0.2 Date:2019-01-09

    '; + $html_body_nav .= '

    '; + + // Environment information + $html_body_environment = ' +
    +
    检查当前环境
    +
      '; + $html_body_environment .= '
    • 操作系统 : ' . $this->env['os']['raw_name'] . '
    • '; + $html_body_environment .= '
    • PHP版本 : ' . $this->env['php']['version'] . '
    • '; + $html_body_environment .= '
    • PHP运行环境 : ' . $this->env['php']['sapi'] . '
    • '; + $html_body_environment .= '
    • PHP配置文件 : ' . $this->env['php']['ini_loaded_file'] . '
    • '; + $html_body_environment .= '
    • PHP扩展安装目录 : ' . $this->env['php']['extension_dir'] . '
    • '; + $html_body_environment .= '
    • PHP是否线程安全 : ' . $this->env['php']['thread_safety'] . '
    • '; + $html_body_environment .= '
    • 是否安装swoole_loader : ' . $this->env['php']['swoole_loader']['status'] . '
    • '; + if (isset($sysInfo['swoole_loader']) and $sysInfo['swoole_loader']) { + $html_body_environment .= '
    • swoole_loader版本 : ' . $this->env['php']['swoole_loader']['version'] . '
    • '; + } + if ($this->env['php']['bit'] == 32) { + $html_body_environment .= '
    • 温馨提示:当前环境使用的PHP为 ' . $this->env['php']['bit'] . ' 位的PHP,Compiler 目前不支持 Debug 版本或 32 位的PHP,可在 phpinfo() 中查看对应位数,如果误报请忽略此提示
    • '; + } + $html_body_environment .= '
    '; + + // Error infomation + $html_error = ""; + if (!empty($this->env['php']['loaded_incompatible_extensions'])) { + $html_error = '
    +
    +
    错误信息
    +

    %s

    +
    + '; + $err_msg = "当前PHP包含与swoole_compiler_loader扩展不兼容的扩展" . implode(',', $this->env['php']['loaded_incompatible_extensions']) . ",请移除不兼容的扩展。"; + $html_error = sprintf($html_error, $err_msg); + } + + // Check Loader Status + $html_body_loader = '
    '; + if (empty($html_error)) { + $html_body_loader .= '
    '; + $html_body_loader .= '
    安装和配置Swoole Loader
    '; + $phpversion = substr($this->env['php']['version'], 0, 3); + $phpversion = str_replace('.', '', $phpversion); + $loaderFileName = ''; + if ($this->env['os']['name'] == "windows") { + $loaderFileName = 'php_swoole_loader_php' . $phpversion; + if ($this->env['php']['thread_safety'] == '非线程安全') { + $loaderFileName .= '_nzts_x64.dll'; + } else { + $loaderFileName .= '_zts_x64.dll'; + } + } else { + if ($this->env['php']['thread_safety'] != '非线程安全') { + $loaderFileName = 'swoole_loader' . $phpversion . '_zts.so'; + } else { + + $loaderFileName = 'swoole_loader' . $phpversion . '.so'; + } + } + $html_body_loader .= '

    1 - 安装Swoole Loader

    前往根目录 /install/swoole-loader/' . $loaderFileName . '扩展文件上传到当前PHP的扩展安装目录中:

    ' . $this->env['php']['extension_dir'] . '

    '; + $html_body_loader .= '

    2 - 修改php.ini配置(如已修改配置,请忽略此步骤,不必重复添加)

    '; + $html_body_loader .= '编辑此PHP配置文件:' . $this->env['php']['ini_loaded_file'] . ',在此文件底部结尾处加入如下配置
    '; + if ($this->env['os']['name'] == "windows") { + $html_body_loader .= '

    extension=' . $this->env['php']['extension_dir'] . DIRECTORY_SEPARATOR . $loaderFileName . '
    注意:需要名称和刚才上传到当前PHP的扩展安装目录中的文件名一致'; + } else { + $html_body_loader .= '
    extension=' . $this->env['php']['extension_dir'] . DIRECTORY_SEPARATOR . $loaderFileName . '
    注意:需要名称和刚才上传到当前PHP的扩展安装目录中的文件名一致'; + } + $html_body_loader .= '

    '; + $html_body_loader .= '

    3 - 重启服务

    重启或重载PHP配置

    '; + $html_body_loader .= '
    '; + } + + // Body footer + $html_body_footer = '
    +

    CopyRight © 2018 - ' . date('Y') . ' Swoole.com 上海识沃网络科技有限公司

    +
    '; + $html_body .= $html_body_nav . '
    ' . $html_body_environment . $html_error . $html_body_loader . '
    ' . $html_body_footer; + $html_body .= '
    '; + // Footer + $html_footer = ' + + + + + '; + + $html = $html_header . $html_body . $html_footer; + return Response::create()->content($html)->send(); + } + + public function w_getSysInfo() + { + $sysEnv = []; + // Get content of phpinfo + ob_start(); + phpinfo(); + $sysInfo = ob_get_contents(); + ob_end_clean(); + // Explode phpinfo content + if ($this->env['php']['run_mode'] == 'cli') { + $sysInfoList = explode('\n', $sysInfo); + } else { + $sysInfoList = explode('', $sysInfo); + } + foreach ($sysInfoList as $sysInfoItem) { + if (preg_match('/thread safety/i', $sysInfoItem)) { + $sysEnv['thread_safety'] = (preg_match('/(enabled|yes)/i', $sysInfoItem) != 0); + } + if (preg_match('/swoole_loader support/i', $sysInfoItem)) { + $sysEnv['swoole_loader'] = (preg_match('/(enabled|yes)/i', $sysInfoItem) != 0); + } + if (preg_match('/swoole_loader version/i', $sysInfoItem)) { + preg_match('/\d+.\d+.\d+/s', $sysInfoItem, $match); + $sysEnv['swoole_loader_version'] = isset($match[0]) ? $match[0] : false; + } + } + return $sysEnv; + } +} diff --git a/app/controller/View.php b/app/controller/View.php new file mode 100644 index 00000000..a2e3b946 --- /dev/null +++ b/app/controller/View.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller; + + +use crmeb\basic\BaseController; + +class View extends BaseController +{ + public function mobile() + { + $siteName = systemConfig('site_name'); + $https = (parse_url(systemConfig('site_url'))['scheme'] ?? '') == 'https'; + $url = set_http_type($this->request->url(true), $https ? 0 : 1); + $url .= (strpos($url, '?') === false ? '?' : '&'); + $url .= 'inner_frame=1'; + return \think\facade\View::fetch('/mobile/view', compact('siteName', 'url')); + } + + public function h5() + { + if ((!$this->request->isMobile()) && (!$this->request->param('inner_frame')) && !strpos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger')) return $this->mobile(); + $DB = DIRECTORY_SEPARATOR; + return view(app()->getRootPath() . 'public' . $DB . 'index.html'); + } +} diff --git a/app/controller/WechatNotice.php b/app/controller/WechatNotice.php new file mode 100644 index 00000000..4dc86a91 --- /dev/null +++ b/app/controller/WechatNotice.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller; + + +use crmeb\basic\BaseController; +use crmeb\services\WechatService; +use EasyWeChat\Core\Exceptions\InvalidArgumentException; +use EasyWeChat\Server\BadRequestException; +use think\Response; + +/** + * Class WechatNotice + * @package app\controller + * @author xaboy + * @day 2020-04-26 + */ +class WechatNotice extends BaseController +{ + /** + * @return Response + * @throws InvalidArgumentException + * @throws BadRequestException + * @author xaboy + * @day 2020-04-26 + */ + public function serve() + { + ob_clean(); + return WechatService::create()->serve($this->request); + } +} diff --git a/app/controller/admin/Common.php b/app/controller/admin/Common.php new file mode 100644 index 00000000..82719ed5 --- /dev/null +++ b/app/controller/admin/Common.php @@ -0,0 +1,447 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin; + + +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\system\CacheRepository; +use app\common\repositories\system\config\ConfigRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\user\UserVisitRepository; +use crmeb\basic\BaseController; +use crmeb\services\HttpService; +use crmeb\services\UploadService; +use think\facade\Cache; + +/** + * Class Common + * @package app\controller\admin + * @author xaboy + * @day 2020/6/25 + */ +class Common extends BaseController +{ + + /** + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function main() + { + $res = Cache::store('file')->remember(self::class . '@main', function () { + $today = $this->mainGroup('today'); + $yesterday = $this->mainGroup('yesterday'); + $lastWeek = $this->mainGroup(date('Y-m-d', strtotime('- 7day'))); + $lastWeekRate = []; + foreach ($lastWeek as $k => $item) { + $lastWeekRate[$k] = $this->getRate($item, $today[$k], 4); + } + return compact('today', 'yesterday', 'lastWeekRate'); + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + /** + * TODO 上传视频key + * @return \think\response\Json + * @author Qinii + * @day 3/11/22 + */ + public function temp_key() + { + $upload = UploadService::create(); + $re = $upload->getTempKeys(); + return app('json')->success($re); + } + + /** + * @param $date + * @return array + * @author xaboy + * @day 2020/6/25 + */ + protected function mainGroup($date) + { + $userRepository = app()->make(UserRepository::class); + $storeOrderRepository = app()->make(StoreOrderRepository::class); + $merchantRepository = app()->make(MerchantRepository::class); + $userVisitRepository = app()->make(UserVisitRepository::class); + $payPrice = (float)$storeOrderRepository->dayOrderPrice($date); + $userNum = (float)$userRepository->newUserNum($date); + $storeNum = (float)$merchantRepository->dateMerchantNum($date); + $visitUserNum = (float)$userVisitRepository->dateVisitUserNum($date); + $visitNum = (float)$userVisitRepository->dateVisitNum($date); + + return compact('payPrice', 'userNum', 'storeNum', 'visitUserNum', 'visitNum'); + } + + /** + * @param StoreOrderRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function order(StoreOrderRepository $repository) + { + $today = $repository->dayOrderPriceGroup('today')->toArray(); + $yesterday = $repository->dayOrderPriceGroup('yesterday')->toArray(); + $today = array_combine(array_column($today, 'time'), array_column($today, 'price')); + $yesterday = array_combine(array_column($yesterday, 'time'), array_column($yesterday, 'price')); + $time = getTimes(); + $order = []; + foreach ($time as $item) { + $order[] = [ + 'time' => $item, + 'today' => $today[$item] ?? 0, + 'yesterday' => $yesterday[$item] ?? 0, + ]; + } + $todayPrice = $repository->dayOrderPrice('today'); + $yesterdayPrice = $repository->dayOrderPrice('yesterday'); + return app('json')->success(compact('order', 'todayPrice', 'yesterdayPrice')); + } + + /** + * @param StoreOrderRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function orderNum(StoreOrderRepository $repository) + { + $orderNum = $repository->dayOrderNum('today'); + + $yesterdayNum = $repository->dayOrderNum('yesterday'); + $today = $repository->dayOrderNumGroup('today')->toArray(); + $today = array_combine(array_column($today, 'time'), array_column($today, 'total')); + $monthOrderNum = $repository->dayOrderNum(date('Y/m/d', strtotime('first day of')) . ' 00:00:00' . '-' . date('Y/m/d H:i:s')); + + $date = date('Y/m/01 00:00:00', strtotime('last Month')) . '-' . date('Y/m/d 00:00:00', strtotime('-1 day', strtotime('first day of'))); + $beforeOrderNum = $repository->dayOrderNum($date); + + $monthRate = $this->getRate($beforeOrderNum, $monthOrderNum); + $orderRate = $this->getRate($yesterdayNum, $orderNum); + $time = getTimes(); + $data = []; + foreach ($time as $item) { + $data[] = [ + 'total' => $today[$item] ?? 0, + 'time' => $item + ]; + } + $today = $data; + return app('json')->success(compact('orderNum', 'today', 'monthOrderNum', 'monthRate', 'orderRate')); + } + + /** + * @param StoreOrderRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function orderUser(StoreOrderRepository $repository) + { + $orderNum = $repository->dayOrderUserNum('today'); + $yesterdayNum = $repository->dayOrderUserNum('yesterday'); + $today = $repository->dayOrderUserGroup('today')->toArray(); + $today = array_combine(array_column($today, 'time'), array_column($today, 'total')); + $monthOrderNum = $repository->dayOrderUserNum(date('Y/m/d', strtotime('first day of')) . ' 00:00:00' . '-' . date('Y/m/d H:i:s')); + + $date = gmdate('Y/m/01 00:00:00', strtotime('last Month')) . '-' . date('Y/m/d 00:00:00', strtotime('-1 day', strtotime('first day of'))); + $beforeOrderNum = $repository->dayOrderUserNum($date); + + $monthRate = $this->getRate($beforeOrderNum, $monthOrderNum); + $orderRate = $this->getRate($yesterdayNum, $orderNum); + $time = getTimes(); + $data = []; + foreach ($time as $item) { + $data[] = [ + 'total' => $today[$item] ?? 0, + 'time' => $item + ]; + } + $today = $data; + return app('json')->success(compact('orderNum', 'today', 'monthOrderNum', 'monthRate', 'orderRate')); + } + + /** + * @param StoreOrderProductRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function merchantStock(StoreOrderProductRepository $repository) + { + $date = $this->request->param('date') ?: 'lately7'; + $res = Cache::store('file')->remember(self::class . '@merchantStock' . $date, function () use ($date, $repository) { + $total = $repository->dateProductNum($date); + $list = $repository->orderProductGroup($date)->toArray(); + foreach ($list as &$item) { + $item['rate'] = bcdiv($item['total'], $total, 2); + } + + return compact('list', 'total'); + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + /** + * @param UserVisitRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function merchantVisit(UserVisitRepository $repository) + { + $date = $this->request->param('date') ?: 'lately7'; + $res = Cache::store('file')->remember(self::class . '@merchantVisit' . $date, function () use ($date, $repository) { + $total = $repository->dateVisitMerchantTotal($date); + $list = $repository->dateVisitMerchantNum($date)->toArray(); + foreach ($list as &$item) { + $item['rate'] = bcdiv($item['total'], $total, 2); + } + return compact('list', 'total'); + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + /** + * @param StoreOrderRepository $repository + * @param MerchantCategoryRepository $merchantCategoryRepository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function merchantRate(StoreOrderRepository $repository, MerchantCategoryRepository $merchantCategoryRepository) + { + $date = $this->request->param('date') ?: 'lately7'; + $res = Cache::store('file')->remember(self::class . '@merchantRate' . $date, function () use ($repository, $merchantCategoryRepository, $date) { + $total = $repository->dateOrderPrice($date); + $list = $merchantCategoryRepository->dateMerchantPriceGroup($date)->toArray(); + $rate = 1; + $pay_price = $total; + foreach ($list as &$item) { + $item['rate'] = bcdiv($item['pay_price'], $total, 2); + $rate = bcsub($rate, $item['rate'], 2); + $pay_price = bcsub($pay_price, $item['pay_price'], 2); + } + if ($rate > 0 && count($list)) { + $list[] = [ + 'pay_price' => $pay_price, + 'category_name' => '其他类', + 'rate' => $rate + ]; + } + return compact('list', 'total'); + }, 2000 + random_int(600, 1200)); + + return app('json')->success($res); + } + + public function userData(UserRepository $repository, UserVisitRepository $visitRepository) + { + $date = $this->request->param('date') ?: 'lately7'; + $res = Cache::store('file')->remember(self::class . '@userData' . $date, function () use ($visitRepository, $repository, $date) { + $newUserList = $repository->userNumGroup($date)->toArray(); + $newUserList = array_combine(array_column($newUserList, 'time'), array_column($newUserList, 'new')); + $visitList = $visitRepository->dateVisitNumGroup($date)->toArray(); + $visitList = array_combine(array_column($visitList, 'time'), array_column($visitList, 'total')); + $base = $repository->beforeUserNum(getStartModelTime($date)); + $time = getDatesBetweenTwoDays(getStartModelTime($date), date('Y-m-d')); + $userList = []; + $before = $base; + foreach ($time as $item) { + $new = $newUserList[$item] ?? 0; + $before += $new; + $userList[] = [ + 'total' => $before, + 'new' => $new, + 'visit' => $visitList[$item] ?? 0, + 'day' => $item + ]; + } + return $userList; + }, 2000 + random_int(600, 1200)); + + return app('json')->success($res); + } + + /** + * @param $last + * @param $today + * @param int $scale + * @return int|string|null + * @author xaboy + * @day 2020/6/25 + */ + protected function getRate($last, $today, $scale = 2) + { + if ($last == $today) + return 0; + else if ($last == 0) + return $today; + else if ($today == 0) + return -$last; + else + return (float)bcdiv(bcsub($today, $last, $scale), $last, $scale); + } + + /** + * 申请授权 + * @return mixed + */ + public function auth_apply() + { + $data = $this->request->params([ + ['company_name', ''], + ['domain_name', ''], + ['order_id', ''], + ['phone', ''], + ['label', 10], + ['captcha', ''], + ]); + if (!$data['company_name']) { + return app('json')->fail('请填写公司名称'); + } + if (!$data['domain_name']) { + return app('json')->fail('请填写授权域名'); + } + if (!$data['phone']) { + return app('json')->fail('请填写手机号码'); + } + if (!$data['order_id']) { + return app('json')->fail('请填写订单id'); + } + if (!$data['captcha']) { + return app('json')->fail('请填写验证码'); + } + $res = HttpService::postRequest('http://authorize.crmeb.net/api/auth_apply', $data); + if ($res === false) { + return app('json')->fail('申请失败,服务器没有响应!'); + } + $res = json_decode($res, true); + if (isset($res['status'])) { + if ($res['status'] == 400) { + return app('json')->fail($res['msg'] ?? "申请失败"); + } else { + return app('json')->success($res['msg'] ?? '申请成功', $res); + } + } + return app('json')->fail("申请授权失败!"); + } + + public function uploadConfig(ConfigRepository $repository) + { + return app('json')->success(formToData($repository->uploadForm())); + } + + public function saveUploadConfig(ConfigRepository $repository) + { + $formData = $this->request->post(); + if (!count($formData)) return app('json')->fail('保存失败'); + $repository->saveUpload($formData); + + return app('json')->success('保存成功'); + } + + public function loginConfig() + { + $login_logo = systemConfig('sys_login_logo'); + $menu_logo = systemConfig('sys_menu_logo'); + $menu_slogo = systemConfig('sys_menu_slogo'); + $login_title = systemConfig('sys_login_title'); + $sys_login_banner = systemConfig('sys_login_banner'); + $beian_sn = systemConfig('beian_sn'); + $login_banner = []; + foreach ($sys_login_banner as $item) { + $login_banner[] = [ + 'pic' => $item, + 'name' => $item + ]; + } + + return app('json')->success(compact('login_banner', 'login_logo', 'login_title', 'menu_slogo', 'menu_logo', 'beian_sn')); + } + + public function version() + { + $sys_open_version = systemConfig('sys_open_version'); + $data = [ + 'version' => get_crmeb_version('未知'), + 'year' => '© 2014-' . date('Y', time()), + 'beian_sn' => systemConfig('beian_sn'), + 'url' => 'www.crmeb.com', + 'Copyright' => 'Copyright', + 'sys_open_version' => $sys_open_version === '' ? '1' : $sys_open_version, + ]; + + $copyright = app()->make(CacheRepository::class)->getResultByKey('copyright_status'); + if (!$copyright) { + $data['status'] = -1; + } else { + $copyright = app()->make(CacheRepository::class)->search(['copyright_status', 'copyright_context', 'copyright_image']); + $data['status'] = 1; + $data['Copyright'] = $copyright['copyright_context'] ?? ''; + $data['image'] = $copyright['copyright_image'] ?? ''; + } + return app('json')->success($data); + } + + public function config() + { + $config = systemConfig(['delivery_type', 'delivery_status', 'sms_use_type', 'hot_ranking_lv', 'hot_ranking_switch']); + return app('json')->success($config); + } + + public function getChangeColor() + { + return app('json')->success(systemConfig(['global_theme'])); + } + + public function setChangeColor() + { + $data = $this->request->params(['global_theme']); + $make = app()->make(ConfigValueRepository::class); + $make->setFormData($data, 0); + return app('json')->success('修改成功'); + } + + + public function svaeCopyright() + { + $data = $this->request->params(['copyright_context', 'copyright_image']); + $copyright = app()->make(CacheRepository::class)->getResultByKey('copyright_status'); + if (!$copyright) + return app('json')->fail('请先获取版权授权'); + + app()->make(CacheRepository::class)->saveAll($data); + return app('json')->success('修改成功'); + } + + public function payAuth() + { + $host = 'https://shop.crmeb.net/html/index.html'; + $version = get_crmeb_version_code(); + $url = rtrim($this->request->host(), '/'); + $data['url'] = $host . '?url=' . $url . '&product=mer&label=10&venrsion=' . $version; + return app('json')->success($data); + } + +} + diff --git a/app/controller/admin/article/Article.php b/app/controller/admin/article/Article.php new file mode 100644 index 00000000..651fb825 --- /dev/null +++ b/app/controller/admin/article/Article.php @@ -0,0 +1,148 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\article; + +use crmeb\basic\BaseController; +use app\common\repositories\article\ArticleCategoryRepository; +use app\common\repositories\article\ArticleContentRepository; +use app\common\repositories\article\ArticleRepository; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use app\validate\admin\ArticleValidate; + +class Article extends BaseController +{ + /** + * @var ArticleRepository + */ + protected $repository; + + /** + * Article constructor. + * @param App $app + * @param ArticleRepository $repository + */ + public function __construct(App $app,ArticleRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * @return mixed + * @author Qinii + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + + $where = $this->request->params(['cid','title']); + + return app('json')->success($this->repository->search($this->request->merId(),$where, $page, $limit)); + } + + /** + * 添加 + * @param ArticleValidate $validate + * @param ArticleCategoryRepository $repository + * @return mixed + * @author Qinii + */ + public function create(ArticleValidate $validate,ArticleCategoryRepository $repository) + { + $data = $this->checkParams($validate); + $data['admin_id'] = $this->request->adminId(); + $data['mer_id'] = $this->request->merId() ; + if (!$repository->merExists(0,$data['cid'])) + return app('json')->fail('分类不存在'); + $this->repository->create($data); + return app('json')->success('添加成功'); + + } + + public function detail($id) + { + if (!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + + return app('json')->success($this->repository->get($id,$this->request->merId())); + } + + /** + * 更新 + * @param $id + * @param ArticleValidate $validate + * @param ArticleCategoryRepository $articleCategoryRepository + * @return mixed + * @author Qinii + */ + public function update($id,ArticleValidate $validate,ArticleCategoryRepository $articleCategoryRepository) + { + $data = $this->checkParams($validate); + if (!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + if (!$articleCategoryRepository->merExists($this->request->merId(),$data['cid'])) + return app('json')->fail('分类不存在'); + + $this->repository->update($id,$data); + + return app('json')->success('编辑成功'); + + + } + + /** + * 删除 + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + + $this->repository->delete($id,$this->request->merId()); + + return app('json')->success('删除成功'); + } + + + /** + * @param ArticleValidate $validate + * @return array + * @author Qinii + */ + public function checkParams(ArticleValidate $validate) + { + $data = $this->request->params([['cid', 0], 'title', 'content', 'author', 'image_input','status','sort','synopsis','is_hot','is_banner','url']); + $validate->check($data); + return $data; + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if(!$this->repository->get($id)) return app('json')->fail('数据不存在'); + $this->repository->switchStatus($id, ['status' => $status]); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/admin/article/ArticleCategory.php b/app/controller/admin/article/ArticleCategory.php new file mode 100644 index 00000000..c1b0e149 --- /dev/null +++ b/app/controller/admin/article/ArticleCategory.php @@ -0,0 +1,194 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\article; + + +use crmeb\basic\BaseController; +use app\common\repositories\article\ArticleCategoryRepository; +use app\validate\admin\ArticleCategoryValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class ArticleCategory + * @package app\controller\admin\article + * @author xaboy + * @day 2020-04-20 + */ +class ArticleCategory extends BaseController +{ + /** + * @var ArticleCategoryRepository + */ + protected $repository; + + /** + * ArticleCategory constructor. + * @param App $app + * @param ArticleCategoryRepository $repository + */ + public function __construct(App $app, ArticleCategoryRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-20 + */ + public function lst() + { + $result = $this->repository->getFormatList(); + return app('json')->success($result); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-15 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form(0))); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function updateForm($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm(0, $id))); + } + + /** + * @param ArticleCategoryValidate $validate + * @return mixed + * @author xaboy + * @day 2020-04-20 + */ + public function create(ArticleCategoryValidate $validate) + { + $data = $this->checkParams($validate); + if ($data['pid'] && !$this->repository->merExists(0, $data['pid'])) + return app('json')->fail('上级分类不存在'); + $data['mer_id'] = 0; + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @param $id + * @param ArticleCategoryValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function update($id, ArticleCategoryValidate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + if ($data['pid'] && !$this->repository->merExists(0, $data['pid'])) + return app('json')->fail('上级分类不存在'); + + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('分类不存在'); + $this->repository->update($id, compact('status')); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function delete($id) + { + if ($this->repository->merFieldExists(0, 'pid', $id)) + return app('json')->fail('存在子级,无法删除'); + $this->repository->delete($id, 0); + return app('json')->success('删除成功'); + } + + + /** + * 详情 + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('分类不存在'); + return app('json')->success($this->repository->get($id,0)); + } + + /** + * @param ArticleCategoryValidate $validate + * @return array + * @author xaboy + * @day 2020-04-20 + */ + public function checkParams(ArticleCategoryValidate $validate) + { + $data = $this->request->params([['pid', 0], 'title', 'info', 'status', 'image', 'sort']); + $validate->check($data); + return $data; + } + + public function select() + { + $result = $this->repository->getFormatList(0,1); + return app('json')->success($result); + } +} diff --git a/app/controller/admin/community/Community.php b/app/controller/admin/community/Community.php new file mode 100644 index 00000000..7d0419ac --- /dev/null +++ b/app/controller/admin/community/Community.php @@ -0,0 +1,131 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\community; + +use crmeb\basic\BaseController; +use think\App; +use app\common\repositories\community\CommunityRepository as repository; + +class Community extends BaseController +{ + /** + * @var CommunityRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function title() + { + $where['is_del'] = 0; + return app('json')->success($this->repository->title($where)); + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + $where = $this->request->params(['keyword','status','username','category_id','topic_id','is_show','is_type']); + $where['order'] = 'start'; + $where['is_del'] = 0; + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->detail($id)); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id))); + } + + public function showForm($id) + { + return app('json')->success(formToData($this->repository->showForm($id))); + } + + public function update($id) + { + $data['start'] = $this->request->param('start',1); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id,$data); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->destory($id); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $data = $this->request->params(['status', 'refusal']); + + if (!in_array($data['status'],[0,1,-1,-2])) + return app('json')->fail('状态类型错误'); + + $data['is_show'] = ($data['status'] == 1) ? : 0; + + if($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + if($data['status'] == -2 && empty($data['refusal'])) + return app('json')->fail('请填写下架原因'); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->setStatus($id,$data); + return app('json')->success('操作成功'); + } + + public function switchShow($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id,['is_show' => $status]); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/admin/community/CommunityCategory.php b/app/controller/admin/community/CommunityCategory.php new file mode 100644 index 00000000..0f6c513f --- /dev/null +++ b/app/controller/admin/community/CommunityCategory.php @@ -0,0 +1,137 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\community; + +use crmeb\basic\BaseController; +use crmeb\traits\CategoresRepository; +use think\App; +use app\validate\admin\StoreCategoryValidate; +use app\common\repositories\community\CommunityCategoryRepository as repository; + +class CommunityCategory extends BaseController +{ + /** + * @var CommunityCategoryRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + $where = $this->request->params(['cate_name']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 10/26/21 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null))); + } + + public function create() + { + $data = $this->checkParams(); + $data['cate_name'] = trim($data['cate_name']); + if ($this->repository->fieldExists('cate_name', $data['cate_name'],null)) + return app('json')->fail('分类名重复'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/26/21 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->clearCahe(); + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $data = $this->checkParams(); + + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($this->repository->fieldExists('cate_name', $data['cate_name'],$id)) + return app('json')->fail('分类名重复'); + $this->repository->update($id,$data); + $this->repository->clearCahe(); + return app('json')->success('编辑成功'); + } + + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + $this->repository->clearCahe(); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id,['is_show' => $status]); + $this->repository->clearCahe(); + return app('json')->success('修改成功'); + } + + public function checkParams() + { + $data = $this->request->params(['pid','cate_name','is_show','sort']); + $data['pid'] = 0; + app()->make(StoreCategoryValidate::class)->check($data); + return $data; + } + + public function getOptions() + { + return app('json')->success($this->repository->options()); + } +} diff --git a/app/controller/admin/community/CommunityReply.php b/app/controller/admin/community/CommunityReply.php new file mode 100644 index 00000000..3219b1d3 --- /dev/null +++ b/app/controller/admin/community/CommunityReply.php @@ -0,0 +1,86 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\community; + +use crmeb\basic\BaseController; +use think\App; +use app\common\repositories\community\CommunityReplyRepository as repository; + +class CommunityReply extends BaseController +{ + /** + * @var CommunityReplyRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + $where = $this->request->params(['keyword', 'date', 'username', 'community_id', 'pid']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_del' => 1]); + return app('json')->success('删除成功'); + } + + public function statusForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->statusForm($id))); + } + + + public function switchStatus($id) + { + $data = $this->request->params(['status', 'refusal']); + + if (!in_array($data['status'], [1, -1])) + return app('json')->fail('审核类型错误'); + + if ($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id, $data); + return app('json')->success('审核成功'); + } +} diff --git a/app/controller/admin/community/CommunityTopic.php b/app/controller/admin/community/CommunityTopic.php new file mode 100644 index 00000000..0a0c573f --- /dev/null +++ b/app/controller/admin/community/CommunityTopic.php @@ -0,0 +1,141 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\community; + +use app\common\repositories\community\CommunityCategoryRepository; +use app\validate\admin\CommunityTopicValidate; +use crmeb\basic\BaseController; +use think\App; +use app\common\repositories\community\CommunityTopicRepository as repository; + +class CommunityTopic extends BaseController +{ + /** + * @var CommunityTopicRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + $where = $this->request->params(['topic_name', 'category_id', 'status','is_hot','is_del']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 10/26/21 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null))); + } + + public function create() + { + $data = $this->checkParams(); + $data['topic_name'] = trim($data['topic_name']); + if ($this->repository->fieldExists('topic_name', $data['topic_name'],null)) + return app('json')->fail('话题重复'); + $this->repository->create($data); + app()->make(CommunityCategoryRepository::class)->clearCahe(); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $data = $this->checkParams(); + + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($this->repository->fieldExists('topic_name', $data['topic_name'],$id)) + return app('json')->fail('话题重复'); + $this->repository->update($id,$data); + app()->make(CommunityCategoryRepository::class)->clearCahe(); + return app('json')->success('编辑成功'); + } + + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['is_del' => 1]); + app()->make(CommunityCategoryRepository::class)->clearCahe(); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id,['status' => $status]); + app()->make(CommunityCategoryRepository::class)->clearCahe(); + return app('json')->success('修改成功'); + } + + public function checkParams() + { + $data = $this->request->params(['category_id','topic_name','is_hot','status','sort','pic']); + app()->make(CommunityTopicValidate::class)->check($data); + return $data; + } + + public function getOptions() + { + return app('json')->success($this->repository->options()); + } + + public function switchHot($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id,['is_hot' => $status]); + app()->make(CommunityCategoryRepository::class)->clearCahe(); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/admin/delivery/DeliveryOrder.php b/app/controller/admin/delivery/DeliveryOrder.php new file mode 100644 index 00000000..04e42b83 --- /dev/null +++ b/app/controller/admin/delivery/DeliveryOrder.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\delivery; + +use app\common\repositories\delivery\DeliveryOrderRepository; +use crmeb\basic\BaseController; +use think\App; + +class DeliveryOrder extends BaseController +{ + protected $repository; + + public function __construct(App $app, DeliveryOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','station_name','status','mer_id','date','order_sn','station_type']); + $data = $this->repository->sysList($where, $page, $limit); + return app('json')->success($data); + } + + public function detail($id) + { + $data = $this->repository->detail($id, null); + return app('json')->success($data); + } + + public function title() + { + $data = $this->repository->getTitle(); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/delivery/DeliveryStation.php b/app/controller/admin/delivery/DeliveryStation.php new file mode 100644 index 00000000..2cec72b3 --- /dev/null +++ b/app/controller/admin/delivery/DeliveryStation.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\delivery; + +use app\common\repositories\delivery\DeliveryStationRepository; +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use crmeb\basic\BaseController; +use think\App; + +class DeliveryStation extends BaseController +{ + protected $repository; + + public function __construct(App $app, DeliveryStationRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function deliveryForm() + { + return app('json')->success(formToData($this->repository->deliveryForm())); + } + + public function saveDeliveryConfig() + { + $status = $this->request->param('delivery_status') == 1 ? 1 : 0; + $type = $this->request->param('delivery_type') == 1 ? 1 : 2; + if ($type == 1) { + $data = $this->request->params([ + 'delivery_type', + 'dada_app_key', + 'dada_app_sercret', + 'dada_source_id' + ]); + } else { + $data = $this->request->params([ + 'delivery_type', + 'uupt_appkey', + 'uupt_app_id', + 'uupt_open_id', + ]); + } + $data['delivery_status'] = $status; + $cid = app()->make(ConfigClassifyRepository::class)->keyById('delivery_config'); + if (!$cid) return app('json')->fail('保存失败'); + app()->make(ConfigValueRepository::class)->save($cid, $data, 0); + return app('json')->success('保存成功'); + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','station_name','status','mer_id']); + $data = $this->repository->sysList($where, $page, $limit); + return app('json')->success($data); + } + + public function detail($id) + { + $data = $this->repository->detail($id, null); + return app('json')->success($data); + } + + public function getBalance() + { + return app('json')->success($this->repository->getBalance()); + } + + public function getRecharge() + { + return app('json')->success($this->repository->getRecharge()); + } + + /** + * TODO 充值记录 + * @author Qinii + * @day 2/18/22 + */ + public function payLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['mer_id','date']); + $where['type'] = 20; + $data = app()->make(ServeOrderRepository::class)->getList($where, $page, $limit); + return app('json')->success($data); + } + + public function options() + { + return app('json')->success($this->repository->getOptions(null)); + } +} diff --git a/app/controller/admin/order/Order.php b/app/controller/admin/order/Order.php new file mode 100644 index 00000000..e5050711 --- /dev/null +++ b/app/controller/admin/order/Order.php @@ -0,0 +1,204 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\order; + +use crmeb\basic\BaseController; +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\store\order\StoreOrderRepository as repository; +use crmeb\services\ExcelService; +use think\App; + +class Order extends BaseController +{ + protected $repository; + + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','order_sn','order_type','keywords','username','activity_type','group_order_sn','store_name']); + $where['reconciliation_type'] = $this->request->param('status', 1); + $where['mer_id'] = $id; + return app('json')->success($this->repository->adminMerGetList($where, $page, $limit)); + } + + public function markForm($id) + { + if (!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->adminMarkForm($id))); + } + + public function mark($id) + { + if (!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['admin_mark']); + $this->repository->update($id, $data); + return app('json')->success('备注成功'); + } + + public function title() + { + $where = $this->request->params(['type', 'date', 'mer_id','keywords','status','username','order_sn','is_trader','activity_type']); + return app('json')->success($this->repository->getStat($where, $where['status'])); + } + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-25 + */ + public function getAllList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type', 'date', 'mer_id','keywords','status','username','order_sn','is_trader','activity_type','group_order_sn','store_name']); + $data = $this->repository->adminGetList($where, $page, $limit); + return app('json')->success($data); + } + + public function takeTitle() + { + $where = $this->request->params(['date','order_sn','keywords','username','is_trader']); + $where['take_order'] = 1; + $where['status'] = ''; + $where['verify_date'] = $where['date']; + unset($where['date']); + return app('json')->success($this->repository->getStat($where, '')); + } + + /** + * TODO 自提订单列表 + * @return mixed + * @author Qinii + * @day 2020-08-17 + */ + public function getTakeList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','order_sn','keywords','username','is_trader']); + $where['take_order'] = 1; + $where['status'] = ''; + $where['verify_date'] = $where['date']; + unset($where['date']); + return app('json')->success($this->repository->adminGetList($where, $page, $limit)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-08-17 + */ + public function chart() + { + return app('json')->success($this->repository->OrderTitleNumber(null,null)); + } + + /** + * TODO 自提订单头部统计 + * @return mixed + * @author Qinii + * @day 2020-08-17 + */ + public function takeChart() + { + return app('json')->success($this->repository->OrderTitleNumber(null,1)); + } + + /** + * TODO 订单类型 + * @return mixed + * @author Qinii + * @day 2020-08-15 + */ + public function orderType() + { + return app('json')->success($this->repository->orderType([])); + } + + public function detail($id) + { + $data = $this->repository->getOne($id, null); + if (!$data) + return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function status($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','user_type']); + $where['id'] = $id; + return app('json')->success($this->repository->getOrderStatus($where, $page, $limit)); + } + + /** + * TODO 快递查询 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-25 + */ + public function express($id) + { + if (!$this->repository->getWhereCount(['order_id' => $id, 'delivery_type' => 1])) + return app('json')->fail('订单信息或状态错误'); + return app('json')->success($this->repository->express($id,null)); + } + + public function reList($id) + { + [$page, $limit] = $this->getPage(); + $where = ['reconciliation_id' => $id, 'type' => 0]; + return app('json')->success($this->repository->reconList($where, $page, $limit)); + } + + /** + * TODO 导出文件 + * @author Qinii + * @day 2020-07-30 + */ + public function excel() + { + $where = $this->request->params(['type', 'date', 'mer_id','keywords','status','username','order_sn','take_order']); + if($where['take_order']){ + $where['verify_date'] = $where['date']; + unset($where['date']); + } + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->order($where, $page, $limit); + return app('json')->success($data); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 2023/2/22 + */ + public function childrenList($id) + { + $data = $this->repository->childrenList($id, 0); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/order/OrderProfitsharing.php b/app/controller/admin/order/OrderProfitsharing.php new file mode 100644 index 00000000..fcdf5608 --- /dev/null +++ b/app/controller/admin/order/OrderProfitsharing.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\order; + + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\order\StoreOrderProfitsharingRepository; +use crmeb\basic\BaseController; +use crmeb\services\ExcelService; +use think\App; + +class OrderProfitsharing extends BaseController +{ + protected $repository; + + public function __construct(App $app, StoreOrderProfitsharingRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getList() + { + $where = $this->request->params(['type', 'status', 'mer_id', 'keyword', 'profit_date', 'date']); + $merId = $this->request->merId(); + if ($merId) { + $where['mer_id'] = $merId; + } + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit, (bool)$merId)); + } + + public function again($id) + { + if (!$model = $this->repository->get((int)$id)) { + return app('json')->fail('分账单不存在'); + } + if ($model->status != -2) { + return app('json')->fail('分账单状态操作,不能分账'); + } + if ($this->repository->profitsharing($model)) { + return app('json')->success('分账成功'); + } + return app('json')->fail('分账失败'); + } + + public function export() + { + $where = $this->request->params(['type', 'status', 'mer_id', 'keyword', 'profit_date', 'date']); + $merId = $this->request->merId(); + if ($merId) { + $where['mer_id'] = $merId; + } + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->profitsharing($where,$page,$limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/order/Reconciliation.php b/app/controller/admin/order/Reconciliation.php new file mode 100644 index 00000000..b61bb1aa --- /dev/null +++ b/app/controller/admin/order/Reconciliation.php @@ -0,0 +1,92 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\order; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\store\order\MerchantReconciliationRepository as repository; + +class Reconciliation extends BaseController +{ + protected $repository; + + public function __construct(App $app,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['date','status','keyword','reconciliation_id']); + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + + + public function create($id) + { + if(!app()->make(MerchantRepository::class)->merExists($id)) + return app('json')->fail('商户不存在'); + $data = $this->request->params([ + 'date', //时间 + 'order_type', //订单 全选1 + 'refund_type', //退款 全选1 + ['order_ids',[]], //订单 + ['order_out_ids',[]], //排除,不参与对账的订单ID + ['refund_out_ids',[]], //排除,不参与对账的退款订单ID + ['refund_order_ids',[]] //退款段id + ]); + $data['adminId'] = $this->request->adminId(); + $this->repository->create($id,$data); + return app('json')->success('对账单生成成功'); + } + + /** + * TODO 确认打款 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-15 + */ + public function switchStatus($id) + { + if(!$this->repository->getWhereCountById($id)) + return app('json')->fail('数据不存在或状态错误'); + $status = $this->request->param('status') == 1 ? 1 : 0; + $data['is_accounts'] = $status; + if($status == 1) $data['accounts_time'] = date('Y-m-d H:i:s',time()); + $this->repository->switchStatus($id,$data); + return app('json')->success('修改成功'); + } + + + + public function markForm($id) + { + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->adminMarkForm($id))); + } + + public function mark($id) + { + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['admin_mark']); + $this->repository->update($id,$data); + return app('json')->success('备注成功'); + } +} diff --git a/app/controller/admin/order/RefundOrder.php b/app/controller/admin/order/RefundOrder.php new file mode 100644 index 00000000..46a91875 --- /dev/null +++ b/app/controller/admin/order/RefundOrder.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\order; + +use app\common\repositories\store\ExcelRepository; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\MerchantReconciliationorderRepository; +use app\common\repositories\store\order\MerchantReconciliationRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository as repository; +use crmeb\services\ExcelService; +use think\App; + +class RefundOrder extends BaseController +{ + protected $repository; + + public function __construct(App $app,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst($id) + { + [$page,$limit] = $this->getPage(); + $where['reconciliation_type'] = $this->request->param('status',1); + $where['date'] = $this->request->param('date'); + $where['mer_id'] = $id; + $where['status'] = 3; + return app('json')->success($this->repository->getAdminList($where,$page,$limit)); + } + + public function markForm($id) + { + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->adminMarkForm($id))); + } + + public function mark($id) + { + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['admin_mark']); + $this->repository->update($id,$data); + + return app('json')->success('备注成功'); + } + + + public function getAllList() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['refund_order_sn','status','refund_type','date','mer_id','order_sn','is_trader']); + return app('json')->success($this->repository->getAllList($where, $page, $limit)); + } + + public function reList($id) + { + [$page,$limit] = $this->getPage(); + $where = ['reconciliation_id' => $id,'type' => 1]; + return app('json')->success($this->repository->reconList($where,$page,$limit)); + + } + + public function excel() + { + $where = $this->request->params(['refund_order_sn','status','refund_type','date','order_sn','id','mer_id']); + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->refundOrder($where, $page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/parameter/ParameterTemplate.php b/app/controller/admin/parameter/ParameterTemplate.php new file mode 100644 index 00000000..1f0f5a5f --- /dev/null +++ b/app/controller/admin/parameter/ParameterTemplate.php @@ -0,0 +1,147 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\parameter; + +use app\common\repositories\store\parameter\ParameterTemplateRepository; +use app\validate\admin\ParameterTemplateValidate; +use think\App; +use crmeb\basic\BaseController; +use think\exception\ValidateException; + +class ParameterTemplate extends BaseController +{ + protected $repository; + + /** + * City constructor. + * @param App $app + * @param ParameterTemplateRepository $repository + */ + public function __construct(App $app, ParameterTemplateRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:40 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['template_name','cate_id','mer_name','mer_id']); + $where['is_mer'] = $this->request->param('is_mer',1); + if ($merId = $this->request->merId()) { + $where['mer_id'] = $merId; + unset($where['is_mer']); + } + $data = $this->repository->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function detail($id) + { + $data = $this->repository->detail($id,$this->request->merId()); + return app('json')->success($data); + } + + public function create() + { + $data = $this->checkParams(1); + $this->repository->create($this->request->merId(), $data); + return app('json')->success('添加成功'); + } + + public function update($id) + { + $data = $this->checkParams(); + $where['template_id'] = $id; + if ($merId = $this->request->merId()) { + $where['mer_id'] = $merId; + } + if (!$res = $this->repository->getWhere($where)){ + return app('json')->fail('数据不存在'); + } + $this->repository->update($id, $data, $merId); + return app('json')->success('编辑成功'); + } + + public function delete($id) + { + $where['template_id'] = $id; + if ($merId = $this->request->merId()) { + $where['mer_id'] = $merId; + } + if (!$this->repository->getWhere($where)){ + return app('json')->fail('数据不存在'); + } + $this->repository->delete($id); + return app('json')->success('操作成功'); + } + + /** + * TODO 根据cate_id获取参数模板列表 + * @return \think\response\Json + * @author Qinii + * @day 2022/11/22 + */ + public function select() + { + $where = $this->request->params(['cate_id',0]); + $where['mer_id'] = 0; + $data['sys'] = $this->repository->getSelect($where); + + $where = ['mer_id' => $this->request->merId()]; + $data['mer'] = $this->repository->getSelect($where); + + return app('json')->success($data); + } + + /** + * TODO 根据模板id 获取参数 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 2022/11/22 + */ + public function show() + { + $template_ids = $this->request->param('template_ids'); + if (!$template_ids) return app('json')->success([]); + $where['template_ids'] = $template_ids; + $data = $this->repository->show($where); + return app('json')->success($data); + } + + public function checkParams($isCreate = 0) + { + $mer_id = $this->request->merId(); + $data = $this->request->params(['template_name',['cate_ids',[]],'sort','params']); + app()->make(ParameterTemplateValidate::class)->check($data); + if ($mer_id == 0 && empty($data['cate_ids'])) { + throw new ValidateException('请选择商品分类'); + } + if ($isCreate) { + foreach ($data['params'] as $item) { + if (isset($item['parameter_id'])) unset($item['parameter_id']); + if (isset($item['template_id'])) unset($item['template_id']); + $params[] = $item; + } + $data['params'] = $params; + } + return $data; + } +} diff --git a/app/controller/admin/store/BroadcastGoods.php b/app/controller/admin/store/BroadcastGoods.php new file mode 100644 index 00000000..0de85eba --- /dev/null +++ b/app/controller/admin/store/BroadcastGoods.php @@ -0,0 +1,91 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\store; + + +use app\common\repositories\store\broadcast\BroadcastGoodsRepository; +use crmeb\basic\BaseController; +use think\App; + +class BroadcastGoods extends BaseController +{ + protected $repository; + + public function __construct(App $app, BroadcastGoodsRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'status_tag', 'is_trader', 'mer_valid','broadcast_goods_id']); + return app('json')->success($this->repository->adminList($where, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)->append(['product'])->toArray()); + } + + public function applyForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + return app('json')->success(formToData($this->repository->applyForm($id))); + } + + public function apply($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + [$status, $msg] = $this->request->params(['status', 'msg'], true); + $status = $status == 1 ? 1 : -1; + if ($status == -1 && !$msg) + return app('json')->fail('请输入理由'); + $this->repository->apply($id, $status, $msg); + return app('json')->success('操作成功'); + } + + public function changeStatus($id) + { + $isShow = $this->request->param('is_show') == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->isShow($id, $isShow, true); + return app('json')->success('修改成功'); + } + + public function sort($id) + { + $sort = (int)$this->request->param('sort'); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->change($id, compact('sort')); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + +} diff --git a/app/controller/admin/store/BroadcastRoom.php b/app/controller/admin/store/BroadcastRoom.php new file mode 100644 index 00000000..25f3fe49 --- /dev/null +++ b/app/controller/admin/store/BroadcastRoom.php @@ -0,0 +1,140 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\store; + + +use app\common\repositories\store\broadcast\BroadcastRoomGoodsRepository; +use app\common\repositories\store\broadcast\BroadcastRoomRepository; +use crmeb\basic\BaseController; +use think\App; +use think\response\Json; + +class BroadcastRoom extends BaseController +{ + protected $repository; + + public function __construct(App $app, BroadcastRoomRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'status_tag', 'is_trader', 'show_type','mer_id','live_status', 'star','broadcast_room_id']); + return app('json')->success($this->repository->adminList($where, $page, $limit)); + } + + /** + * @param BroadcastRoomGoodsRepository $repository + * @param $id + * @return Json + * @author xaboy + * @day 2020/8/31 + */ + public function goodsList(BroadcastRoomGoodsRepository $repository, $id) + { + [$page, $limit] = $this->getPage(); + if (!$this->repository->exists((int)$id)) + return app('json')->fail('直播间不存在'); + return app('json')->success($repository->getGoodsList($id, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)->toArray()); + } + + public function applyForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + return app('json')->success(formToData($this->repository->applyForm($id))); + } + + public function apply($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + [$status, $msg] = $this->request->params(['status', 'msg'], true); + $status = $status == 1 ? 1 : -1; + if ($status == -1 && !$msg) + return app('json')->fail('请输入理由'); + $this->repository->apply($id, $status, $msg); + return app('json')->success('操作成功'); + } + + public function changeStatus($id) + { + $isShow = $this->request->param('is_show') == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->isShow($id, $isShow, true); + return app('json')->success('修改成功'); + } + + public function changeLiveStatus($id) + { + $isShow = $this->request->param('replay_status') == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['replay_status' => $isShow]); + return app('json')->success('修改成功'); + } + + public function sort($id) + { + $sort = (int)$this->request->param('sort'); + $star = (int)$this->request->param('star'); + if ($star < 0 || $star > 5) + return app('json')->fail('请选择正确的星级'); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('sort', 'star')); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function closeKf($id) + { + $status = $this->request->param('status') == 1 ? 1 : -1; + $this->repository->closeInfo($id,'close_kf', $status, false); + return app('json')->success('修改成功'); + } + + public function banComment($id) + { + $status = $this->request->param('status') == 1 ? 1 : -1; + $this->repository->closeInfo($id,'close_comment', $status,false); + return app('json')->success('修改成功'); + } + + public function isFeedsPublic($id) + { + $status = $this->request->param('status') == 1 ? 1 : -1; + $this->repository->closeInfo($id,'is_feeds_public', $status, false); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/CityArea.php b/app/controller/admin/store/CityArea.php new file mode 100644 index 00000000..031fd2ef --- /dev/null +++ b/app/controller/admin/store/CityArea.php @@ -0,0 +1,103 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\CityAreaRepository; +use think\App; +use crmeb\basic\BaseController; +use think\exception\ValidateException; + +class CityArea extends BaseController +{ + protected $repository; + + /** + * City constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, CityAreaRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:40 + * @return mixed + */ + public function lst($id) + { + $where['parent_id'] = $id; + return app('json')->success($this->repository->getList($where)); + } + + + public function createForm($id) + { + return app('json')->success(formToData($this->repository->form(0, $id))); + } + + public function create() + { + $data = $this->checkParams(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id,null))); + } + + public function update($id) + { + $data = $this->checkParams(); + if (!$res = $this->repository->get($id)){ + return app('json')->fail('数据不存在'); + } + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + public function checkParams() + { + $type = [ + 1 => 'province', + 2 => 'city', + 3 => 'area', + 4 => 'street', + ]; + $data = $this->request->params(['parent_id','level','name',['path','/']]); + if ($data['parent_id']) { + $parent = $this->repository->get($data['parent_id']); + if (!$parent) throw new ValidateException('上级数据不存在'); + $data['path'] = $parent['path'] . $parent['id'].'/'; + } + $data['type'] = $type[$data['level']]; + if (!$data['name']) throw new ValidateException('请填写城市名称'); + return $data; + } + + public function delete($id) + { + $res = $this->repository->getWhere(['parent_id' => $id]); + if ($res) { + return app('json')->fail('数据存在子集不能删除'); + } + $this->repository->delete($id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/store/Coupon.php b/app/controller/admin/store/Coupon.php new file mode 100644 index 00000000..78e3dbde --- /dev/null +++ b/app/controller/admin/store/Coupon.php @@ -0,0 +1,272 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\store; + +use app\common\repositories\store\coupon\StoreCouponProductRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponSendRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\validate\merchant\StoreCouponSendValidate; +use app\validate\merchant\StoreCouponValidate; +use crmeb\basic\BaseController; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; + +/** + * Class CouponIssue + * @package app\controller\merchant\store\coupon + * @author xaboy + * @day 2020-05-13 + */ +class Coupon extends BaseController +{ + /** + * @var StoreCouponRepository + */ + protected $repository; + + /** + * CouponIssue constructor. + * @param App $app + * @param StoreCouponRepository $repository + */ + public function __construct(App $app, StoreCouponRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-14 + */ + public function lst() + { + $where = $this->request->params(['is_full_give', 'status', 'is_give_subscribe', 'coupon_name', ['mer_id', null],'is_trader']); + [$page, $limit] = $this->getPage(); + $where['is_mer'] = 1; + return app('json')->success($this->repository->getList($where['mer_id'], $where, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $coupon = $this->repository->get($id)->append(['used_num', 'send_num']); + return app('json')->success($coupon->toArray()); + } + + public function showLst($id) + { + [$page, $limit] = $this->getPage(); + $data = $this->repository->getProductList($id, $page, $limit); + return app('json')->success($data); + } + + public function product($id) + { + $merId = $this->request->merId(); + if ($merId) { + $exists = app()->make(StoreCouponRepository::class)->merExists($merId, $id); + } else { + $exists = app()->make(StoreCouponRepository::class)->exists($id); + } + if (!$exists) { + return app('json')->fail('优惠券不存在'); + } + [$page, $limit] = $this->getPage(); + return app('json')->success(app()->make(StoreCouponProductRepository::class)->productList((int)$id, $page, $limit)); + } + + /** + * @param StoreCouponUserRepository $repository + * @author xaboy + * @day 2020/6/2 + */ + public function issue(StoreCouponUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['username', 'coupon_id', 'coupon','coupon_type', 'status','type']); + return app('json')->success($repository->getList($where, $page, $limit)); + } + + /** + * TODO 平台领取记录 + * @param StoreCouponUserRepository $repository + * @return \think\response\Json + * @author Qinii + * @day 2/26/22 + */ + public function platformIssue(StoreCouponUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['username', 'coupon_id', 'coupon', 'status','coupon_type','type', 'send_id']); + $where['mer_id'] = 0; + return app('json')->success($repository->getList($where, $page, $limit)); + } + + + public function createForm() + { + $data = $this->repository->sysForm(); + return app('json')->success(formToData($data)); + } + + public function create() + { + $data = $this->checkParams(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm(0, $id))); + } + + public function update($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['title']); + $this->repository->update($id, $data); + + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('status')); + return app('json')->success('修改成功'); + } + + public function platformLst() + { + $where = $this->request->params(['is_full_give', 'status', 'is_give_subscribe', 'coupon_name', 'send_type', 'type']); + [$page, $limit] = $this->getPage(); + $data = $this->repository->sysLst($where, $page, $limit); + return app('json')->success($data); + } + + + public function cloneForm($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->cloneSysCouponForm($id))); + } + + + /** + * @param StoreCouponValidate $validate + * @return array + * @author xaboy + * @day 2020/5/20 + */ + public function checkParams() + { + $data = $this->request->params([ + 'use_type', + 'title', + 'coupon_price', + 'use_min_price', + ['coupon_type',0], + ['coupon_time',1], + ['use_start_time', []], + 'sort', + ['status', 0], + 'type', + ['product_id', []], + ['range_date', ''], + ['send_type', 0], + ['full_reduction', 0], + ['is_limited', 0], + ['is_timeout', 0], + ['total_count', ''], + ['status', 0], + ['cate_ids',[]], + 'mer_type', + 'is_trader', + 'category_id', + 'type_id', + ['mer_ids',[]], + ]); + + app()->make(StoreCouponValidate::class)->check($data); + if ($data['send_type'] == $this->repository::GET_COUPON_TYPE_SVIP) { + $data['coupon_type'] = 0; + $data['is_timeout'] = 0; + } + if ($data['is_timeout']) { + [$data['start_time'], $data['end_time']] = $data['range_date']; + if (strtotime($data['end_time']) <= time()) + throw new ValidateException('优惠券领取结束时间不能小于当前'); + } + if (!$data['use_type']) $data['use_min_price'] = 0; + unset($data['use_type']); + if ($data['coupon_type']) { + if (count(array_filter($data['use_start_time'])) != 2) + throw new ValidateException('请选择有效期限'); + [$data['use_start_time'], $data['use_end_time']] = $data['use_start_time']; + if ($data['use_start_time'] > $data['use_end_time']) { + throw new ValidateException('使用开始时间小于结束时间'); + } + } else unset($data['use_start_time']); + unset($data['range_date']); + if ($data['is_limited'] == 0) $data['total_count'] = 0; + if (!in_array($data['type'], [10, 11, 12])) { + throw new ValidateException('请选择有效的优惠券类型'); + } + return $data; + } + + public function send(StoreCouponSendValidate $validate, StoreCouponSendRepository $repository) + { + $data = $this->request->params(['coupon_id', 'mark', 'is_all', 'search', 'uid']); + $validate->check($data); + if (!$data['is_all'] && !count($data['uid'])) { + return app('json')->fail('请选择发送用户'); + } + $repository->create($data, 0); + return app('json')->success('创建成功,正在发送中'); + } + + public function sendLst( StoreCouponSendRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date', 'coupon_type', 'coupon_name', 'status']); + $where['mer_id'] = 0; + return app('json')->success($repository->getList($where, $page, $limit)); + } + + +} diff --git a/app/controller/admin/store/Discounts.php b/app/controller/admin/store/Discounts.php new file mode 100644 index 00000000..d0b20565 --- /dev/null +++ b/app/controller/admin/store/Discounts.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\store; + +use app\common\repositories\store\product\StoreDiscountRepository; +use crmeb\basic\BaseController; +use think\App; + +class Discounts extends BaseController +{ + + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param StoreDiscountRepository $repository + */ + public function __construct(App $app ,StoreDiscountRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','store_name','mer_id','title','status','type']); + $data = $this->repository->getAdminlist($where, $page, $limit); + return app('json')->success($data); + } + + public function detail($id) + { + $data = $this->repository->detail($id, 0); + if (!$data ) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function switchStatus($id) + { + $status = $this->request->param('status') == 1 ?: 0; + if (!$this->repository->getWhere([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status]); + return app('json')->success('修改成功'); + } + + + +} diff --git a/app/controller/admin/store/Express.php b/app/controller/admin/store/Express.php new file mode 100644 index 00000000..878bfb2a --- /dev/null +++ b/app/controller/admin/store/Express.php @@ -0,0 +1,201 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use crmeb\jobs\ExpressSyncJob; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\shipping\ExpressRepository as repository; +use think\facade\Queue; + +class Express extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * City constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @return mixed + */ + public function lst() + { + [$page , $limit] = $this->getPage(); + $where = $this->request->params(['keyword','code']); + $mer_id = $this->request->merId(); + if($mer_id) $where['is_show'] = 1; + return app('json')->success($this->repository->search($where, $page, $limit)); + } + + public function detail($id) + { + return app('json')->success($this->repository->get($id)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @return mixed + */ + public function create() + { + $data = $this->request->params(['name','code','is_show','sort']); + if(empty($data['name'])) + return app('json')->fail('名称不可为空'); + if($this->repository->codeExists($data['code'],null)) + return app('json')->fail('编码重复'); + if($this->repository->nameExists($data['name'],null)) + return app('json')->fail('名称重复'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param $id + * @return mixed + */ + public function update($id) + { + $data = $this->request->params(['name','code','is_show','sort']); + if(!$this->repository->fieldExists($id)) + return app('json')->fail('数据不存在'); + if(empty($data['name'])) + return app('json')->fail('名称不可为空'); + if($this->repository->codeExists($data['code'],$id)) + return app('json')->fail('编码重复'); + if($this->repository->nameExists($data['name'],$id)) + return app('json')->fail('名称重复'); + + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->fieldExists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->delete($id); + return app('json')->success('删除成功'); + + } + + /** + * @Author:Qinii + * @Date: 2020/5/22 + * @return mixed + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->request->merId()))); + } + + /** + * @Author:Qinii + * @Date: 2020/5/22 + * @param $id + * @return mixed + */ + public function updateForm($id) + { + if(!$this->repository->fieldExists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($this->request->merId(),$id))); + } + + /** + * @Author:Qinii + * @Date: 2020/5/22 + * @param int $id + * @return mixed + */ + public function switchStatus($id) + { + $status = $this->request->param('is_show', 0) == 1 ? 1 : 0; + if(!$this->repository->fieldExists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->switchStatus($id, ['is_show' =>$status]); + return app('json')->success('修改成功'); + } + + /** + * TODO 同步信息 + * @return \think\response\Json + * @author Qinii + * @day 7/23/21 + */ + public function syncAll() + { + Queue::push(ExpressSyncJob::class,[]); + return app('json')->success('后台同步中,请稍后来查看~'); + } + + public function partnerForm($id) + { + $merId = $this->request->merId(); + return app('json')->success(formToData($this->repository->partnerForm($id,$merId))); + } + + public function partner($id) + { + $data = $this->request->params(['account','key','net_name']); + + if (!$expressInfo = $this->repository->get($id)) + return app('json')->fail('编辑的记录不存在!'); + if ($expressInfo['partner_id'] == 1 && !$data['account']) + return app('json')->fail('请输入月结账号'); + if ($expressInfo['partner_key'] == 1 && !$data['key']) + return app('json')->fail('请输入月结密码'); + if ($expressInfo['net'] == 1 && !$data['net_name']) + return app('json')->fail('请输入取件网点'); + if ($expressInfo['check_man'] == 1 && !$data['check_man']) + return app('json')->fail('请输入承载快递员名称'); + if ($expressInfo['partner_name'] == 1 && !$data['partner_name']) + return app('json')->fail('请输入客户账户名称'); + if ($expressInfo['is_code'] == 1 && !$data['code']) + return app('json')->fail('请输入承载编号'); + + $data['express_id'] = $id; + $data['mer_id'] = $this->request->merId(); + + $this->repository->updatePartne($data); + return app('json')->success('修改成功'); + } + + public function options() + { + return app('json')->success($this->repository->options()); + } +} diff --git a/app/controller/admin/store/Guarantee.php b/app/controller/admin/store/Guarantee.php new file mode 100644 index 00000000..616a8c39 --- /dev/null +++ b/app/controller/admin/store/Guarantee.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\GuaranteeRepository; +use app\validate\admin\GuaranteeValidate; +use think\App; +use crmeb\basic\BaseController; + +class Guarantee extends BaseController +{ + /** + * @var GuaranteeRepository + */ + protected $repository; + + /** + * City constructor. + * @param App $app + * @param GuaranteeRepository $repository + */ + public function __construct(App $app, GuaranteeRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','keyword']); + $where['is_del'] = 0; + $data = $this->repository->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null))); + } + + public function create(GuaranteeValidate $validate) + { + $data = $this->checkParams($validate); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + public function update($id,GuaranteeValidate $validate) + { + $ret = $this->repository->get($id); + if(!$ret) return app('json')->fail('数据不存在'); + $data = $this->checkParams($validate); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + public function sort($id) + { + $ret = $this->repository->get($id); + if(!$ret) return app('json')->fail('数据不存在'); + $data = [ + 'sort' => $this->request->param('sort'), + ]; + $this->repository->update($id,$data); + + return app('json')->success('修改成功'); + } + + public function switchStatus($id) + { + $ret = $this->repository->get($id); + if(!$ret) return app('json')->fail('数据不存在'); + $data = [ + 'status' => $this->request->param('status') == 1 ?: 0, + ]; + $this->repository->update($id,$data); + + return app('json')->success('修改成功'); + } + + public function detail($id) + { + $ret = $this->repository->get($id); + if(!$ret) return app('json')->fail('数据不存在'); + return app('json')->success($ret); + } + + public function delete($id) + { + $ret = $this->repository->get($id); + if(!$ret) return app('json')->fail('数据不存在'); + $this->repository->update($id,['is_del' => 1]); + return app('json')->success('删除成功'); + } + + public function checkParams(GuaranteeValidate $validate) + { + $params = [ + "guarantee_name", "guarantee_info", "image", "status", "sort", + ]; + $data = $this->request->params($params); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/store/PriceRule.php b/app/controller/admin/store/PriceRule.php new file mode 100644 index 00000000..ed3bfb58 --- /dev/null +++ b/app/controller/admin/store/PriceRule.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\store; + +use app\common\repositories\store\PriceRuleRepository; +use app\validate\admin\PriceRuleValidate; +use crmeb\basic\BaseController; +use think\App; + +class PriceRule extends BaseController +{ + + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param PriceRuleRepository $repository + */ + public function __construct(App $app, PriceRuleRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + $where = $this->request->params(['cate_id', 'keyword', 'is_show']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->lst($where, $page, $limit)); + } + + public function update($id) + { + $data = $this->getParams(); + if (!$this->repository->exists((int)$id)) { + return app('json')->fail('数据不存在'); + } + $this->repository->updateRule((int)$id, $data); + return app('json')->success('编辑成功'); + } + + public function create() + { + $data = $this->getParams(); + $this->repository->createRule($data); + return app('json')->success('添加成功'); + } + + public function delete($id) + { + if (!$this->repository->exists((int)$id)) { + return app('json')->fail('数据不存在'); + } + $this->repository->delete((int)$id); + return app('json')->success('删除成功'); + } + + public function getParams() + { + $data = $this->request->params(['rule_name', 'cate_id', 'sort', 'is_show', 'content']); + app()->make(PriceRuleValidate::class)->check($data); + return $data; + } + + public function switchStatus($id) + { + $status = $this->request->param('is_show') == 1 ?: 0; + if (!$this->repository->exists((int)$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_show' => $status]); + return app('json')->success('修改成功'); + } + + +} diff --git a/app/controller/admin/store/ProductLabel.php b/app/controller/admin/store/ProductLabel.php new file mode 100644 index 00000000..7939a336 --- /dev/null +++ b/app/controller/admin/store/ProductLabel.php @@ -0,0 +1,100 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\store; + +use app\common\repositories\store\product\ProductLabelRepository; +use app\validate\admin\ProductLabelValidate; +use think\App; +use crmeb\basic\BaseController; + +class ProductLabel extends BaseController +{ + + protected $repository; + + public function __construct(App $app, ProductLabelRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['name', 'type', ['mer_id',0], 'status']); + $data = $this->repository->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null, 'systemStoreProductLabelCreate'))); + } + + public function create(ProductLabelValidate $validate) + { + $data = $this->request->params(['label_name', 'status', 'sort', 'info']); + $validate->check($data); + if (!$this->repository->check($data['label_name'], 0)) + return app('json')->fail('名称重复'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm($id, 'systemStoreProductLabelUpdate'))); + } + + public function update($id, ProductLabelValidate $validate) + { + $data = $this->request->params(['label_name', 'status', 'sort', 'info']); + $validate->check($data); + if (!$this->repository->check($data['label_name'], 0,$id)) + return app('json')->fail('名称重复'); + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => 0]); + if (!$getOne) return app('json')->fail('数据不存在'); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + public function detail($id) + { + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => 0, 'is_del' => 0]); + if (!$getOne) return app('json')->fail('数据不存在'); + return app('json')->success($getOne); + } + + public function delete($id) + { + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => 0]); + if (!$getOne) return app('json')->fail('数据不存在'); + $this->repository->update($id,['is_del' => 1]); + return app('json')->success('删除成功'); + } + + + public function switchWithStatus($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => 0]); + if (!$getOne) return app('json')->fail('数据不存在'); + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + + public function getOptions() + { + $data = $this->repository->getOptions(0); + return app('json')->success($data); + } + +} diff --git a/app/controller/admin/store/StoreBrand.php b/app/controller/admin/store/StoreBrand.php new file mode 100644 index 00000000..3065060d --- /dev/null +++ b/app/controller/admin/store/StoreBrand.php @@ -0,0 +1,140 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use think\App; +use crmeb\basic\BaseController; +use app\validate\admin\StoreBrandValidate as validate; +use app\common\repositories\store\StoreBrandRepository; + +class StoreBrand extends BaseController +{ + + protected $repository; + + /** + * ArticleCategory constructor. + * @param App $app + * @param StoreBrandRepository $repository + */ + public function __construct(App $app, StoreBrandRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * 列表 + * @return mixed + * @author Qinii + */ + public function lst() + { + [$page , $limit] = $this->getPage(); + $where = $this->request->params(['brand_category_id','brand_name']); + + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function create(validate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->parentExists($data['brand_category_id'])) + return app('json')->fail('上级分类不存在'); + if ($this->repository->merExistsBrand($data['brand_name'])) + return app('json')->fail('该品牌已存在'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->meExists($id)) + return app('json')->fail('数据不存在'); + if (!$this->repository->parentExists($data['brand_category_id'])) + return app('json')->fail('上级分类不存在'); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + + public function delete($id) + { + if(!$this->repository->meExists($id)) + return app('json')->fail('数据不存在'); + if($this->repository->getBrandHasProduct($id)) + return app('json')->fail('该品牌下存在商品'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function detail($id) + { + if (!$this->repository->meExists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)); + } + /** + * 验证 + * @param validate $validate + * @param bool $isCreate + * @return array + * @author Qinii + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['brand_category_id','brand_name','is_show','sort','pic']); + $validate->check($data); + return $data; + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @return mixed + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @param $id + * @return mixed + */ + public function updateForm($id) + { + if (!$this->repository->meExists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @param int $id + * @return mixed + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->meExists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id, ['is_show' => $status]); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreBrandCategory.php b/app/controller/admin/store/StoreBrandCategory.php new file mode 100644 index 00000000..0897e2e3 --- /dev/null +++ b/app/controller/admin/store/StoreBrandCategory.php @@ -0,0 +1,136 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\validate\admin\StoreBrandCategoryValidate as validate; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreBrandCategoryRepository as repository; + +class StoreBrandCategory extends BaseController +{ + + protected $repository; + + /** + * ArticleCategory constructor. + * @param App $app + * @param StoreBrandCategoryRepository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * 列表 + * @return mixed + * @author Qinii + */ + public function lst() + { + $status = $this->request->param('status',null); + return app('json')->success($this->repository->getFormatList($this->request->merId(),$status)); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->request->merId()))); + } + + public function updateForm($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($this->request->merId(),$id))); + } + + public function create(validate $validate) + { + $data = $this->checkParams($validate); + if ($data['pid'] && !$this->repository->merExists($this->request->merId(), $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'])) + return app('json')->fail('不可添加更低阶分类'); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + + $brand = $this->repository->getWhere(['store_brand_category_id' => $id]); + if (!$brand) + return app('json')->fail('数据不存在'); + + if ($data['pid'] && !$this->repository->merExists($this->request->merId(), $data['pid'])) + return app('json')->fail('上级分类不存在'); + + if ($data['pid'] && !$this->repository->checkLevel($data['pid'])) + return app('json')->fail('不可添加更低阶分类'); + + if (!$this->repository->checkChangeToChild($id, $data['pid'])) + return app('json')->fail('无法修改到当前分类到子集,请先修改子类'); + + if ($brand['pid'] != $data['pid'] && !$this->repository->checkChildLevel($id, $data['pid'])) + return app('json')->fail('子类超过最低限制,请先修改子类'); + + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + + $this->repository->switchStatus($id, $status); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->hasChild($id)) + return app('json')->fail('该分类存在子集,请先处理子集'); + + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function detail($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)); + } + /** + * 验证 + * @param WechatNewsValidate $validate + * @param bool $isCreate + * @return array + * @author Qinii + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['pid','cate_name','is_show','sort']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/store/StoreCategory.php b/app/controller/admin/store/StoreCategory.php new file mode 100644 index 00000000..1d131296 --- /dev/null +++ b/app/controller/admin/store/StoreCategory.php @@ -0,0 +1,249 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\validate\admin\StoreCategoryValidate as validate; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreCategoryRepository as repository; + +class StoreCategory extends BaseController +{ + + /** + * @var repository|ArticleCategoryRepository + */ + protected $repository; + + /** + * ArticleCategory constructor. + * @param App $app + * @param ArticleCategoryRepository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * 列表 + * @return mixed + * @author Qinii + */ + public function lst() + { + return app('json')->success($this->repository->getFormatList($this->request->merId())); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @return mixed + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->request->merId()))); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + * @return mixed + */ + public function updateForm($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($this->request->merId(),$id))); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param validate $validate + * @return mixed + */ + public function create(validate $validate) + { + $data = $this->checkParams($validate); + $data['cate_name'] = trim($data['cate_name']); + if($data['cate_name'] == '') return app('json')->fail('分类名不可为空'); + + if ($data['pid'] && !$this->repository->merExists($this->request->merId(), $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'],0,$this->request->merId())) + return app('json')->fail('不可添加更低阶分类'); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + + if(!$this->repository->checkUpdate($id,$data['pid'])){ + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + if ($data['pid'] && !$this->repository->merExists($this->request->merId(), $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'],0,$this->request->merId())) + return app('json')->fail('不可添加更低阶分类'); + if (!$this->repository->checkChangeToChild($id,$data['pid'])) + return app('json')->fail('无法修改到当前分类到子集,请先修改子类'); + if (!$this->repository->checkChildLevel($id,$data['pid'], $this->request->merId())) + return app('json')->fail('子类超过最低限制,请先修改子类'); + } + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + /** + * 修改状态 + * @param int $id + * @return mixed + * @author Qinii + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->switchStatus($id, $status); + return app('json')->success('修改成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + * @return mixed + */ + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->hasChild($id)) + return app('json')->fail('该分类存在子集,请先处理子集'); + + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + * @return mixed + */ + public function detail($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)); + } + /** + * 验证 + * @param WechatNewsValidate $validate + * @param bool $isCreate + * @return array + * @author Qinii + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['pid','cate_name','is_show','pic','sort']); + $validate->check($data); + return $data; + } + + /** + * @Author:Qinii + * @Date: 2020/5/16 + * @return mixed + */ + public function getTreeList() + { + $data = $this->repository->getTreeList($this->request->merId(),1); + $ret = []; + foreach ($data as $datum) { + if (isset($datum['children'])) { + $ret[] = $datum; + } + } + return app('json')->success($ret); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getList() + { + $type = $this->request->param('type',null); + $lv = $this->request->param('lv',null); + if (!is_null($lv)) $lv = $lv + 1; + $data = $this->repository->getList($type,$lv); + if ($lv) { + $ret = $data; + } else { + $ret = []; + foreach ($data as $key => $value) { + if (isset($value['children'])) { + $level = []; + foreach ($value['children'] as $child) { + if (isset($child['children'])) { + $level[] = $child; + } + } + if (isset($level) && !empty($level)) { + $value['children'] = $level; + $ret[] = $value; + } + } + } + } + return app('json')->success($ret); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function BrandList() + { + return app('json')->success($this->repository->getBrandList()); + } + + + public function switchIsHot($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + + $this->repository->updateStatus($id, ['is_hot' => $status]); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreProduct.php b/app/controller/admin/store/StoreProduct.php new file mode 100644 index 00000000..c98142ff --- /dev/null +++ b/app/controller/admin/store/StoreProduct.php @@ -0,0 +1,303 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use think\App; +use crmeb\basic\BaseController; +use app\validate\merchant\StoreProductAdminValidate as validate; +use app\common\repositories\store\product\ProductRepository as repository; +use think\facade\Queue; + +class StoreProduct extends BaseController +{ + + + /** + * @var repository + */ + protected $repository; + + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['cate_id', 'keyword', ['type', 1], 'mer_cate_id', 'pid','store_name','is_trader','us_status','product_id','star','sys_labels','hot_type','svip_price_type']); + $mer_id = $this->request->param('mer_id',''); + $merId = $mer_id ? $mer_id : null; + $where['is_gift_bag'] = 0; + $_where = $this->repository->switchType($where['type'], null,0); + unset($_where['star']); + $where = array_merge($where, $_where); + return app('json')->success($this->repository->getAdminList($merId, $where, $page, $limit)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function bagList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['cate_id','keyword',['type',1],'mer_cate_id' ,'is_trader','us_status']); + $merId = $this->request->param('mer_id') ? $this->request->param('mer_id') : null; + + $_where = $this->repository->switchType($where['type'], null,10); + $where = array_merge($where,$_where); + $where['order'] = 'rank'; + unset($where['star']); + return app('json')->success($this->repository->getAdminList($merId,$where, $page, $limit)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getStatusFilter() + { + return app('json')->success($this->repository->getFilter(null,'商品',0)); + } + + /** + * TODO 礼包表头 + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getBagStatusFilter() + { + return app('json')->success($this->repository->getFilter(null,'礼包',10)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function detail($id) + { + if(!$this->repository->merExists(null,$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id,0)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + $this->repository->adminUpdate($id,$data); + return app('json')->success('编辑成功'); + } + + /** + * TODO 审核 / 下架 + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @return mixed + */ + public function switchStatus() + { + //0:审核中,1:审核通过 -1: 未通过 -2: 下架 + $id = $this->request->param('id'); + $data = $this->request->params(['status','refusal']); + if (in_array($data['status'],[1,0,-2,-1])) + if($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + if(is_array($id)) { + $this->repository->batchSwitchStatus($id,$data); + } else { + $this->repository->switchStatus($id,$data); + } + return app('json')->success('操作成功'); + } + + + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param validate $validate + * @return array + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['is_hot','is_best','is_benefit','is_new','store_name','content','rank','star']); + $validate->check($data); + return $data; + } + + /** + * TODO + * @author Qinii + * @day 2020-06-24 + */ + public function checkProduct() + { + Queue::push(CheckProductExtensionJob::class,[]); + return app('json')->success('后台已开始检测'); + } + + public function lists() + { + $make = app()->make(MerchantRepository::class); + $data = $make->selectWhere(['is_del' => 0],'mer_id,mer_name'); + return app('json')->success($data); + } + + /** + * 增加虚拟销量表单 + * @Author:Qinii + * @Date: 2020/10/9 + * @param $id + * @return mixed + */ + public function addFictiForm($id) + { + if(!$this->repository->merExists(null,$id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->fictiForm($id))); + } + + /** + * 修改虚拟销量 + * @Author:Qinii + * @Date: 2020/10/9 + * @param $id + * @return mixed + * + */ + public function addFicti($id) + { + $data = $this->request->params(['type','ficti']); + if(!in_array($data['type'],[1,2])) return app('json')->fail('类型错误'); + if(!$data['ficti'] || $data['ficti'] < 0) return app('json')->fail('已售数量必须大于0'); + $res = $this->repository->getWhere(['product_id' => $id],'ficti,sales'); + if(!$res) return app('json')->fail('数据不存在'); + if($data['type'] == 2 && $res['ficti'] < $data['ficti']) return app('json')->fail('已售数量不足'); + $ficti = ($data['type'] == 1) ? $data['ficti'] : '-' . $data['ficti']; + $data = [ + 'ficti' => $res['ficti'] + $ficti, + 'sales' => $res['sales'] + $ficti + ]; + $this->repository->update($id,$data); + return app('json')->success('修改成功'); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/17/21 + */ + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id,null,['rank' => $sort]); + return app('json')->success('修改成功'); + } + + public function setLabels($id) + { + $data = $this->request->params(['sys_labels']); + app()->make(SpuRepository::class)->setLabels($id,0,$data,0); + return app('json')->success('修改成功'); + } + + /** + * TODO 是否隐藏 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-17 + */ + public function changeUsed($id) + { + if(!$this->repository->merExists(null,$id)) + return app('json')->fail('数据不存在'); + $status = $this->request->param('status',0) == 1 ? 1 : 0; + $this->repository->switchShow($id,$status,'is_used',0); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量显示隐藏 + * @return \think\response\Json + * @author Qinii + * @day 2022/11/14 + */ + public function batchShow() + { + $ids = $this->request->param('ids'); + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->batchSwitchShow($ids,$status,'is_used',0); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量标签 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchLabels() + { + $ids = $this->request->param('ids'); + $data = $this->request->params(['sys_labels']); + if (empty($ids)) return app('json')->fail('请选择商品'); + app()->make(SpuRepository::class)->batchLabels($ids, $data,0); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置推荐类型 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchHot() + { + $ids = $this->request->param('ids'); + $data = $this->request->params([['is_hot',0],['is_benefit',0],['is_best',0],['is_new',0]]); + if (empty($ids)) return app('json')->fail('请选择商品'); + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreProductAssist.php b/app/controller/admin/store/StoreProductAssist.php new file mode 100644 index 00000000..af064096 --- /dev/null +++ b/app/controller/admin/store/StoreProductAssist.php @@ -0,0 +1,138 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\product\ProductAssistRepository as repository; +use app\common\repositories\store\product\SpuRepository; +use app\validate\merchant\StoreProductAdminValidate as validate; +use crmeb\basic\BaseController; +use crmeb\services\SwooleTaskService; +use think\App; + +class StoreProductAssist extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['product_status', 'keyword', 'status', 'type', 'mer_id', 'is_trader', 'us_status', 'star', 'product_assist_id', 'sys_labels']); + $data = $this->repository->getAdminList($where, $page, $limit); + return app('json')->success($data); + } + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + $data = $this->repository->detail(null, $id); + return app('json')->success($data); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$ret = $this->repository->get($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status]); + app()->make(SpuRepository::class)->changeStatus($id,3); + return app('json')->success('修改成功'); + } + + + /** + * TODO 获取商品 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-11-02 + */ + public function get($id) + { + if (!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $data = $this->repository->get($id); + return app('json')->success($data); + } + + /** + * TODO 编辑商品 + * @param $id + * @param validate $validate + * @return mixed + * @author Qinii + * @day 2020-11-02 + */ + public function update($id, validate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $this->repository->updateProduct($id, $data); + return app('json')->success('编辑成功'); + } + + public function checkParams(validate $validate) + { + $data = $this->request->params(['is_hot', 'is_best', 'is_benefit', 'is_new', 'store_name', 'keyword', 'content', 'rank', 'star']); + $validate->check($data); + return $data; + } + + /** + * TODO 审核 + * @return \think\response\Json + * @author Qinii + * @day 2022/11/15 + */ + public function switchAudit() + { + $id = $this->request->param('id'); + if (!$ret = $this->repository->get($id)) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['status', 'refusal']); + if ($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + $this->repository->switchStatus($id,$data); + return app('json')->success('操作成功'); + } + + public function setLabels($id) + { + $data = $this->request->params(['sys_labels']); + app()->make(SpuRepository::class)->setLabels($id, 3, $data, 0); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreProductAssistSet.php b/app/controller/admin/store/StoreProductAssistSet.php new file mode 100644 index 00000000..6d3d7b4b --- /dev/null +++ b/app/controller/admin/store/StoreProductAssistSet.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\product\ProductAssistSetRepository as repository; +use app\common\repositories\store\product\ProductAssistUserRepository; +use app\common\repositories\system\CacheRepository; +use crmeb\basic\BaseController; +use think\App; +use app\validate\merchant\StoreProductPresellValidate; + +class StoreProductAssistSet extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','status','type','date','user_name','mer_id','is_trader']); + return app('json')->success($this->repository->getAdminList($where,$page,$limit)); + } + + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + [$page, $limit] = $this->getPage(); + $where['product_assist_set_id'] = $id; + $make = app()->make(ProductAssistUserRepository::class); + return app('json')->success($make->userList($where,$page,$limit)); + } + + +} diff --git a/app/controller/admin/store/StoreProductGroup.php b/app/controller/admin/store/StoreProductGroup.php new file mode 100644 index 00000000..b5fdf53f --- /dev/null +++ b/app/controller/admin/store/StoreProductGroup.php @@ -0,0 +1,132 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\store; + +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\validate\merchant\StoreProductAdminValidate as validate; +use crmeb\basic\BaseController; +use think\App; + +class StoreProductGroup extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, ProductGroupRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['product_status', 'keyword', 'status', 'active_type', 'mer_id', 'is_trader', 'level', 'us_status', 'star', 'product_group_id', 'sys_labels']); + $data = $this->repository->getAdminList($where, $page, $limit); + return app('json')->success($data); + } + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + $data = $this->repository->detail(null, $id); + return app('json')->success($data); + } + + /** + * TODO 获取商品 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-11-02 + */ + public function get($id) + { + $data = $this->repository->get($id); + if (!$data) return app('json')->fail('数据不存在'); + $res = app()->make(ProductRepository::class)->getAdminOneProduct($data['product_id'], $id); + $res['product_group_id'] = $id; + if (!$data) return app('json')->fail('数据不存在'); + return app('json')->success($res); + } + + /** + * TODO 编辑商品 + * @param $id + * @param validate $validate + * @return mixed + * @author Qinii + * @day 2020-11-02 + */ + public function update($id, validate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $this->repository->updateProduct($id, $data); + return app('json')->success('编辑成功'); + } + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$ret = $this->repository->get($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status]); + app()->make(SpuRepository::class)->changeStatus($id,4); + return app('json')->success('修改成功'); + } + + public function checkParams(validate $validate) + { + $data = $this->request->params(['is_hot', 'is_best', 'is_benefit', 'is_new', 'store_name', 'keyword', 'content', 'rank', 'star']); + $validate->check($data); + return $data; + } + + public function switchAudit() + { + $id = $this->request->param('id'); + $data = $this->request->params(['status', 'refusal']); + if ($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + $this->repository->switchStatus($id, $data); + return app('json')->success('操作成功'); + } + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id, null, ['rank' => $sort]); + return app('json')->success('修改成功'); + } + + public function setLabels($id) + { + $data = $this->request->params(['sys_labels']); + // if (empty($data['sys_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id, 4, $data, 0); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreProductGroupBuying.php b/app/controller/admin/store/StoreProductGroupBuying.php new file mode 100644 index 00000000..21d393a8 --- /dev/null +++ b/app/controller/admin/store/StoreProductGroupBuying.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\store; + +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupUserRepository; +use crmeb\basic\BaseController; +use think\App; + +class StoreProductGroupBuying extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param ProductGroupBuyingRepository $repository + */ + public function __construct(App $app, ProductGroupBuyingRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * TODO 团列表 + * @return \think\response\Json + * @author Qinii + * @day 1/12/21 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','status','date','mer_id','is_trader','user_name']); + $data = $this->repository->getAdminList($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO 团成员列表 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 1/12/21 + */ + public function detail($id) + { + [$page, $limit] = $this->getPage(); + if(!$this->repository->get($id)) + return app('json')->fail('数据不存在'); + $where = ['group_buying_id' => $id]; + $list = app()->make(ProductGroupUserRepository::class)->getAdminList($where,$page,$limit); + return app('json')->success($list); + } +} diff --git a/app/controller/admin/store/StoreProductPresell.php b/app/controller/admin/store/StoreProductPresell.php new file mode 100644 index 00000000..c913dffe --- /dev/null +++ b/app/controller/admin/store/StoreProductPresell.php @@ -0,0 +1,130 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\product\ProductPresellRepository as repository; +use app\common\repositories\store\product\SpuRepository; +use crmeb\basic\BaseController; +use think\App; +use app\validate\merchant\StoreProductAdminValidate as validate; + +class StoreProductPresell extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['product_status','keyword','status','type','presell_type','mer_id','is_trader','us_status','star','product_presell_id','sys_labels']); + $data = $this->repository->getAdminList($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + $data = $this->repository->detail(null,$id); + return app('json')->success($data); + } + + /** + * TODO 获取商品 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-11-02 + */ + public function get($id) + { + $data = $this->repository->get($id); + if(!$data) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + /** + * TODO 编辑商品 + * @param $id + * @param validate $validate + * @return mixed + * @author Qinii + * @day 2020-11-02 + */ + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $this->repository->updateProduct($id,$data); + return app('json')->success('编辑成功'); + + } + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if(!$ret = $this->repository->get($id)) return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status]); + app()->make(SpuRepository::class)->changeStatus($id,2); + return app('json')->success('修改成功'); + } + + + public function checkParams(validate $validate) + { + $data = $this->request->params(['is_hot','is_best','is_benefit','is_new','store_name','keyword','content','rank','star']); + $validate->check($data); + return $data; + } + + public function switchAudit() + { + $id = $this->request->param('id'); + $data = $this->request->params(['status','refusal']); + if($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + $this->repository->switchStatus($id, $data); + return app('json')->success('操作成功'); + } + + public function setLabels($id) + { + $data = $this->request->params(['sys_labels']); +// if (empty($data['sys_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id,2,$data,0); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/admin/store/StoreProductReply.php b/app/controller/admin/store/StoreProductReply.php new file mode 100644 index 00000000..32a50283 --- /dev/null +++ b/app/controller/admin/store/StoreProductReply.php @@ -0,0 +1,162 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\store; + + +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductReplyRepository; +use app\common\repositories\store\product\ProductRepository; +use app\validate\admin\StoreProductReplyValidate; +use crmeb\services\ApiResponseService; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class StoreProductReply + * @package app\controller\admin\store + * @author xaboy + * @day 2020/6/1 + */ +class StoreProductReply extends BaseController +{ + /** + * @var ProductReplyRepository + */ + protected $repository; + + /** + * StoreProductReply constructor. + * @param App $app + * @param ProductReplyRepository $repository + */ + public function __construct(App $app, ProductReplyRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'nickname', 'is_reply', 'date', 'product_id']); + $where['mer_id'] = $this->request->merId() ?: ''; + return \app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param null $productId + * @throws FormBuilderException + * @author xaboy + * @day 2020/6/1 + */ + public function virtualForm($productId = null) + { + if ($productId && !app()->make(ProductRepository::class)->exists($productId)) { + app('json')->fail('商品不存在'); + } + return app('json')->success(formToData($this->repository->form($productId))); + } + + /** + * @param StoreProductReplyValidate $validate + * @return mixed + * @author xaboy + * @day 2020/6/1 + */ + public function virtualReply(StoreProductReplyValidate $validate) + { + $data = $this->checkParams($validate); + $_name = mb_substr($data['nickname'], 0, 1) . '***'; + $name = (strLen($data['nickname']) > 6) ? $_name . mb_substr($data['nickname'], -1, 1) : $_name; + $data['nickname'] = $name; + $productId = $data['product_id']; + unset($data['product_id']); + $this->repository->createVirtual([$productId], $data); + + return app('json')->success('添加成功'); + } + + public function replyForm($id) + { + $merId = $this->request->merId(); + if ($merId) + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在');; + return app('json')->success(formToData($this->repository->replyForm($id, $merId))); + } + + public function reply($id) + { + $merId = $this->request->merId(); + if ($merId) + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $merchant_reply_content = $this->request->param('content'); + if (!$merchant_reply_content) + return app('json')->fail('请输入回复的内容'); + $merchant_reply_time = date('Y-m-d H:i:s'); + $is_reply = 1; + $this->repository->update($id, compact('is_reply', 'merchant_reply_content', 'merchant_reply_time')); + return app('json')->success('回复成功'); + } + + /** + * @param $id + * @return int + * @throws DbException + * @author xaboy + * @day 2020/6/1 + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * @param StoreProductReplyValidate $validate + * @return array + * @author xaboy + * @day 2020/6/1 + */ + public function checkParams(StoreProductReplyValidate $validate) + { + $data = $this->request->params([['product_id', []], 'nickname', 'comment', 'product_score', 'service_score', 'postage_score', 'avatar', ['pics', '']]); + $validate->check($data); + $data['product_id'] = $data['product_id']['id'] ?? 0; + return $data; + } + + public function sort($id) + { + $data = $this->request->params(['sort']); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreProductSeckill.php b/app/controller/admin/store/StoreProductSeckill.php new file mode 100644 index 00000000..fd914bdf --- /dev/null +++ b/app/controller/admin/store/StoreProductSeckill.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use think\App; +use crmeb\basic\BaseController; +use app\validate\merchant\StoreProductAdminValidate as validate; +use app\common\repositories\store\product\ProductRepository as repository; +use think\facade\Queue; + +class StoreProductSeckill extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['cate_id', 'keyword', ['type', 1], 'mer_cate_id', 'pid', 'seckill_status', 'is_trader', 'us_status', 'star', 'product_id', 'sys_labels']); + $mer_id = $this->request->param('mer_id'); + $merId = $mer_id ? $mer_id : null; + $where_ = $this->repository->switchType($where['type'], $merId, 1); + unset($where_['star']); + $where = array_merge($where, $where_); + return app('json')->success($this->repository->getAdminSeckillList($merId, $where, $page, $limit)); + } + + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-08-04 + */ + public function getStatusFilter() + { + return app('json')->success($this->repository->getFilter(null, '秒杀商品', 1)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function detail($id) + { + if (!$this->repository->merExists(null, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id, null)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id, validate $validate) + { + $data = $this->checkParams($validate); + $this->repository->adminUpdate($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @return mixed + */ + public function switchStatus() + { + $id = $this->request->param('id'); + $data = $this->request->params(['status', 'refusal']); + if ($data['status'] == -1 && empty($data['refusal'])) + return app('json')->fail('请填写拒绝理由'); + if (is_array($id)) { + $this->repository->batchSwitchStatus($id, $data); + } else { + $this->repository->switchStatus($id, $data); + } + return app('json')->success('操作成功'); + } + + /** + * TODO 是否隐藏 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-17 + */ + public function changeUsed($id) + { + if (!$this->repository->merExists(null, $id)) + return app('json')->fail('数据不存在'); + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + $this->repository->switchShow($id, $status,'is_used'); + return app('json')->success('修改成功'); + } + + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @param validate $validate + * @return array + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['is_hot', 'is_best', 'is_benefit', 'is_new', 'store_name', 'keyword', 'content', 'rank', 'star']); + $validate->check($data); + return $data; + } + + /** + * TODO + * @author Qinii + * @day 2020-06-24 + */ + public function checkProduct() + { + Queue::push(CheckProductExtensionJob::class, []); + return app('json')->success('后台已开始检测'); + } + + public function lists() + { + $make = app()->make(MerchantRepository::class); + $data = $make->selectWhere(['status' => 1, 'mer_state' => 1, 'is_del' => 0], 'mer_id,mer_name'); + return app('json')->success($data); + } + + public function setLabels($id) + { + $data = $this->request->params(['sys_labels']); + // if (empty($data['sys_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id, 1, $data, 0); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/store/StoreSeckill.php b/app/controller/admin/store/StoreSeckill.php new file mode 100644 index 00000000..09fe756d --- /dev/null +++ b/app/controller/admin/store/StoreSeckill.php @@ -0,0 +1,155 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use think\App; +use crmeb\basic\BaseController; +use app\validate\admin\StoreSeckillValidate; +use app\common\repositories\store\StoreSeckillTimeRepository as repository; + +class StoreSeckill extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * Express constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @return mixed + */ + public function lst() + { + [$page , $limit] = $this->getPage(); + $where = $this->request->params(['title','status']); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-08-01 + */ + public function select() + { + return app('json')->success($this->repository->select()); + } + + /** + * @Author:Qinii + * @Date: 2020/5/13 + * @return mixed + */ + public function create(StoreSeckillValidate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->checkTime($data,null)) + return app('json')->fail('时间段不可重叠'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * TODO + * @param $id + * @param StoreSeckillValidate $validate + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function update($id,StoreSeckillValidate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->checkTime($data,$id)) + return app('json')->fail('时间段不可重叠'); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function delete($id) + { + if(!$this->repository->get($id)) + return app('json')->fail('数据不存在'); + + $this->repository->delete($id); + return app('json')->success('删除成功'); + + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-31 + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if(!$this->repository->get($id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id, ['status' =>$status]); + return app('json')->success('修改成功'); + } + + public function checkParams(StoreSeckillValidate $validate) + { + $data = $this->request->params(['start_time','end_time','status','title','pic']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/store/StoreService.php b/app/controller/admin/store/StoreService.php new file mode 100644 index 00000000..9e6a51f4 --- /dev/null +++ b/app/controller/admin/store/StoreService.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceRepository; + +class StoreService extends BaseController +{ + /** + * @var StoreServiceRepository + */ + protected $repository; + /** + * @var StoreServiceLogRepository + */ + protected $logRepository; + + /** + * StoreService constructor. + * @param App $app + * @param StoreServiceRepository $repository + */ + public function __construct(App $app, StoreServiceRepository $repository,StoreServiceLogRepository $logRepository) + { + parent::__construct($app); + $this->repository = $repository; + $this->logRepository = $logRepository; + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function lst($id) + { + $where = $this->request->params(['keyword', 'status']); + [$page, $limit] = $this->getPage(); + $where['mer_id'] = $id; + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @param $uid + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function getUserMsnByMerchant($uid,$id) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getUserMsn($uid, $page, $limit,$id)); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function merchantUserList($id) + { + [$page, $limit] = $this->getPage(); + return app('json')->success( $this->logRepository->getMerchantUserList($id, $page, $limit)); + } +} diff --git a/app/controller/admin/store/marketing/StoreAtmosphere.php b/app/controller/admin/store/marketing/StoreAtmosphere.php new file mode 100644 index 00000000..4faf93ba --- /dev/null +++ b/app/controller/admin/store/marketing/StoreAtmosphere.php @@ -0,0 +1,176 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store\marketing; + +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\RelevanceRepository; +use app\validate\admin\StoreActivityValidate; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreActivityRepository as repository; + +/** + * 边框 + * Class StoreActivitySweet + * @package app\controller\admin\store\activity + */ +class StoreAtmosphere extends BaseController +{ + + /** + * @var repository + */ + protected $repository; + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * 列表 + * @return mixed + * @Author: liusl + * @Date: 2022/6/24 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'status', 'date']); + $where['activity_type'] = repository::ACTIVITY_TYPE_ATMOSPHERE; + return app('json')->success($this->repository->getAdminList($where, $page, $limit)); + } + + /** + * TODO + * @param StoreActivityValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 2022/9/16 + */ + public function create(StoreActivityValidate $validate) + { + $data = $this->checkParams($validate); + $extend = [ + 'spu_ids' => $data['spu_ids'], + 'cate_ids' => $data['cate_ids'], + 'mer_ids' => $data['mer_ids'], + ]; + unset($data['spu_ids'], $data['cate_ids'], $data['mer_ids']); + $this->repository->createActivity($data, $extend); + return app('json')->success('添加成功'); + } + + /** + * TODO + * @param StoreActivityValidate $validate + * @return array + * @author Qinii + * @day 2022/9/15 + */ + public function checkParams(StoreActivityValidate $validate) + { + $params = ["activity_name","start_time","end_time", "is_show", "pic", "spu_ids", 'cate_ids', 'mer_ids','scope_type']; + $data = $this->request->params($params); + $validate->check($data); + $data['activity_type'] = repository::ACTIVITY_TYPE_ATMOSPHERE; + if (strtotime($data['start_time']) <= time()) { + $data['status'] = 1; + } + return $data; + } + + /** + * TODO + * @param StoreActivityValidate $validate + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 2022/9/17 + */ + public function update(StoreActivityValidate $validate, $id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $data = $this->checkParams($validate); + $extend = [ + 'spu_ids' => $data['spu_ids'], + 'cate_ids' => $data['cate_ids'], + 'mer_ids' => $data['mer_ids'], + ]; + unset($data['spu_ids'], $data['cate_ids'], $data['mer_ids']); + $this->repository->updateActivity($id,$data, $extend); + return app('json')->success('修改成功'); + } + + public function statusSwitch($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + $this->repository->update($id, ['is_show' => $status]); + return app('json')->success('修改成功'); + } + + /** + * TODO 详情 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 2022/9/16 + */ + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->detail($id)); + } + + /** + * 删除 + * @param $id + * @return mixed + * @Author: liusl + * @Date: 2022/6/27 + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->deleteActivity($id); + return app('json')->success('删除成功'); + } + + public function markLst(SpuRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([ + 'keyword', + 'cate_id', + 'cate_pid', + 'brand_id', + 'product_type', + 'spu_ids', + 'mer_id' + ]); + $where['is_gift_bag'] = 0; + $data = $repository->makinList($where, $page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/store/marketing/StoreBorder.php b/app/controller/admin/store/marketing/StoreBorder.php new file mode 100644 index 00000000..9132a55d --- /dev/null +++ b/app/controller/admin/store/marketing/StoreBorder.php @@ -0,0 +1,170 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\store\marketing; + +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\RelevanceRepository; +use app\validate\admin\StoreActivityValidate; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreActivityRepository as repository; + +class StoreBorder extends BaseController +{ + + /** + * @var repository + */ + protected $repository; + + /** + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * 列表 + * @return mixed + * @Author: liusl + * @Date: 2022/6/24 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'status', 'date']); + $where['activity_type'] = repository::ACTIVITY_TYPE_BORDER; + return app('json')->success($this->repository->getAdminList($where, $page, $limit)); + } + + /** + * TODO + * @param StoreActivityValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 2022/9/16 + */ + public function create(StoreActivityValidate $validate) + { + $data = $this->checkParams($validate); + $extend = [ + 'spu_ids' => $data['spu_ids'], + 'cate_ids' => $data['cate_ids'], + 'mer_ids' => $data['mer_ids'], + ]; + unset($data['spu_ids'], $data['cate_ids'], $data['mer_ids']); + $this->repository->createActivity($data, $extend); + return app('json')->success('添加成功'); + } + + /** + * TODO + * @param StoreActivityValidate $validate + * @return array + * @author Qinii + * @day 2022/9/15 + */ + public function checkParams(StoreActivityValidate $validate) + { + $params = ["activity_name","start_time","end_time", "is_show", "pic", "spu_ids", 'cate_ids', 'mer_ids','scope_type']; + $data = $this->request->params($params); + $validate->check($data); + $data['activity_type'] = repository::ACTIVITY_TYPE_BORDER; + if (strtotime($data['start_time']) <= time()) { + $data['status'] = 1; + } + return $data; + } + + /** + * TODO + * @param StoreActivityValidate $validate + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 2022/9/17 + */ + public function update(StoreActivityValidate $validate, $id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $data = $this->checkParams($validate); + $extend = [ + 'spu_ids' => $data['spu_ids'], + 'cate_ids' => $data['cate_ids'], + 'mer_ids' => $data['mer_ids'], + ]; + unset($data['spu_ids'], $data['cate_ids'], $data['mer_ids']); + $this->repository->updateActivity($id,$data, $extend); + return app('json')->success('修改成功'); + } + + public function statusSwitch($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + $this->repository->update($id, ['is_show' => $status]); + return app('json')->success('修改成功'); + } + + /** + * TODO 详情 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 2022/9/16 + */ + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->detail($id)); + } + + /** + * 删除 + * @param $id + * @return mixed + * @Author: liusl + * @Date: 2022/6/27 + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->deleteActivity($id); + return app('json')->success('删除成功'); + } + + public function markLst(SpuRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([ + 'keyword', + 'cate_id', + 'cate_pid', + 'brand_id', + 'product_type', + 'spu_ids', + 'mer_id' + ]); + $where['is_gift_bag'] = 0; + $data = $repository->makinList($where, $page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/system/Cache.php b/app/controller/admin/system/Cache.php new file mode 100644 index 00000000..44724f3d --- /dev/null +++ b/app/controller/admin/system/Cache.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\system; + +use app\common\repositories\system\CacheRepository; +use crmeb\basic\BaseController; +use think\App; + +class Cache extends BaseController +{ + /** + * @var CacheRepository + */ + protected $repository; + + /** + * CacheRepository constructor. + * @param App $app + */ + public function __construct(App $app, CacheRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function getKeyLst() + { + $type = $this->request->param('type',0); + $data = $this->repository->getAgreeList($type); + return app('json')->success($data); + } + + + /** + * @Author:Qinii + * @Date: 2020/9/15 + * @return mixed + */ + public function getAgree($key) + { + $allow = $this->repository->getAgreeKey(); + if (!in_array($key, $allow)) return app('json')->fail('数据不存在'); + $data = $this->repository->getResult($key); + return app('json')->success($data); + } + + + /** + * @Author:Qinii + * @Date: 2020/9/15 + * @return mixed + */ + public function saveAgree($key) + { + $allow = $this->repository->getAgreeKey(); + if (!in_array($key, $allow)) return app('json')->fail('KEY不存在'); + + $value = $this->request->param('agree'); + $this->repository->save($key, $value); + + if ($key == CacheRepository::USER_PRIVACY) + $this->repository->setUserAgreement($value); + if ($key == CacheRepository::USER_AGREE) + $this->repository->setUserRegister($value); + + return app('json')->success('保存成功'); + } + + /** + * TODO 清除缓存 + * @return \think\response\Json + * @author Qinii + * @day 12/9/21 + */ + public function clearCache() + { + return app('json')->success('清除缓存成功'); + } +} diff --git a/app/controller/admin/system/admin/Admin.php b/app/controller/admin/system/admin/Admin.php new file mode 100644 index 00000000..ae30fa7e --- /dev/null +++ b/app/controller/admin/system/admin/Admin.php @@ -0,0 +1,264 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\admin; + + +use app\common\repositories\system\auth\RoleRepository; +use crmeb\basic\BaseController; +use app\common\repositories\system\admin\AdminRepository; +use app\validate\admin\AdminEditValidate; +use app\validate\admin\AdminValidate; +use Exception; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\response\Json; + +class Admin extends BaseController +{ + protected $repository; + + public function __construct(App $app, AdminRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function getList() + { + $where = $this->request->params(['keyword', 'date', 'status']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function switchStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status == 1 ? 1 : 0]); + return app('json')->success('编辑成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-09 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param int $id + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-09 + */ + public function passwordForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->passwordForm($id))); + } + + /** + * @param AdminValidate $validate + * @return mixed + * @author xaboy + * @day 2020-04-09 + */ + public function create(AdminValidate $validate) + { + $data = $this->request->params(['account', 'pwd', 'phone', 'againPassword', 'real_name', ['roles', []], ['status', 0]]); + $validate->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + unset($data['againPassword']); + if ($this->repository->fieldExists('account', $data['account'])) + return app('json')->fail('账号已存在'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + + $check = app()->make(RoleRepository::class)->checkRole($data['roles'],0); + if (!$check ) { + return app('json')->fail('未开启或者不存在的身份不能添加'); + } + + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + /** + * @param int $id + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function update($id, AdminValidate $validate) + { + $data = $this->request->params(['account', 'real_name', 'phone', ['roles', []], ['status', 0]]); + $validate->isUpdate()->check($data); + if ($this->repository->fieldExists('account', $data['account'], $id)) + return app('json')->fail('账号已存在'); + + $check = app()->make(RoleRepository::class)->checkRole($data['roles'],0); + if (!$check ) { + return app('json')->fail('未开启或者不存在的身份不能添加'); + } + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + /** + * @param int $id + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function password($id, AdminValidate $validate) + { + $data = $this->request->params(['pwd', 'againPassword']); + $validate->isPassword()->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + if (!$this->repository->exists($id)) + return app('json')->fail('管理员不存在'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + unset($data['againPassword']); + $this->repository->update($id, $data); + + return app('json')->success('修改密码成功'); + } + + /** + * 删除 + * @param int $id + * @return Json + * @throws Exception + * @author 张先生 + * @date 2020-03-30 + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_del' => 1]); + return app('json')->success('删除成功'); + } + + /** + * @param AdminEditValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function edit(AdminEditValidate $validate) + { + $data = $this->request->params(['real_name', 'phone']); + $validate->check($data); + $this->repository->update($this->request->adminId(), $data); + return app('json')->success('修改成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function editForm() + { + $adminInfo = $this->request->adminInfo(); + return app('json')->success(formToData($this->repository->editForm(['real_name' => $adminInfo->real_name, 'phone' => $adminInfo->phone]))); + } + + /** + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function editPassword(AdminValidate $validate) + { + $data = $this->request->params(['pwd', 'againPassword']); + $validate->isPassword()->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + unset($data['againPassword']); + $this->repository->update($this->request->adminId(), $data); + + return app('json')->success('修改密码成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function editPasswordForm() + { + return app('json')->success(formToData($this->repository->passwordForm($this->request->adminId(), true))); + } + +} diff --git a/app/controller/admin/system/admin/AdminLog.php b/app/controller/admin/system/admin/AdminLog.php new file mode 100644 index 00000000..238c93ca --- /dev/null +++ b/app/controller/admin/system/admin/AdminLog.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\admin; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\admin\AdminLogRepository; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +class AdminLog extends BaseController +{ + protected $repository; + + public function __construct(App $app, AdminLogRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['section_startTime', 'section_endTime', 'admin_id', 'method', 'date']); + return app('json')->success($this->repository->lst($this->request->merId(), $where, $page, $limit)); + } +} diff --git a/app/controller/admin/system/admin/Login.php b/app/controller/admin/system/admin/Login.php new file mode 100644 index 00000000..e9bf27d0 --- /dev/null +++ b/app/controller/admin/system/admin/Login.php @@ -0,0 +1,118 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\admin; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\admin\AdminRepository; +use app\validate\admin\LoginValidate; +use Gregwar\Captcha\CaptchaBuilder; +use Gregwar\Captcha\PhraseBuilder; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Cache; + +class Login extends BaseController +{ + protected $repository; + + public function __construct(App $app, AdminRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 判断是否需要滑块验证码 + * @return \think\response\Json + * @author Qinii + * @day 2022/10/11 + */ + public function ajCaptchaStatus() + { + $data = $this->request->params(['account']); + $key = 'sys_login_failuree_'.$data['account']; + $numb = (Cache::get($key) ?? 0); + return app('json')->success(['status' => $numb > 2 ]); + } + + + /** + * @param LoginValidate $validate + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-10 + */ + public function login(LoginValidate $validate) + { + $data = $this->request->params(['account', 'password', 'code', 'key',['captchaType', ''], ['captchaVerification', ''],'token']); + $validate->check($data); + //图形验证码废弃 + #$this->repository->checkCode($data['key'], $data['code']); + + $key = 'sys_login_failuree_'.$data['account']; + $numb = Cache::get($key) ?? 0; + if($numb > 2){ + if (!$data['captchaType'] || !$data['captchaVerification']) { + return app('json')->fail('请滑动滑块验证'); + } + try { + aj_captcha_check_two($data['captchaType'], $data['captchaVerification']); + } catch (\Throwable $e) { + return app('json')->fail($e->getMessage()); + } + } + $adminInfo = $this->repository->login($data['account'], $data['password']); + $tokenInfo = $this->repository->createToken($adminInfo); + $admin = $adminInfo->toArray(); + unset($admin['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $admin + ]; + Cache::delete($key); + return app('json')->success($data); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-10 + */ + public function logout() + { + if ($this->request->isLogin()) + $this->repository->clearToken($this->request->token()); + return app('json')->success('退出登录'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-09 + */ + public function getCaptcha() + { + $codeBuilder = new CaptchaBuilder(null, new PhraseBuilder(4)); + $key = $this->repository->createLoginKey($codeBuilder->getPhrase()); + $captcha = $codeBuilder->build()->inline(); + return app('json')->success(compact('key', 'captcha')); + } +} diff --git a/app/controller/admin/system/attachment/Attachment.php b/app/controller/admin/system/attachment/Attachment.php new file mode 100644 index 00000000..ef714575 --- /dev/null +++ b/app/controller/admin/system/attachment/Attachment.php @@ -0,0 +1,188 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\attachment; + + +use app\common\repositories\system\attachment\AttachmentCategoryRepository; +use app\common\repositories\system\attachment\AttachmentRepository; +use crmeb\basic\BaseController; +use crmeb\services\UploadService; +use Exception; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\response\Json; + +/** + * Class Attachment + * @package app\controller\admin\system\attachment + * @author xaboy + * @day 2020-04-16 + */ +class Attachment extends BaseController +{ + /** + * @var AttachmentRepository + */ + protected $repository; + + /** + * @var int + */ + protected $merId; + + /** + * Attachment constructor. + * @param App $app + * @param AttachmentRepository $repository + */ + public function __construct(App $app, AttachmentRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->merId(); + } + + /** + * @param int $id + * @param string $field + * @param AttachmentCategoryRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function image($id, $field, AttachmentCategoryRepository $repository) + { + $file = $this->request->file($field); + $ueditor = $this->request->param('ueditor'); + if (!$file) + return app('json')->fail('请上传图片'); + $file = is_array($file) ? $file[0] : $file; + if ($id) { + if (!$category = $repository->get($id, $this->merId)) + return app('json')->fail('目录不存在'); + $info = [ + 'enname' => $category->attachment_category_enname, + 'id' => $category->attachment_category_id + ]; + } else { + $info = [ + 'enname' => 'def', + 'id' => 0 + ]; + } + validate(["$field|图片" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'jpg,jpeg,png,bmp,gif', + 'fileMime' => 'image/jpeg,image/png,image/gif', + ]])->check([$field => $file]); + + $type = (int)systemConfig('upload_type') ?: 1; + $upload = UploadService::create($type); + $data = $upload->to($info['enname'])->move($field); + if ($data === false) { + return app('json')->fail($upload->getError()); + } + $res = $upload->getUploadInfo(); + $res['dir'] = tidy_url($res['dir']); + $_name = '.' . $file->getOriginalExtension(); + $data = [ + 'attachment_category_id' => $info['id'], + 'attachment_name' => str_replace($_name, '', $file->getOriginalName()), + 'attachment_src' => $res['dir'] + ]; + $this->repository->create($type, $this->merId, $this->request->adminId(), $data); + if ($ueditor) + return response([ + 'state' => 'SUCCESS', + 'url' => $data['attachment_src'], + 'title' => $data['attachment_src'], + 'original' => $data['attachment_src'], + ], 200, [], 'json'); + return app('json')->success(['src' => $data['attachment_src']]); + } + + /** + * 获取列表 + * @return Json + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author 张先生 + * @date 2020-03-27 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([['attachment_category_id', 0],'order','attachment_name']); + $where['user_type'] = $this->merId; + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param AttachmentCategoryRepository $attachmentCategoryRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-16 + */ + public function batchChangeCategory(AttachmentCategoryRepository $attachmentCategoryRepository) + { + [$ids, $attachment_category_id] = $this->request->params([['ids', []], 'attachment_category_id'], true); + if ($attachment_category_id && !$attachmentCategoryRepository->merExists($this->merId, $attachment_category_id)) + return app('json')->fail('分类不存在'); + if (!is_array($ids) || !count($ids)) + return app('json')->fail('请选择要修改分类的附件'); + $this->repository->batchChangeCategory(array_map('intval', $ids), intval($attachment_category_id), $this->merId); + return app('json')->success('图片移动成功'); + } + + /** + * 批量删除 + * + * @return Json + * @throws Exception + * @author 张先生 + * @date 2020-03-30 + */ + public function delete() + { + $ids = (array)$this->request->param('ids', []); + if (!count($ids)) + return app('json')->fail('数据不存在'); + $this->repository->batchDelete($ids, $this->merId); + return app('json')->success('删除成功'); + } + + public function updateForm($id) + { + if(!$this->repository->getWhereCount(['attachment_id' => $id,'user_type' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->form($id,$this->request->merId()))); + } + + public function update($id) + { + $data= $this->request->params(['attachment_name']); + if(!$this->repository->getWhereCount(['attachment_id' => $id,'user_type' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $this->repository->update($id,$data); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/admin/system/attachment/AttachmentCategory.php b/app/controller/admin/system/attachment/AttachmentCategory.php new file mode 100644 index 00000000..186b84f7 --- /dev/null +++ b/app/controller/admin/system/attachment/AttachmentCategory.php @@ -0,0 +1,166 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\attachment; + +use app\common\repositories\system\attachment\AttachmentCategoryRepository; +use app\validate\admin\AttachmentCategoryValidate; +use crmeb\basic\BaseController; +use Exception; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\response\Json; + +/** + * Class AttachmentCategory + * @package app\controller\admin\system\attachment + * @author xaboy + * @day 2020-04-22 + */ +class AttachmentCategory extends BaseController +{ + /** + * @var AttachmentCategoryRepository + */ + protected $repository; + + /** + * @var int + */ + protected $merId; + + /** + * AttachmentCategory constructor. + * @param App $app + * @param AttachmentCategoryRepository $repository + */ + public function __construct(App $app, AttachmentCategoryRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->merId(); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-15 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->merId))); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-15 + */ + public function updateForm($id) + { + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($this->merId, $id))); + } + + /** + * 获取带级别列表 + * @return Json + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author 张先生 + * @date 2020-03-26 + */ + public function getFormatList() + { + $result = $this->repository->getFormatList($this->merId); + return app('json')->success($result); + } + + /** + * @param AttachmentCategoryValidate $validate + * @return mixed + * @author xaboy + * @day 2020-04-15 + */ + public function create(AttachmentCategoryValidate $validate) + { + $data = $this->checkParam($validate); + if ($data['pid'] && !$this->repository->merExists($this->merId, $data['pid'])) + return app('json')->fail('上级分类不存在'); + $data['mer_id'] = $this->merId; + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * 更新 + * @param int $id id + * @param AttachmentCategoryValidate $validate + * @return mixed + * @throws DbException + * @author 张先生 + * @date 2020-03-30 + */ + public function update($id, AttachmentCategoryValidate $validate) + { + $data = $this->checkParam($validate); + if ($data['pid'] && !$this->repository->merExists($this->merId, $data['pid'])) + return app('json')->fail('上级分类不存在'); + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $this->merId, $data); + return app('json')->success('编辑成功'); + } + + /** + * 添加和修改参数验证 + * @param AttachmentCategoryValidate $validate 验证规则 + * @return mixed + * @author 张先生 + * @date 2020-03-30 + */ + private function checkParam(AttachmentCategoryValidate $validate) + { + $data = $this->request->params(['pid', 'attachment_category_name', 'attachment_category_enname', 'sort']); + $data['attachment_category_enname'] = trim($data['attachment_category_enname']) ?: 'def'; + $validate->check($data); + return $data; + } + + /** + * 删除单个 + * @param int $id + * @return Json + * @throws Exception + * @author 张先生 + * @date 2020-03-30 + */ + public function delete($id) + { + if ($this->repository->merFieldExists($this->merId, 'pid', $id)) + return app('json')->fail('存在子级,无法删除'); + $this->repository->delete($id, $this->merId); + return app('json')->success(); + } +} diff --git a/app/controller/admin/system/auth/Menu.php b/app/controller/admin/system/auth/Menu.php new file mode 100644 index 00000000..bfd0995f --- /dev/null +++ b/app/controller/admin/system/auth/Menu.php @@ -0,0 +1,207 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\auth; + +use crmeb\basic\BaseController; +use app\common\repositories\system\auth\MenuRepository; +use app\validate\admin\MenuValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class Menu + * @package app\controller\admin\system\menu + * @author xaboy + * @day 2020-04-08 + */ +class Menu extends BaseController +{ + /** + * @var int + */ + protected $merchant; + + /** + * @var MenuRepository + */ + protected $repository; + + /** + * Menu constructor. + * @param App $app + * @param MenuRepository $repository + */ + public function __construct(App $app, MenuRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merchant = $this->request->param('merchant', 0) == 0 ? 0 : 1; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-08 + */ + public function getList() + { + $data = $this->repository->getList([], $this->merchant); + $data['list'] = formatCategory($data['list'], 'menu_id'); + return app('json')->success($data); + } + + /** + * 创建 + * @param MenuValidate $validate + * @return mixed + * @author 张先生 + * @date 2020-03-30 + */ + public function create(MenuValidate $validate) + { + $data = $this->checkParam($validate); + if (!$data['pid']) $data['pid'] = 0; + if ($data['pid'] && !$this->repository->merExists($data['pid'], $this->merchant)) + return app('json')->fail('父级分类不存在'); + $data['is_mer'] = $this->merchant; + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * 更新 + * @param int $id id + * @param MenuValidate $validate + * @return mixed + * @throws DbException + * @author 张先生 + * @date 2020-03-30 + */ + public function update($id, MenuValidate $validate) + { + $data = $this->checkParam($validate); + if (!$data['pid']) $data['pid'] = 0; + if (!$this->repository->merExists($id, $this->merchant)) + return app('json')->fail('数据不存在'); + if ($data['pid'] && !$this->repository->merExists($data['pid'], $this->merchant)) + return app('json')->fail('父级分类不存在'); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-08 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->menuForm($this->merchant))); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-08 + */ + public function updateForm($id) + { + if (!$this->repository->merExists($id, $this->merchant)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateMenuForm($id, $this->merchant))); + } + + /** + * + * @param MenuValidate $validate 验证规则 + * @return mixed + * @author 张先生 + * @date 2020-03-30 + */ + private function checkParam(MenuValidate $validate) + { + $data = $this->request->params([['pid', 0], 'icon', 'menu_name', 'route', ['params', '[]'], 'sort', ['is_show', 0], ['is_menu', 0]]); + if ($data['is_menu'] != 1) $validate->isAuth(); + $validate->check($data); + return $data; + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-08 + */ + public function delete($id) + { + if ($this->repository->pidExists($id)) + return app('json')->fail('存在下级,无法删除'); + $this->repository->delete($id, $this->merchant); + + return app('json')->success('删除成功'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-10 + */ + public function menus() + { + $pre = '/' . config('admin.' . ($this->merchant ? 'merchant' : 'admin') . '_prefix'); + $menus = $this->request->adminInfo()->level + ? $this->repository->ruleByMenuList($this->request->adminRule(), $this->merchant) + : $this->repository->getValidMenuList($this->merchant); + foreach ($menus as $k => $menu) { + $menu['route'] = $pre . $menu['route']; + $menus[$k] = $menu; + } + return app('json')->success(array_values(array_filter(formatCategory($menus, 'menu_id'), function ($v) { + return 0 == $v['pid']; + }))); + } + /** + * @return mixed + * @author xaboy + * @day 2020-04-10 + */ + public function merchantMenus() + { + $pre = '/' . config('admin.merchant_prefix'); + $merchant = $this->request->merchant(); + $menus = $this->request->adminInfo()->level + ? $this->repository->ruleByMenuList($this->request->adminRule(), $this->merchant) + : ($merchant->type_id ? $this->repository->typesByValidMenuList($merchant->type_id) : $this->repository->getValidMenuList($this->merchant)); + foreach ($menus as $k => $menu) { + $menu['route'] = $pre . $menu['route']; + $menus[$k] = $menu; + } + return app('json')->success(array_values(array_filter(formatCategory($menus, 'menu_id'), function ($v) { + return 0 == $v['pid']; + }))); + } +} diff --git a/app/controller/admin/system/auth/Role.php b/app/controller/admin/system/auth/Role.php new file mode 100644 index 00000000..7d392302 --- /dev/null +++ b/app/controller/admin/system/auth/Role.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\auth; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\auth\RoleRepository; +use app\validate\admin\RoleValidate; +use Exception; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\response\Json; + +class Role extends BaseController +{ + protected $repository; + + public function __construct(App $app, RoleRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-09 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm(false, $id))); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-09 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->search(0, [], $page, $limit)); + } + + /** + * 获取单个 + * @param int $id + * @return Json + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author 张先生 + * @date 2020-03-26 + */ + public function get( $id) + { + $data = $this->repository->get($id); + return app('json')->success($data); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function switchStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status == 1 ? 1 : 0]); + return app('json')->success('编辑成功'); + } + + /** + * 删除单个 + * @param int $id + * @return Json + * @throws Exception + * @author 张先生 + * @date 2020-03-30 + */ + public function delete($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * 创建 + * @param RoleValidate $validate + * @return mixed + * @author 张先生 + * @date 2020-03-30 + */ + public function create(RoleValidate $validate) + { + $data = $this->checkParam($validate); + $data['mer_id'] = 0; + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * 更新 + * @param int $id id + * @param RoleValidate $validate + * @return mixed + * @throws DbException + * @author 张先生 + * @date 2020-03-30 + */ + public function update($id, RoleValidate $validate) + { + $data = $this->checkParam($validate); + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * 添加和修改参数验证 + * @param RoleValidate $validate 验证规则 + * @return mixed + * @author 张先生 + * @date 2020-03-30 + */ + private function checkParam(RoleValidate $validate) + { + $data = $this->request->params(['role_name', ['rules', []], ['status', 0]]); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/system/config/Config.php b/app/controller/admin/system/config/Config.php new file mode 100644 index 00000000..7a8f963b --- /dev/null +++ b/app/controller/admin/system/config/Config.php @@ -0,0 +1,338 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\config; + + +use app\common\repositories\system\CacheRepository; +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigRepository; +use app\validate\admin\ConfigValidate; +use crmeb\basic\BaseController; +use crmeb\services\FileService; +use crmeb\services\UploadService; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Log; + +/** + * Class Config + * @package app\controller\admin\system\config + * @author xaboy + * @day 2020-03-27 + */ +class Config extends BaseController +{ + /** + * @var ConfigRepository + */ + protected $repository; + + /** + * Config constructor. + * @param App $app + * @param ConfigRepository $repository + */ + public function __construct(App $app, ConfigRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function lst() + { + $where = $this->request->params(['keyword', 'config_classify_id', 'user_type']); + [$page, $limit] = $this->getPage(); + $lst = $this->repository->lst($where, $page, $limit); + + return app('json')->success($lst); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function createTable() + { + $form = $this->repository->form(); + return app('json')->success(formToData($form)); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function updateTable($id) + { + if (!$this->repository->exists($id)) app('json')->fail('数据不存在'); + $form = $this->repository->updateForm($id); + return app('json')->success(formToData($form)); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0); + if (!$this->repository->exists($id)) + return app('json')->fail('分类不存在'); + $this->repository->switchStatus($id, $status == 1 ? 1 : 0); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function get($id) + { + $data = $this->repository->get($id); + if (!$data) + return app('json')->fail('配置不存在'); + else + return app('json')->success($data->hidden(['mer_id', 'value'])); + } + + /** + * @param ConfigValidate $validate + * @param ConfigClassifyRepository $configClassifyRepository + * @return mixed + * @author xaboy + * @day 2020-03-27 + */ + public function create(ConfigValidate $validate, ConfigClassifyRepository $configClassifyRepository) + { + $data = $this->request->params(['user_type', 'config_classify_id', 'config_name', 'config_props', 'config_key', 'config_type', 'config_rule', 'required', 'info', 'sort', 'status']); + $validate->check($data); + if (!$configClassifyRepository->exists($data['config_classify_id'])) + return app('json')->fail('配置分类不已存在'); + if ($this->repository->keyExists($data['config_key'])) + return app('json')->fail('配置key已存在'); + + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @param int $id + * @param ConfigValidate $validate + * @param ConfigClassifyRepository $configClassifyRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function update($id, ConfigValidate $validate, ConfigClassifyRepository $configClassifyRepository) + { + $data = $this->request->params(['user_type', 'config_classify_id', 'config_name', 'config_props', 'config_key', 'config_type', 'config_rule', 'required', 'info', 'sort', 'status']); + $validate->check($data); + + if (!$this->repository->exists($id)) + return app('json')->fail('分类不存在'); + if (!$configClassifyRepository->exists($data['config_classify_id'])) + return app('json')->fail('配置分类不已存在'); + if ($this->repository->keyExists($data['config_key'], $id)) + return app('json')->fail('配置key已存在'); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function delete($id) + { + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * @param string $key + * @param ConfigClassifyRepository $configClassifyRepository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-22 + */ + public function form($key, ConfigClassifyRepository $configClassifyRepository) + { + if (!$configClassifyRepository->keyExists($key) || !($configClassfiy = $configClassifyRepository->keyByData($key))) + return app('json')->fail('配置分类不存在'); + if ($configClassifyRepository->existsWhere(['pid' => $configClassfiy->config_classify_id])) + $form = $this->repository->tabForm($configClassfiy, $this->request->merId()); + else + $form = $this->repository->cidByFormRule($configClassfiy, $this->request->merId()); + return app('json')->success(formToData($form)); + } + + public function upload($field) + { + $file = $this->request->file($field); + if (!$file) return app('json')->fail('请上传附件'); + + //ico 图标处理 + if ($file->getOriginalExtension() == 'ico') { + $file->move('public','favicon.ico'); + $res = tidy_url('public/favicon.ico'); + return app('json')->success(['src' => $res]); + } + + $upload = UploadService::create(1); + $data = $upload->to('attach')->validate()->move($field); + if ($data === false) { + return app('json')->fail($upload->getError()); + } + return app('json')->success(['src' => path_to_url($upload->getFileInfo()->filePath)]); + } + + public function uploadWechatForm() + { + return app('json')->success(formToData($this->repository->wechatForm())); + } + + public function uploadAsName() + { + $file = $this->request->file('file'); + validate(["file|文件" => ['fileExt' => 'txt']])->check(['file' => $file]); + if (!$file) return app('json')->fail('请上传附件'); + $res = \think\facade\Filesystem::putFileAs('', $file, $file->getOriginalName()); + if (!$res) return app('json')->fail('上传失败'); + + return app('json')->success(['src' => $res]); + } + + public function uploadWechatSet() + { + $name = $this->request->param('wechat_chekc_file'); + if (!$name || !is_file(public_path() . 'uploads/' . $name)) return app('json')->fail('文件不存在'); + try { + rename(public_path() . 'uploads/' . $name, public_path() . $name); + app()->make(CacheRepository::class)->save('wechat_chekc_file', public_path() . $name, 0); + } catch (\Exception $exception) { + return app('json')->fail('修改失败'); + } + + return app('json')->success('提交成功'); + } + + /** + * 下载小程序 + * @return mixed + */ + public function downloadTemp() + { + $is_live = $this->request->param('is_live', 0); + $is_menu = $this->request->param('is_menu', 0); + if (systemConfig('routine_appId') == '') throw new ValidateException('请先配置小程序appId'); + $code = get_crmeb_version_code(); + $name = md5(time()); + $make = app()->make(CacheRepository::class); + $routine_zip = $make->getResult('routine_zip'); + $path = root_path() . 'extend'; + + if (!is_dir($path . '/download')) { + @mkdir($path . '/download', 0777); + } + + if (!is_dir(public_path() . 'static/download')) { + @mkdir(public_path() . 'static/download', 0777); + } + if (!is_dir($path . '/mp-weixin/' . $code)) { + return app('json')->fail('缺少小程序源文件'); + } + + try { + @unlink(public_path() . 'static/download/' . $routine_zip . '.zip'); + //拷贝源文件 + /** @var FileService $fileService */ + $fileService = app(FileService::class); + + $fileService->copyDir($path . '/mp-weixin/' . $code, $path . '/download'); + //替换appid和名称 + + $this->repository->updateConfigJson(systemConfig('routine_appId'), systemConfig('routine_name'), $path); + //是否开启直播 + if ($is_live == 0 ) { + $this->repository->updateAppJson($path); + } + + $this->repository->updatePlantJson($path, $is_menu); + //是否显示菜单 + if ($is_menu == 0) { + $this->repository->updateRouteJson($path); + } + + //替换url + $this->repository->updateUrl(systemConfig('site_url'), $path); + //压缩文件 + $fileService->addZip( + $path . '/download', + public_path() . 'static/download/' . $name . '.zip', + $path . '/download' + ); + $data['url'] = rtrim(systemConfig('site_url'), '/') . '/static/download/' . $name . '.zip'; + + app()->make(CacheRepository::class)->save('routine_zip', $name); + return app('json')->success($data); + } catch (\Throwable $throwable) { + Log::info($throwable->getMessage()); + return app('json')->fail('生成失败:' . $throwable->getMessage()); + } + } + + public function getRoutineConfig() + { + $data['routine_name'] = systemConfig('routine_name'); + $data['routine_appId'] = systemConfig('routine_appId'); + $data['url'] = 'https://doc.crmeb.com/mer/mer2/4491'; + $data['site_url'] = rtrim(systemConfig('site_url'), '/') . '/pages/index/index'; + return app('json')->success($data); + } +} diff --git a/app/controller/admin/system/config/ConfigClassify.php b/app/controller/admin/system/config/ConfigClassify.php new file mode 100644 index 00000000..84c76a10 --- /dev/null +++ b/app/controller/admin/system/config/ConfigClassify.php @@ -0,0 +1,219 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\config; + + +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigRepository; +use app\validate\admin\ConfigClassifyValidate; +use crmeb\basic\BaseController; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class ConfigClassify + * @package app\controller\admin\system\config + * @author xaboy + * @day 2020-03-27 + */ +class ConfigClassify extends BaseController +{ + /** + * @var ConfigClassifyRepository + */ + private $repository; + + /** + * ConfigClassify constructor. + * @param App $app + * @param ConfigClassifyRepository $repository + */ + public function __construct(App $app, ConfigClassifyRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-31 + */ + public function lst() + { + $where = $this->request->params(['status', 'classify_name']); + $lst = $this->repository->lst($where); + $lst['list'] = formatCategory($lst['list']->toArray(), 'config_classify_id'); + return app('json')->success($lst); + } + + /** + * @param int $pid + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function children($pid) + { + return app('json')->success($this->repository->children($pid)); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function createTable() + { + $form = $this->repository->createForm(); + return app('json')->success(formToData($form)); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-03-31 + */ + public function updateTable($id) + { + if (!$this->repository->exists($id)) app('json')->fail('数据不存在'); + $form = $this->repository->updateForm($id); + return app('json')->success(formToData($form)); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-03-27 + */ + public function options() + { + return app('json')->success($this->repository->options()); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function get($id) + { + $data = $this->repository->get($id); + if (!$data) + return app('json')->fail('分类不存在'); + else + return app('json')->success($data); + + } + + /** + * @param ConfigClassifyValidate $validate + * @return mixed + * @author xaboy + * @day 2020-03-27 + */ + public function create(ConfigClassifyValidate $validate) + { + $data = $this->request->params(['pid', 'classify_name', 'classify_key', 'info', 'status', 'icon', 'sort']); + $validate->check($data); + if ($this->repository->keyExists($data['classify_key'])) + return app('json')->fail('配置分类key已存在'); + if ($data['pid'] && !$this->repository->pidExists($data['pid'])) + return app('json')->fail('上级分类不存在'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @param int $id + * @param ConfigClassifyValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function update($id, ConfigClassifyValidate $validate) + { + $data = $this->request->params(['pid', 'classify_name', 'classify_key', 'info', 'status', 'icon', 'sort']); + $validate->check($data); + + if (!$this->repository->exists($id)) + return app('json')->fail('分类不存在'); + if ($this->repository->keyExists($data['classify_key'], $id)) + return app('json')->fail('配置分类key已存在'); + if ($data['pid'] && !$this->repository->pidExists($data['pid'], $id)) + return app('json')->fail('上级分类不存在'); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0); + if (!$this->repository->exists($id)) + return app('json')->fail('分类不存在'); + $this->repository->switchStatus($id, $status == 1 ? 1 : 0); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @param ConfigRepository $configRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function delete($id, ConfigRepository $configRepository) + { + if ($this->repository->existsChild($id)) + return app('json')->fail('存在子级,无法删除'); + if ($configRepository->classifyIdExists($id)) + return app('json')->fail('分类下存在配置,无法删除'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function getOptions() + { + $options = $this->repository->getOption(); + return app('json')->success(formatCategory($options, 'config_classify_id')); + } +} diff --git a/app/controller/admin/system/config/ConfigOthers.php b/app/controller/admin/system/config/ConfigOthers.php new file mode 100644 index 00000000..1a015a58 --- /dev/null +++ b/app/controller/admin/system/config/ConfigOthers.php @@ -0,0 +1,250 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\config; + +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserRepository; +use crmeb\jobs\ChangeMerchantStatusJob; +use FormBuilder\Factory\Elm; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigRepository as repository; +use app\common\repositories\system\config\ConfigValueRepository; +use think\facade\Db; +use think\facade\Queue; +use think\facade\Route; + +class ConfigOthers extends BaseController +{ + + public $repository; + + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function update() + { + $data = $this->request->params([ + 'extension_status', + 'extension_two_rate', + 'extension_one_rate', + 'extension_self', + 'extension_limit', + 'extension_limit_day', + 'sys_extension_type', + 'lock_brokerage_timer', + 'max_bag_number', + 'promoter_explain', + 'user_extract_min', + 'withdraw_type' + ]); + + if ($data['extension_two_rate'] < 0 || $data['extension_one_rate'] < 0) + return app('json')->fail('比例不能小于0'); + if (bccomp($data['extension_one_rate'], $data['extension_two_rate'], 4) == -1) + return app('json')->fail('一级比例不能小于二级比例'); + if (bccomp(bcadd($data['extension_one_rate'], $data['extension_two_rate'], 3), 1, 3) == 1) + return app('json')->fail('比例之和不能超过1,即100%'); + if (!ctype_digit((string)$data['extension_limit_day']) || $data['extension_limit_day'] <= 0) + return app('json')->fail('分销绑定时间必须大于0'); + + $old = systemConfig(['extension_limit', 'extension_limit_day']); + + if (!$old['extension_limit'] && $data['extension_limit']) { + app()->make(UserRepository::class)->initSpreadLimitDay(intval($data['extension_limit_day'])); + } else if ($old['extension_limit'] && !$data['extension_limit']) { + app()->make(UserRepository::class)->clearSpreadLimitDay(); + } else if ($data['extension_limit_day'] != $old['extension_limit_day'] && $data['extension_limit']) { + app()->make(UserRepository::class)->updateSpreadLimitDay(intval($data['extension_limit_day'] - $old['extension_limit_day'])); + } + + app()->make(ConfigValueRepository::class)->setFormData($data, 0); + + return app('json')->success('修改成功'); + } + + + /** + * TODO 拼团相关配置 + * @return \think\response\Json + * @author Qinii + * @day 4/6/22 + */ + public function getGroupBuying() + { + $data = [ + 'ficti_status' => systemConfig('ficti_status'), + 'group_buying_rate' => systemConfig('group_buying_rate'), + ]; + return app('json')->success($data); + } + + public function setGroupBuying() + { + $data['ficti_status'] = $this->request->param('ficti_status') == 1 ? 1 : 0; + $data['group_buying_rate'] = $this->request->param('group_buying_rate'); + if ($data['group_buying_rate'] < 0 || $data['group_buying_rate'] > 100) + return app('json')->fail('请填写1~100之间的整数'); + app()->make(ConfigValueRepository::class)->setFormData($data, 0); + + return app('json')->success('修改成功'); + } + + public function getProfitsharing() + { + return app('json')->success(array_filter(systemConfig(['extract_maxmum_num', 'extract_minimum_line', 'extract_minimum_num', 'open_wx_combine', 'open_wx_sub_mch', 'mer_lock_time']), function ($val) { + return $val !== ''; + }) + ['open_wx_sub_mch' => 0, 'open_wx_combine' => 0]); + } + + public function setProfitsharing() + { + $data = $this->request->params(['extract_maxmum_num', 'extract_minimum_line', 'extract_minimum_num', 'open_wx_combine', 'open_wx_sub_mch', 'mer_lock_time']); + if ($data['extract_minimum_num'] < $data['extract_minimum_line']) + return app('json')->fail('最小提现额度不能小于最低提现金额'); + if ($data['extract_maxmum_num'] < $data['extract_minimum_num']) + return app('json')->fail('最高提现额度不能小于最小提现额度'); + $config = systemConfig(['open_wx_combine', 'wechat_service_merid', 'wechat_service_key', 'wechat_service_v3key', 'wechat_service_client_cert', 'wechat_service_client_key', 'wechat_service_serial_no']); + $open_wx_combine = $config['open_wx_combine']; + unset($config['open_wx_combine']); + if (($data['open_wx_combine'] || $data['open_wx_sub_mch']) && count(array_filter($config)) < 6) { + return app('json')->fail('请先配置微信服务商相关参数'); + } + Db::transaction(function () use ($data, $open_wx_combine) { + app()->make(ConfigValueRepository::class)->setFormData($data, 0); + if (!$open_wx_combine && $data['open_wx_combine']) { + $column = app()->make(MerchantRepository::class)->search([])->where('sub_mchid', '')->column('mer_id'); + app()->make(MerchantRepository::class)->search([])->where('sub_mchid', '')->save(['mer_state' => 0]); + foreach ($column as $merId) { + Queue::push(ChangeMerchantStatusJob::class, $merId); + } + } + }); + return app('json')->success('修改成功'); + } + + + /** + * 未启用 + * TODO 上传图片水印设置 + * @return \think\response\Json + * @author Qinii + * @day 12/14/21 + */ + public function getImageWaterConfig() + { + $config = [ + 'image_watermark_status', + 'watermark_type', + 'watermark_image', + 'watermark_opacity', + 'watermark_position', + 'watermark_rotate', + 'watermark_text', + 'watermark_text_angle', + 'watermark_text_color', + 'watermark_text_size', + 'watermark_x', + 'watermark_y' + ]; + $formData = systemConfig($config); + $form = Elm::createForm(Route::buildUrl('configOthersWaterSave')->build()); + $form->setRule([ + Elm::radio('image_watermark_status', '是否开启水印') + ->setOptions([ + ['value' => 1, 'label' => '开启'], + ['value' => 0, 'label' => '关闭'], + ])->control([ + [ + 'value' => 1, + 'rule'=> [ + Elm::radio('watermark_type', '水印类型') + ->setOptions([ + ['value' => 1, 'label' => '图片'], + ['value' => 2, 'label' => '文字'], + ]) + ->control([ + [ + 'value' => 1, + 'rule'=> [ + Elm::frameImage('watermark_image', '水印图片', '/' . config('admin.admin_prefix') . '/setting/uploadPicture?field=watermark_image&type=1') + ->value($formData['watermark_image'] ?? '') + ->modal(['modal' => false]) + ->width('896px') + ->height('480px'), + Elm::number('watermark_opacity','水印图片透明度')->required(), + Elm::number('watermark_rotate','水印图片倾斜度')->required(), + ] + ], + [ + 'value' => 2, + 'rule'=> [ + Elm::input('watermark_text', '水印文字')->required(), + Elm::number('watermark_text_size','水印文字大小(单位:px)'), + Elm::color('watermark_text_color','水印字体颜色'), + Elm::number('watermark_text_angle','水印字体旋转角度'), + ] + ], + ]), + Elm::radio('watermark_position','水印位置')->setOptions([ + ['value' => 0, 'label' => '左上'], + ['value' => 1, 'label' => '中上'], + ['value' => 2, 'label' => '右上'], + ['value' => 3, 'label' => '左中'], + ['value' => 4, 'label' => '居中'], + ['value' => 5, 'label' => '中右'], + ['value' => 6, 'label' => '左下'], + ['value' => 7, 'label' => '中下'], + ['value' => 8, 'label' => '右下'], + ]), + Elm::number('watermark_x','水印横坐标偏移量(单位:px)'), + Elm::number('watermark_y','水印纵坐标偏移量(单位:px)'), + ] + ], + ]), + ]); + $form->setTitle('水印配置')->formData($formData); + return app('json')->success(formToData($form)); + } + + /** + * 未启用 + * TODO 保存水印设置信息 + * @return \think\response\Json + * @author Qinii + * @day 12/14/21 + */ + public function setImageWaterConfig() + { + $arr = $this->request->params([ + 'image_watermark_status', + 'watermark_type', + 'watermark_image', + 'watermark_opacity', + 'watermark_position', + 'watermark_rotate', + 'watermark_text', + 'watermark_text_angle', + 'watermark_text_color', + 'watermark_text_size', + 'watermark_x', + 'watermark_y' + ]); + app()->make(ConfigValueRepository::class)->setFormData($arr, 0); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/system/config/ConfigValue.php b/app/controller/admin/system/config/ConfigValue.php new file mode 100644 index 00000000..027c7c16 --- /dev/null +++ b/app/controller/admin/system/config/ConfigValue.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\config; + + +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use crmeb\basic\BaseController; +use think\App; + +/** + * Class ConfigValue + * @package app\controller\admin\system\config + * @author xaboy + * @day 2020-03-27 + */ +class ConfigValue extends BaseController +{ + /** + * @var ConfigClassifyRepository + */ + private $repository; + + /** + * ConfigValue constructor. + * @param App $app + * @param ConfigValueRepository $repository + */ + public function __construct(App $app, ConfigValueRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @param string $key + * @return mixed + * @author xaboy + * @day 2020-04-22 + */ + public function save($key) + { + $formData = $this->request->post(); + if (!count($formData)) return app('json')->fail('保存失败'); + + /** @var ConfigClassifyRepository $make */ + $make = app()->make(ConfigClassifyRepository::class); + if (!($cid = $make->keyById($key))) return app('json')->fail('保存失败'); + $children = array_column($make->children($cid, 'config_classify_id')->toArray(), 'config_classify_id'); + $children[] = $cid; + + $this->repository->save($children, $formData, $this->request->merId()); + return app('json')->success('保存成功'); + } +} diff --git a/app/controller/admin/system/diy/Diy.php b/app/controller/admin/system/diy/Diy.php new file mode 100644 index 00000000..8bd3b30b --- /dev/null +++ b/app/controller/admin/system/diy/Diy.php @@ -0,0 +1,317 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\diy; + +use app\common\repositories\article\ArticleRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\diy\DiyRepository; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class Diy extends BaseController +{ + + protected $repository; + public function __construct(App $app, DiyRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * DIY列表 + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function lst() + { + $where = $this->request->params([ + ['status', ''], + ['type', ''], + ['name', ''], + ['version', ''], + ['is_diy',1] + ]); + $where['mer_id'] = $this->request->merId(); + [$page, $limit] = $this->getPage(); + $data = $this->repository->getSysList($where,$page, $limit); + return app('json')->success($data); + } + + /** + * 保存资源 + * @param int $id + * @return mixed + */ + public function saveData(int $id = 0) + { + $data = $this->request->params([ + ['name', ''], + ['title', ''], + ['value', ''], + ['type', '1'], + ['cover_image', ''], + ['is_show', 0], + ['is_bg_color', 0], + ['is_bg_pic', 0], + ['bg_tab_val', 0], + ['color_picker', ''], + ['bg_pic', ''], + ['is_diy',1], + ]); + $data['mer_id'] = $this->request->merId(); + $value = is_string($data['value']) ? json_decode($data['value'], true) : $data['value']; + $infoDiy = $id ? $this->repository->getWhere(['id' => $id, 'mer_id' => $data['mer_id']]) : []; + if ($infoDiy && $infoDiy['is_default']) + return app('json')->fail('默认模板不能修改'); + if ($infoDiy) { + foreach ($value as $k => $item) { + if ($item['name'] === 'goodList') { + if (isset($item['selectConfig']['list'])) { + unset($item['selectConfig']['list']); + } + if (isset($item['goodsList']['list']) && is_array($item['goodsList']['list'])) { + $item['goodsList']['ids'] = array_column($item['goodsList']['list'], 'product_id'); + unset($item['goodsList']['list']); + } + } elseif ($item['name'] === 'articleList') { + if (isset($item['selectList']['list']) && is_array($item['selectList']['list'])) { + unset($item['selectList']['list']); + } + } elseif ($item['name'] === 'promotionList') { + unset($item['productList']['list']); + } + $value[$k] = $item; + } + $data['value'] = json_encode($value); + } else { + if (isset($value['d_goodList']['selectConfig']['list'])) { + unset($value['d_goodList']['selectConfig']['list']); + } elseif (isset($value['d_goodList']['goodsList']['list'])) { + $limitMax = config('database.page.limitMax', 50); + if (isset($value['d_goodList']['numConfig']['val']) && isset($value['d_goodList']['tabConfig']['tabVal']) && $value['d_goodList']['tabConfig']['tabVal'] == 0 && $value['d_goodList']['numConfig']['val'] > $limitMax) { + return app('json')->fail('您设置得商品个数超出系统限制,最大限制' . $limitMax . '个商品'); + } + $value['d_goodList']['goodsList']['ids'] = array_column($value['d_goodList']['goodsList']['list'], 'product_id'); + unset($value['d_goodList']['goodsList']['list']); + } elseif (isset($value['k_newProduct']['goodsList']['list'])) { + $list = []; + foreach ($value['k_newProduct']['goodsList']['list'] as $item) { + $list[] = [ + 'image' => $item['image'], + 'store_info' => $item['store_info'], + 'store_name' => $item['store_name'], + 'id' => $item['id'], + 'price' => $item['price'], + 'ot_price' => $item['ot_price'], + ]; + } + $value['k_newProduct']['goodsList']['list'] = $list; + } elseif (isset($value['selectList']['list']) && is_array($value['selectList']['list'])) { + unset($value['goodsList']['list']); + } + $data['value'] = json_encode($value, JSON_UNESCAPED_UNICODE); + } + $data['version'] = '1.0'; + return app('json')->success($id ? '修改成功' : '保存成功', + ['id' => $this->repository->saveData($id, $data)] + ); + } + + public function select() + { + $where = ['is_diy' => 0, 'is_del' => 0]; + $data = $this->repository->getOptions($where); + return app('json')->success($data); + } + + /** + * 删除模板 + * @param $id + * @return mixed + */ + public function del($id) + { + $this->repository->del($id,$this->request->merId()); + return app('json')->success('删除成功'); + } + + public function getDiyInfo() + { + return app('json')->success($this->repository->getDiyInfo(0,$this->request->merId())); + } + + /** + * 使用模板 + * @param $id + * @return mixed + */ + public function setStatus($id) + { + $this->repository->setUsed($id,$this->request->merId()); + return app('json')->success('修改成功'); + } + + /** + * 获取一条数据 + * @param int $id + * @return mixed + */ + public function getInfo(int $id) + { + if (!$id) throw new ValidateException('参数错误'); + $info = $this->repository->getWhere([$this->repository->getPk() => $id, 'mer_id' => $this->request->merId()]); + if ($info) { + $info = $info->toArray(); + } else { + throw new ValidateException('模板不存在'); + } + $info['value'] = json_decode($info['value'], true); + if ($info['value']) { + $articleServices = app()->make(ArticleRepository::class); + if ($info['is_diy']) { + foreach ($info['value'] as &$item) { + if ($item['name'] === 'goodList' && isset($item['goodsList']['ids']) && count($item['goodsList']['ids'])) { + $item['goodsList']['list'] = app()->make(SpuRepository::class)->search(['product_ids' => $item['goodsList']['ids']])->select(); + } elseif ($item['name'] === 'articleList') {//文章 + $data = []; + if ($item['selectConfig']['activeValue'] ?? 0) { + $data = $articleServices->search(0,['cid' => $item['selectConfig']['activeValue'] ?? 0], 0, $item['numConfig']['val'] ?? 10); + $data = $data['list']; + } + $item['selectList']['list'] = $data['list'] ?? []; + } elseif ($item['name'] === 'promotionList') {//活动模仿 + $data = []; + if (isset($item['tabConfig']['tabCur']) && $typeArr = $item['tabConfig']['list'][$item['tabConfig']['tabCur']] ?? []) { + $val = $typeArr['link']['activeVal'] ?? 0; + if ($val) { + $data = $this->get_groom_list($val, (int)($item['numConfig']['val'] ?? 0)); + } + } + $item['productList']['list'] = $data; + } + } + } else { + if ($info['value']) { + if (isset($info['value']['d_goodList']['goodsList'])) { + $info['value']['d_goodList']['goodsList']['list'] = []; + } + if (isset($info['value']['d_goodList']['goodsList']['ids']) && count($info['value']['d_goodList']['goodsList']['ids'])) { + $info['value']['d_goodList']['goodsList']['list'] = app()->make(SpuRepository::class)->getApiSearch(['product_ids' => $info['value']['d_goodList']['goodsList']['ids']],1,10); + } + } + } + } + return app('json')->success(compact('info')); + } + + + /** + * 设置模版默认数据 + * @param $id + * @return mixed + */ + public function setDefaultData($id) + { + if (!$id) return app('json')->fail('参数错误'); + + $info = $this->repository->getWhere([$this->repository->getPk() => $id, 'mer_id' => $this->request->merId()]); + if ($info) { + if ($info->is_default) return app('json')->fail('默认模板不能修改'); + $info->default_value = $info->value; + $info->update_time = time(); + $info->save(); + return app('json')->success('设置成功'); + } else { + return app('json')->fail('模板不存在'); + } + } + + /** + * 还原模板数据 + * @param $id + * @return mixed + */ + public function Recovery($id) + { + if (!$id) return app('json')->fail('参数错误'); + $info = $this->repository->getWhere([$this->repository->getPk() => $id, 'mer_id' => $this->request->merId()]); + if ($info) { + if ($info->is_default) return app('json')->fail('默认模板不能修改'); + $info->value = $info->default_value; + $info->update_time = time(); + $info->save(); + return app('json')->success('还原成功'); + } else { + return app('json')->fail('模板不存在'); + } + } + + /** + * 实际获取方法 + * @param $type + * @return array + */ + protected function get_groom_list($type, int $num = 0) + { + $services = app()->make(SpuRepository::class); + $info = []; + [$page, $limit] = $this->getPage(); + + $where['is_gift_bag'] = 0; + $where['order'] = 'star'; + $where['product_type'] = 0; + if ($type == 1) {//TODO 精品推荐 + $where['hot_type'] = 'best'; + $info = $services->getApiSearch($where, $page, $limit, null);//TODO 精品推荐个数 + } else if ($type == 2) {//TODO 热门榜单 + $where['hot_type'] = 'hot'; + $info = $services->getApiSearch($where, $page, $limit, null);//TODO 热门榜单 猜你喜欢 + } else if ($type == 3) {//TODO 首发新品 + $where['hot_type'] = 'new'; + $info = $services->getApiSearch($where, $page, $limit, null);//TODO 首发新品 + } else if ($type == 4) {//TODO 促销单品 + $where['hot_type'] = 'good'; + $info = $services->getApiSearch($where, $page, $limit, null);//TODO 促销单品 + } + return $info; + } + + public function productLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([ + ['store_name',''], + ['order', 'star'], + ['cate_pid',0], + ['star',''], + 'product_type', + 'mer_cate_id' + ]); + $where['is_gift_bag'] = 0; + $where['keyword'] = $where['store_name']; + if ($this->request->merId()) $where['mer_id'] = $this->request->merId(); + $data = app()->make(SpuRepository::class)->getApiSearch($where, $page, $limit, null); + return app('json')->success($data); + } + + public function copy($id) + { + $data = $this->repository->copy($id,$this->request->merId()); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/system/diy/PageCategroy.php b/app/controller/admin/system/diy/PageCategroy.php new file mode 100644 index 00000000..29d40d50 --- /dev/null +++ b/app/controller/admin/system/diy/PageCategroy.php @@ -0,0 +1,104 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\system\diy; + +use app\common\repositories\system\diy\PageCategoryRepository; +use app\common\repositories\system\diy\PageLinkRepository; +use crmeb\basic\BaseController; +use think\App; + +class PageCategroy extends BaseController +{ + + protected $repository; + + public function __construct(App $app, PageCategoryRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * 列表 + * @return mixed + * @author Qinii + */ + public function lst() + { + $where['is_mer'] = $this->request->param('type',0); + return app('json')->success($this->repository->getFormatList($where)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/11 + * @return mixed + */ + public function createForm() + { + $type = $this->request->param('type',0); + return app('json')->success(formToData($this->repository->form(0,$type))); + } + + public function create() + { + $data = $this->request->params([ + 'pid', + 'type', + 'name', + 'status', + 'sort', + 'is_mer', + [ 'level',3], + ]); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $data = $this->request->params([ + 'pid', + 'type', + 'name', + 'status', + 'sort', + 'is_mer' + ]); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + public function options() + { + $type = $this->request->param('type',0); + return app('json')->success($this->repository->getSonCategoryList($type,0)); + } + + + public function switchStatus($id) + { + $status = $this->request->param('status') == 1 ? 1: 0; + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + $this->repository->delete($id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/system/diy/PageLink.php b/app/controller/admin/system/diy/PageLink.php new file mode 100644 index 00000000..308d8dad --- /dev/null +++ b/app/controller/admin/system/diy/PageLink.php @@ -0,0 +1,147 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\diy; + + +use app\common\repositories\article\ArticleRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\diy\DiyRepository; +use app\common\repositories\system\diy\PageLinkRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\controller\admin\AuthController; +use app\services\diy\DiyServices; +use app\common\repositories\system\diy\PageCategoryRepository; +use app\services\diy\PageLinkServices; +use app\services\product\category\StoreCategoryServices; +use crmeb\basic\BaseController; +use think\App; + +/** + * Class PageLink + * @package app\controller\admin\v1\diy + */ +class PageLink extends BaseController +{ + + protected $repository; + public function __construct(App $app, PageLinkRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([['status',1]]); + $where['is_mer'] = $this->request->param('type',0); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function createForm() + { + $isMer = $this->request->param('type',0); + return app('json')->success(formToData($this->repository->form(0, $isMer))); + } + + public function create() + { + $data = $this->request->params([ + 'cate_id', + 'name', + 'url', + 'param', + 'example', + 'status', + 'sort', + ]); + $data['is_mer'] = $this->request->param('type',0); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + $isMer = $this->request->param('type',0); + return app('json')->success(formToData($this->repository->form($id, $isMer))); + } + + public function update($id) + { + if ( !$this->repository->existsWhere(['id' => $id])) + return app('json')->fail('数据不存在'); + $data = $this->request->params([ + 'cate_id', + 'name', + 'url', + 'param', + 'example', + 'status', + 'sort', + ]); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + + /** + * 获取页面链接 + * @param $cate_id + * @return mixed + */ + public function getLinks($id, PageCategoryRepository $pageCategoryServices) + { + if (!$id) return app('json')->fail('缺少参数'); + $category = $pageCategoryServices->get((int)$id); + if (!$category) { + return app('json')->fail('页面分类不存在'); + } + [$page, $limit] = $this->getPage(); + switch ($category['type']) { + case 'special': + $diyServices = app()->make(ArticleRepository::class); + $data = $diyServices->search(0,['status' => 1], $page, $limit); + break; + case 'product_category': + $storeCategoryServices = app()->make(StoreCategoryRepository::class); + $data = $storeCategoryServices->getApiFormatList($this->request->merId(),1); + break; + case 'merchant': + $data = app()->make(MerchantRepository::class)->lst(['mer_state' => 1, 'status' => 1],$page,$limit); + break; + case 'active': + $groupid = $this->request->merId() ? 95 : 94; + $data = app()->make(GroupDataRepository::class)->getGroupDataLst($this->request->merId(), $groupid, $page, $limit); + break; + default: + $data = $this->repository->getLinkList($id,$this->request->merId()); + break; + } + return app('json')->success($data); + } + + /** + * 删除链接 + * @param $id + * @return mixed + */ + public function delete($id) + { + if (!$id) return app('json')->fail('参数错误'); + if ( !$this->repository->existsWhere(['id' => $id])) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功!'); + } + +} diff --git a/app/controller/admin/system/diy/VisualConfig.php b/app/controller/admin/system/diy/VisualConfig.php new file mode 100644 index 00000000..547eebb3 --- /dev/null +++ b/app/controller/admin/system/diy/VisualConfig.php @@ -0,0 +1,40 @@ +success(systemConfig(['mer_location', 'store_street_theme']) + ['mer_location' => 0, 'store_street_theme' => 0]); + } + + public function setStoreStreet() + { + $data = $this->request->params(['mer_location', 'store_street_theme']); + app()->make(ConfigValueRepository::class)->setFormData($data, 0); + return app('json')->success('编辑成功'); + } + + public function userIndex() + { + $my_banner = systemGroupData('my_banner'); + $my_menus = systemGroupData('my_menus'); + $theme = app()->make(DiyRepository::class)->getThemeVar(systemConfig('global_theme')); + return app('json')->success(compact('my_banner', 'my_menus', 'theme')); + } + + public function setUserIndex() + { + $data = $this->request->params(['my_banner', 'my_menus']); + $make = app()->make(GroupDataRepository::class); + $make->setGroupData('my_banner', 0, $data['my_banner']); + $make->setGroupData('my_menus', 0, $data['my_menus']); + return app('json')->success('编辑成功'); + } +} \ No newline at end of file diff --git a/app/controller/admin/system/financial/Financial.php b/app/controller/admin/system/financial/Financial.php new file mode 100644 index 00000000..6ad046cd --- /dev/null +++ b/app/controller/admin/system/financial/Financial.php @@ -0,0 +1,157 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\system\financial; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\system\financial\FinancialRepository; +use crmeb\basic\BaseController; +use crmeb\services\ExcelService; +use think\App; + +class Financial extends BaseController +{ + public $repository; + + public function __construct(App $app, FinancialRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','status','financial_type','financial_status','keyword','is_trader','mer_id']); + $where['type'] = 0; + $data = $this->repository->getAdminList($where,$page,$limit); + return app('json')->success($data); + } + + public function getMarginLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','status','financial_type','financial_status','keyword','is_trader','mer_id']); + $where['type'] = 1; + $data = $this->repository->getAdminList($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function detail($id) + { + $data = $this->repository->detail($id); + return app('json')->success($data); + } + + public function statusForm($id) + { + return app('json')->success(formToData($this->repository->statusForm($id))); + } + + /** + * TODO 审核 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function switchStatus($id) + { + $data = $this->request->params([['status',0], 'refusal']); + $type = $this->request->param('type',0); + $data['status_time'] = date('Y-m-d H:i:s'); + if (!in_array($data['status'], [0,1,-1])) { + return app('json')->fail('审核状态错误'); + } + if (($data['status'] == -1) && empty($data['refusal'])) { + return app('json')->fail('请输入拒绝理由'); + } + $this->repository->switchStatus($id, $type, $data); + return app('json')->success('审核完成'); + } + + public function refundShow($id) + { + return app('json')->success($this->repository->refundShow($id)); + } + + + /** + * TODO 修改凭证 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function update($id) + { + $image = $this->request->param('image'); + if(empty($image)) return app('json')->fail('请上传凭证'); + $res = $this->repository->get($id); + if($res['status'] != 1) return app('json')->success('申请未通过审核'); + $data['image'] = implode(',',$image); + $data['admin_id'] = $this->request->adminId(); + $data['update_time'] = date('Y-m-d H:i:s'); + $data['financial_status'] = 1; + $this->repository->update($id,$data); + return app('json')->success('修改完成'); + } + + public function markForm($id) + { + return app('json')->success(formToData($this->repository->adminMarkForm($id))); + } + + public function markMarginForm($id) + { + return app('json')->success(formToData($this->repository->adminMarginMarkForm($id))); + } + + public function mark($id) + { + $ret = $this->repository->getWhere([$this->repository->getPk() => $id]); + + if(!$ret) return app('json')->fail('数据不存在'); + $data = $this->request->params(['admin_mark']); + $this->repository->update($id,$data); + + return app('json')->success('备注成功'); + } + + /** + * TODO 头部统计 + * @return \think\response\Json + * @author Qinii + * @day 4/22/21 + */ + public function title() + { + $ret = $this->repository->getTitle(); + return app('json')->success($ret); + } + + public function export() + { + $where = $this->request->params(['date', 'status', 'financial_type', 'financial_status', 'keyword', 'is_trader', 'mer_id']); + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->financialLog($where,$page,$limit); + return app('json')->success($data); + } + + +} diff --git a/app/controller/admin/system/groupData/Group.php b/app/controller/admin/system/groupData/Group.php new file mode 100644 index 00000000..c559fdf2 --- /dev/null +++ b/app/controller/admin/system/groupData/Group.php @@ -0,0 +1,166 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\groupData; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\groupData\GroupRepository; +use app\validate\admin\GroupValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class Group + * @package app\controller\admin\system\groupData + * @author xaboy + * @day 2020-03-27 + */ +class Group extends BaseController +{ + /** + * @var GroupRepository + */ + private $repository; + + + /** + * GroupData constructor. + * @param App $app + * @param GroupRepository $repository + */ + public function __construct(App $app, GroupRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-27 + */ + public function get( $id) + { + $data = $this->repository->get($id)->hidden(['create_time', 'sort']); + if (!$data) + return app('json')->fail('数据组不存在'); + else + return app('json')->success($data); + + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-01 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $data = $this->repository->page($page, $limit); + + return app('json')->success($data); + } + + + /** + * @param GroupValidate $validate + * @return mixed + * @author xaboy + * @day 2020-03-27 + */ + public function create(GroupValidate $validate) + { + $data = $this->request->params(['group_name', 'group_info', 'user_type', 'group_key', ['fields', []], ['sort', 0]]); + $validate->check($data); + if ($this->repository->keyExists($data['group_key'])) + return app('json')->fail('数据组key已存在'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-02 + */ + public function createTable() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-02 + */ + public function updateTable($id) + { + if (!$this->repository->exists($id)) app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param int $id + * @param GroupValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function update($id, GroupValidate $validate) + { + $data = $this->request->params(['group_name', 'group_info', 'user_type', 'group_key', ['fields', []], ['sort', 0]]); + $validate->check($data); + + if (!$this->repository->exists($id)) + return app('json')->fail('数据组不存在'); + if ($this->repository->keyExists($data['group_key'], $id)) + return app('json')->fail('数据组key已存在'); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-27 + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据组不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/system/groupData/GroupData.php b/app/controller/admin/system/groupData/GroupData.php new file mode 100644 index 00000000..302447e9 --- /dev/null +++ b/app/controller/admin/system/groupData/GroupData.php @@ -0,0 +1,175 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\groupData; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\groupData\GroupRepository; +use app\validate\admin\GroupDataValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class GroupData + * @package app\controller\admin\system\groupData + * @author xaboy + * @day 2020-03-27 + */ +class GroupData extends BaseController +{ + /** + * @var GroupDataRepository + */ + protected $repository; + + /** + * GroupData constructor. + * @param App $app + * @param GroupDataRepository $repository + */ + public function __construct(App $app, GroupDataRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @param int $groupId + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-03-30 + */ + public function lst($groupId) + { + [$page, $limit] = $this->getPage(); + $lst = $this->repository->getGroupDataLst($this->request->merId(), intval($groupId), $page, $limit); + return app('json')->success($lst); + } + + /** + * @param int $groupId + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-02 + */ + public function createTable($groupId) + { + if (!app()->make(GroupRepository::class)->exists($groupId)) + return app('json')->fail('组合数据不存在!'); + return app('json')->success(formToData($this->repository->form($groupId, null, $this->request->merId()))); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-13 + */ + public function changeStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('status')); + return app('json')->success('修改成功'); + } + + /** + * @param int $groupId + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-02 + */ + public function updateTable($groupId, $id) + { + if (!app()->make(GroupRepository::class)->exists($groupId)) + return app('json')->fail('组合数据不存在!'); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在!'); + return app('json')->success(formToData($this->repository->updateForm($groupId, $this->request->merId(), $id))); + } + + /** + * @param int $groupId + * @param GroupDataValidate $validate + * @param GroupRepository $groupRepository + * @return mixed + * @author xaboy + * @day 2020-04-02 + */ + public function create($groupId, GroupDataValidate $validate, GroupRepository $groupRepository) + { + $data = $this->request->params([['sort', 0], ['status', 0]]); + $validate->check($data); + if (!$groupRepository->exists($groupId)) + return app('json')->fail('数据组不存在'); + $fieldRule = $groupRepository->fields($groupId); + $data['value'] = $this->request->params(array_column($fieldRule, 'field')); + $data['group_id'] = $groupId; + $this->repository->create($this->request->merId(), $data, $fieldRule); + return app('json')->success('添加成功'); + } + + /** + * @param int $groupId + * @param int $id + * @param GroupDataValidate $validate + * @param GroupRepository $groupRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-02 + */ + public function update($groupId, $id, GroupDataValidate $validate, GroupRepository $groupRepository) + { + $data = $this->request->params([['sort', 0], ['status', 0]]); + $validate->check($data); + if (!$groupRepository->exists($groupId)) + return app('json')->fail('数据组不存在'); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在!'); + $fieldRule = $groupRepository->fields($groupId); + $data['value'] = $this->request->params(array_column($fieldRule, 'field')); + $this->repository->merUpdate($this->request->merId(), $id, $data, $fieldRule); + + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-30 + */ + public function delete($id) + { + $this->repository->merDelete($this->request->merId(), $id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/system/merchant/FinancialRecord.php b/app/controller/admin/system/merchant/FinancialRecord.php new file mode 100644 index 00000000..06778659 --- /dev/null +++ b/app/controller/admin/system/merchant/FinancialRecord.php @@ -0,0 +1,153 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use crmeb\basic\BaseController; +use crmeb\services\ExcelService; +use think\App; + +class FinancialRecord extends BaseController +{ + protected $repository; + + public function __construct(App $app, FinancialRecordRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'date', 'mer_id']); + $merId = $this->request->merId(); + if ($merId) { + $where['mer_id'] = $merId; + $where['financial_type'] = ['order', 'mer_accoubts', 'brokerage_one', 'brokerage_two', 'refund_brokerage_one', 'refund_brokerage_two', 'refund_order','order_platform_coupon','order_svip_coupon']; + } else { + $where['financial_type'] = ['order', 'sys_accoubts', 'brokerage_one', 'brokerage_two', 'refund_brokerage_one', 'refund_brokerage_two', 'refund_order','order_platform_coupon','order_svip_coupon']; + } + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function export() + { + $where = $this->request->params(['keyword', 'date', 'mer_id']); + $merId = $this->request->merId(); + if ($merId) { + $where['mer_id'] = $merId; + $where['financial_type'] = ['order', 'mer_accoubts', 'brokerage_one', 'brokerage_two', 'refund_brokerage_one', 'refund_brokerage_two', 'refund_order','order_platform_coupon','order_svip_coupon']; + } else { + $where['financial_type'] = ['order', 'sys_accoubts', 'brokerage_one', 'brokerage_two', 'refund_brokerage_one', 'refund_brokerage_two', 'refund_order','order_platform_coupon','order_svip_coupon']; + } + + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->financial($where,$page,$limit); + return app('json')->success($data); + } + + + /** + * TODO 头部统计 + * @return \think\response\Json + * @author Qinii + * @day 3/23/21 + */ + public function getTitle() + { + $where = $this->request->params(['date']); + $where['is_mer'] = $this->request->merId() ?? 0 ; + if($where['is_mer'] == 0){ + $data = $this->repository->getAdminTitle($where); + }else{ + $data = $this->repository->getMerchantTitle($where); + } + return app('json')->success($data); + } + + + /** + * TODO 列表 + * @return \think\response\Json + * @author Qinii + * @day 3/23/21 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([['type',1],'date']); + $where['is_mer'] = $this->request->merId() ?? 0 ; + $data = $this->repository->getAdminList($where,$page, $limit); + return app('json')->success($data); + } + + + /** + * TODO 详情 + * @param $type + * @return \think\response\Json + * @author Qinii + * @day 3/23/21 + */ + public function detail($type) + { + $date = $this->request->param('date'); + $where['date'] = empty($date) ? date('Y-m-d',time()) : $date ; + $where['is_mer'] = $this->request->merId() ?? 0 ; + if($this->request->merId()){ + $data = $this->repository->merDetail($type,$where); + }else{ + $data = $this->repository->adminDetail($type,$where); + } + + return app('json')->success($data); + } + + /** + * TODO 导出文件 + * @param $type + * @author Qinii + * @day 3/25/21 + */ + public function exportDetail($type) + { + [$page, $limit] = $this->getPage(); + $date = $this->request->param('date'); + $where['date'] = empty($date) ? date('Y-m-d',time()) : $date ; + $where['type'] = $type; + $where['is_mer'] = $this->request->merId() ?? 0 ; + $data = app()->make(ExcelService::class)->exportFinancial($where,$page,$limit); +// app()->make(ExcelRepository::class)->create($where, $this->request->adminId(), 'exportFinancial',$where['is_mer']); + return app('json')->success($data); + } + + /** + * TODO 流水统计 + * @return \think\response\Json + * @author Qinii + * @day 5/7/21 + */ + public function title() + { + $where = $this->request->params(['date']); + +// $data = $this->repository->getFiniancialTitle($this->request->merId(),$where); + $data = []; + return app('json')->success($data); + } + +} diff --git a/app/controller/admin/system/merchant/Merchant.php b/app/controller/admin/system/merchant/Merchant.php new file mode 100644 index 00000000..7945288a --- /dev/null +++ b/app/controller/admin/system/merchant/Merchant.php @@ -0,0 +1,311 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + + +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\system\merchant\MerchantTypeRepository; +use app\common\repositories\user\UserBillRepository; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\admin\MerchantValidate; +use crmeb\jobs\ChangeMerchantStatusJob; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; +use think\facade\Queue; + +/** + * Class Merchant + * @package app\controller\admin\system\merchant + * @author xaboy + * @day 2020-04-16 + */ +class Merchant extends BaseController +{ + /** + * @var MerchantRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param MerchantRepository $repository + */ + public function __construct(App $app, MerchantRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function count() + { + $where = $this->request->params(['keyword', 'date', 'status', 'statusTag', 'is_trader', 'category_id', 'type_id']); + return app('json')->success($this->repository->count($where)); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'date', 'status', 'statusTag', 'is_trader', 'category_id', 'type_id']); + return app('json')->success($this->repository->lst($where, $page, $limit)); + } + + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-16 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param MerchantValidate $validate + * @param MerchantCategoryRepository $merchantCategoryRepository + * @param MerchantAdminRepository $adminRepository + * @return mixed + * @author xaboy + * @day 2020/7/2 + */ + public function create(MerchantValidate $validate) + { + $data = $this->checkParam($validate); + $this->repository->createMerchant($data); + return app('json')->success('添加成功'); + } + + + /** + * @param int $id + * @return mixed + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->updateForm($id)); +// return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param int $id + * @param MerchantValidate $validate + * @param MerchantCategoryRepository $merchantCategoryRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function update($id, MerchantValidate $validate, MerchantCategoryRepository $merchantCategoryRepository) + { + $data = $this->checkParam($validate, true); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($this->repository->fieldExists('mer_name', $data['mer_name'], $id)) + return app('json')->fail('商户名已存在'); + if ($data['mer_phone'] && isPhone($data['mer_phone'])) + return app('json')->fail('请输入正确的手机号'); + if (!$data['category_id'] || !$merchantCategoryRepository->exists($data['category_id'])) + return app('json')->fail('商户分类不存在'); + + unset($data['mer_account'], $data['mer_password']); + $margin = $this->repository->checkMargin($id, $data['type_id']); + $data['margin'] = $margin['margin']; + $data['is_margin'] = $margin['is_margin']; + $datas=$data; + unset($datas['area_id'],$datas['street_id'],$datas['village_id']); + $this->repository->update($id, $datas); + $adds=Db::name('merchant_address')->where('mer_id',$id)->find(); + if($adds){ + $adds1=['area_id'=>$data['area_id'],'street_id'=>$data['street_id'],'village_id'=>$data['village_id']]; + Db::name('merchant_address')->where('mer_id',$id)->update($adds1); + }else{ + $adds1=['mer_id'=>$id,'area_id'=>$data['area_id'],'street_id'=>$data['street_id'],'village_id'=>$data['village_id']]; + Db::name('merchant_address')->insert($adds1); + } + return app('json')->success('编辑成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-17 + */ + public function delete($id) + { + if (!$merchant = $this->repository->get(intval($id))) + return app('json')->fail('数据不存在'); + if ($merchant->status) + return app('json')->fail('请先关闭该商户'); + $this->repository->delete($id); + return app('json')->success('编辑成功'); + } + + /** + * @param MerchantValidate $validate + * @param bool $isUpdate + * @return array + * @author xaboy + * @day 2020-04-17 + */ + public function checkParam(MerchantValidate $validate, $isUpdate = false) + { + $data = $this->request->params([['area_id',0],['street_id',0],['village_id',0],['category_id', 0], ['type_id', 0], 'mer_name', 'commission_rate', 'real_name', 'mer_phone', 'mer_keyword', 'mer_address', 'mark', ['sort', 0], ['status', 0], ['is_audit', 0], ['is_best', 0], ['is_bro_goods', 0], ['is_bro_room', 0], ['is_trader', 0],'sub_mchid']); + if (!$isUpdate) { + $data += $this->request->params(['mer_account', 'mer_password']); + }else { + $validate->isUpdate(); + unset($data['status']); + } + $validate->check($data); + return $data; + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchStatus($id) + { + $is_best = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('is_best')); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchClose($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('status')); + Queue::push(ChangeMerchantStatusJob::class, $id); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @param MerchantAdminRepository $adminRepository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/7/7 + */ + public function login($id, MerchantAdminRepository $adminRepository) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $adminInfo = $adminRepository->merIdByAdmin($id); + $tokenInfo = $adminRepository->createToken($adminInfo); + $admin = $adminInfo->toArray(); + unset($admin['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $admin, + 'url' => '/' . config('admin.merchant_prefix') + ]; + + return app('json')->success($data); + } + + /** + * TODO 修改复制次数表单 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function changeCopyNumForm($id) + { + return app('json')->success(formToData($this->repository->copyForm($id))); + } + + /** + * TODO 修改复制次数 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function changeCopyNum($id) + { + $data = $this->request->params(['type', 'num']); + $num = $data['num']; + if ($num <= 0) return app('json')->fail('次数必须为正整数'); + if ($data['type'] == 2) { + $mer_num = $this->repository->getCopyNum($id); + if (($mer_num - $num) < 0) return app('json')->fail('剩余次数不足'); + $num = '-' . $data['num']; + } + $arr = [ + 'type' => 'sys', + 'num' => $num, + 'message' => '平台修改「' . $this->request->adminId() . '」', + ]; + app()->make(ProductCopyRepository::class)->add($arr, $id); + return app('json')->success('修改成功'); + } + + /** + * TODO 清理删除的商户内容 + * @return \think\response\Json + * @author Qinii + * @day 5/15/21 + */ + public function clearRedundancy() + { + $this->repository->clearRedundancy(); + return app('json')->success('清除完成'); + } +} diff --git a/app/controller/admin/system/merchant/Merchant.php.bak b/app/controller/admin/system/merchant/Merchant.php.bak new file mode 100644 index 00000000..2c901672 --- /dev/null +++ b/app/controller/admin/system/merchant/Merchant.php.bak @@ -0,0 +1,300 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + + +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\system\merchant\MerchantTypeRepository; +use app\common\repositories\user\UserBillRepository; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\admin\MerchantValidate; +use crmeb\jobs\ChangeMerchantStatusJob; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Queue; + +/** + * Class Merchant + * @package app\controller\admin\system\merchant + * @author xaboy + * @day 2020-04-16 + */ +class Merchant extends BaseController +{ + /** + * @var MerchantRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param MerchantRepository $repository + */ + public function __construct(App $app, MerchantRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function count() + { + $where = $this->request->params(['keyword', 'date', 'status', 'statusTag', 'is_trader', 'category_id', 'type_id']); + return app('json')->success($this->repository->count($where)); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'date', 'status', 'statusTag', 'is_trader', 'category_id', 'type_id']); + return app('json')->success($this->repository->lst($where, $page, $limit)); + } + + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-16 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param MerchantValidate $validate + * @param MerchantCategoryRepository $merchantCategoryRepository + * @param MerchantAdminRepository $adminRepository + * @return mixed + * @author xaboy + * @day 2020/7/2 + */ + public function create(MerchantValidate $validate) + { + $data = $this->checkParam($validate); + $this->repository->createMerchant($data); + return app('json')->success('添加成功'); + } + + + /** + * @param int $id + * @return mixed + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-16 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param int $id + * @param MerchantValidate $validate + * @param MerchantCategoryRepository $merchantCategoryRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function update($id, MerchantValidate $validate, MerchantCategoryRepository $merchantCategoryRepository) + { + $data = $this->checkParam($validate, true); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($this->repository->fieldExists('mer_name', $data['mer_name'], $id)) + return app('json')->fail('商户名已存在'); + if ($data['mer_phone'] && isPhone($data['mer_phone'])) + return app('json')->fail('请输入正确的手机号'); + if (!$data['category_id'] || !$merchantCategoryRepository->exists($data['category_id'])) + return app('json')->fail('商户分类不存在'); + + unset($data['mer_account'], $data['mer_password']); + $margin = $this->repository->checkMargin($id, $data['type_id']); + $data['margin'] = $margin['margin']; + $data['is_margin'] = $margin['is_margin']; + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-17 + */ + public function delete($id) + { + if (!$merchant = $this->repository->get(intval($id))) + return app('json')->fail('数据不存在'); + if ($merchant->status) + return app('json')->fail('请先关闭该商户'); + $this->repository->delete($id); + return app('json')->success('编辑成功'); + } + + /** + * @param MerchantValidate $validate + * @param bool $isUpdate + * @return array + * @author xaboy + * @day 2020-04-17 + */ + public function checkParam(MerchantValidate $validate, $isUpdate = false) + { + $data = $this->request->params([['category_id', 0], ['type_id', 0], 'mer_name', 'commission_rate', 'real_name', 'mer_phone', 'mer_keyword', 'mer_address', 'mark', ['sort', 0], ['status', 0], ['is_audit', 0], ['is_best', 0], ['is_bro_goods', 0], ['is_bro_room', 0], ['is_trader', 0],'sub_mchid']); + if (!$isUpdate) { + $data += $this->request->params(['mer_account', 'mer_password']); + }else { + $validate->isUpdate(); + unset($data['status']); + } + $validate->check($data); + return $data; + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchStatus($id) + { + $is_best = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('is_best')); + return app('json')->success('修改成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-03-31 + */ + public function switchClose($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('status')); + Queue::push(ChangeMerchantStatusJob::class, $id); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @param MerchantAdminRepository $adminRepository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/7/7 + */ + public function login($id, MerchantAdminRepository $adminRepository) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $adminInfo = $adminRepository->merIdByAdmin($id); + $tokenInfo = $adminRepository->createToken($adminInfo); + $admin = $adminInfo->toArray(); + unset($admin['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $admin, + 'url' => '/' . config('admin.merchant_prefix') + ]; + + return app('json')->success($data); + } + + /** + * TODO 修改复制次数表单 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function changeCopyNumForm($id) + { + return app('json')->success(formToData($this->repository->copyForm($id))); + } + + /** + * TODO 修改复制次数 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function changeCopyNum($id) + { + $data = $this->request->params(['type', 'num']); + $num = $data['num']; + if ($num <= 0) return app('json')->fail('次数必须为正整数'); + if ($data['type'] == 2) { + $mer_num = $this->repository->getCopyNum($id); + if (($mer_num - $num) < 0) return app('json')->fail('剩余次数不足'); + $num = '-' . $data['num']; + } + $arr = [ + 'type' => 'sys', + 'num' => $num, + 'message' => '平台修改「' . $this->request->adminId() . '」', + ]; + app()->make(ProductCopyRepository::class)->add($arr, $id); + return app('json')->success('修改成功'); + } + + /** + * TODO 清理删除的商户内容 + * @return \think\response\Json + * @author Qinii + * @day 5/15/21 + */ + public function clearRedundancy() + { + $this->repository->clearRedundancy(); + return app('json')->success('清除完成'); + } +} diff --git a/app/controller/admin/system/merchant/MerchantAdmin.php b/app/controller/admin/system/merchant/MerchantAdmin.php new file mode 100644 index 00000000..4d71444b --- /dev/null +++ b/app/controller/admin/system/merchant/MerchantAdmin.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\validate\admin\AdminValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DbException; + +/** + * Class MerchantAdmin + * @package app\controller\admin\system\merchant + * @author xaboy + * @day 2020-04-17 + */ +class MerchantAdmin extends BaseController +{ + /** + * @var MerchantAdminRepository + */ + protected $repository; + + /** + * MerchantAdmin constructor. + * @param App $app + * @param MerchantAdminRepository $repository + */ + public function __construct(App $app, MerchantAdminRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @param int $id + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-17 + */ + public function passwordForm($id) + { + return app('json')->success(formToData($this->repository->passwordForm($id, 1))); + } + + + /** + * @param int $id + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-17 + */ + public function password($id, AdminValidate $validate) + { + $data = $this->request->params(['pwd', 'againPassword']); + $validate->isPassword()->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + $adminId = $this->repository->merchantIdByTopAdminId($id); + if (!$adminId) + return app('json')->fail('商户不存在'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + unset($data['againPassword']); + $this->repository->update($adminId, $data); + + return app('json')->success('修改密码成功'); + } +} diff --git a/app/controller/admin/system/merchant/MerchantApplyments.php b/app/controller/admin/system/merchant/MerchantApplyments.php new file mode 100644 index 00000000..9fc71ddd --- /dev/null +++ b/app/controller/admin/system/merchant/MerchantApplyments.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + +use app\common\repositories\system\CacheRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantApplymentsRepository; + +class MerchantApplyments extends BaseController +{ + protected $repository; + + /** + * MerchantApplyments constructor. + * @param App $app + * @param MerchantApplymentsRepository $repository + */ + public function __construct(App $app, MerchantApplymentsRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['mer_name','status','date','mer_applyments_id','out_request_no','applyment_id','mer_id']); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function detail($id) + { + $data = $this->repository->detail($id); + if(empty($data)) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function switchWithStatus($id) + { + $data = $this->request->params(['status','message']); + + if(!in_array($data['status'],[0,-1,10])) return app('json')->fail('参数错误'); + if($data['status'] == -1 && !$data['message'] ) return app('json')->fail('驳回理由为空'); + $this->repository->switchWithStatus($id,$data); + return app('json')->success('审核成功'); + } + + public function getMerchant($id) + { + $data = $this->repository->getMerchant($id); + return app('json')->success($data); + } + + public function markForm($id) + { + return app('json')->success(formToData($this->repository->markForm($id))); + } + + public function mark($id) + { + if(!$this->repository->get($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['mark' => $this->request->param('mark','')]); + + return app('json')->success('备注成功'); + } + +} diff --git a/app/controller/admin/system/merchant/MerchantCategory.php b/app/controller/admin/system/merchant/MerchantCategory.php new file mode 100644 index 00000000..a66c7e84 --- /dev/null +++ b/app/controller/admin/system/merchant/MerchantCategory.php @@ -0,0 +1,161 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\admin\MerchantCategoryValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class MerchantCategory + * @package app\controller\admin\system\merchant + * @author xaboy + * @day 2020-05-06 + */ +class MerchantCategory extends BaseController +{ + /** + * @var MerchantCategoryRepository + */ + protected $repository; + + /** + * MerchantCategory constructor. + * @param App $app + * @param MerchantCategoryRepository $repository + */ + public function __construct(App $app, MerchantCategoryRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList([], $page, $limit)); + } + + public function getOptions() + { + return app('json')->success($this->repository->allOptions()); + } + + /** + * @param MerchantCategoryValidate $validate + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function create(MerchantCategoryValidate $validate) + { + $data = $this->checkParams($validate); + $data['commission_rate'] = bcdiv($data['commission_rate'], 100, 4); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-06 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + + /** + * @param $id + * @param MerchantCategoryValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function update($id, MerchantCategoryValidate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $data['commission_rate'] = bcdiv($data['commission_rate'], 100, 4); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-06 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param $id + * @param MerchantRepository $merchantRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function delete($id, MerchantRepository $merchantRepository) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($merchantRepository->fieldExists('category_id', $id)) + return app('json')->fail('存在商户,无法删除'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * @param MerchantCategoryValidate $validate + * @return array + * @author xaboy + * @day 2020-05-06 + */ + public function checkParams(MerchantCategoryValidate $validate) + { + $data = $this->request->params(['category_name', ['commission_rate', 0]]); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/system/merchant/MerchantIntention.php b/app/controller/admin/system/merchant/MerchantIntention.php new file mode 100644 index 00000000..ef2222bf --- /dev/null +++ b/app/controller/admin/system/merchant/MerchantIntention.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\system\CacheRepository; +use crmeb\services\ExcelService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantIntentionRepository; + +class MerchantIntention extends BaseController +{ + protected $repository; + + /** + * MerchantIntention constructor. + * @param App $app + * @param MerchantIntentionRepository $repository + */ + public function __construct(App $app, MerchantIntentionRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['mer_name', 'status', 'date', 'keyword', 'mer_intention_id', 'category_id', 'type_id']); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function form($id) + { + if (!$this->repository->getWhereCount(['mer_intention_id' => $id, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->markForm($id))); + } + + public function statusForm($id) + { + if (!$this->repository->getWhereCount(['mer_intention_id' => $id, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->statusForm($id))); + } + + public function mark($id) + { + if (!$this->repository->getWhereCount(['mer_intention_id' => $id, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + $data = $this->request->param('mark'); + $this->repository->update($id, ['mark' => $data]); + return app('json')->success('修改成功'); + } + + public function switchStatus($id) + { + if (!$this->repository->getWhereCount(['mer_intention_id' => $id, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['status', 'fail_msg', 'create_mer']); + $data['status'] = $data['status'] == 1 ? 1 : 2; + $this->repository->updateStatus($id, $data); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->getWhereCount(['mer_intention_id' => $id, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_del' => 1]); + return app('json')->success('删除成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/9/15 + * @return mixed + */ + public function saveAgree() + { + $agree = $this->request->param('agree'); + app()->make(CacheRepository::class)->save('sys_intention_agree', $agree); + return app('json')->success('保存成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/9/15 + * @return mixed + */ + public function getAgree() + { + $make = app()->make(CacheRepository::class); + return app('json')->success(['sys_intention_agree' => $make->getResult('sys_intention_agree')]); + } + + public function excel() + { + $where = $this->request->params(['mer_name', 'status', 'date', 'keyword', 'mer_intention_id', 'category_id', 'type_id']); + + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->intention($where,$page,$limit); + return app('json')->success($data); + + } + +} diff --git a/app/controller/admin/system/merchant/MerchantMargin.php b/app/controller/admin/system/merchant/MerchantMargin.php new file mode 100644 index 00000000..f10a0fb6 --- /dev/null +++ b/app/controller/admin/system/merchant/MerchantMargin.php @@ -0,0 +1,77 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\common\repositories\user\UserBillRepository; +use crmeb\basic\BaseController; +use think\App; + +class MerchantMargin extends BaseController +{ + + /** + * MerchantMargin constructor. + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + } + + /** + * TODO + * @param ServeOrderRepository $orderRepository + * @return \think\response\Json + * @author Qinii + * @day 1/26/22 + */ + public function lst(ServeOrderRepository $orderRepository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','keyword','is_trader','category_id','type_id']); + $where['type'] = 10; + $data = $orderRepository->getList($where, $page, $limit); + return app('json')->success($data); + } + + public function getMarginLst($id) + { + [$page, $limit] = $this->getPage(); + $where = [ + 'mer_id' => $id, + 'category' => 'mer_margin' + ]; + $data = app()->make(UserBillRepository::class)->getLst($where, $page, $limit); + return app('json')->success($data); + } + + public function setMarginForm($id) + { + $data = app()->make(MerchantRepository::class)->setMarginForm($id); + return app('json')->success(formToData($data)); + } + + public function setMargin() + { + $data = $this->request->params(['mer_id','number',['type','mer_margin'],'mark']); + $data['title'] = '保证金扣除'; + if ($data['number'] < 0) + return app('json')->fail('扣除金额不能小于0'); + app()->make(MerchantRepository::class)->setMargin($data); + return app('json')->success('扣除保证金成功'); + } + +} diff --git a/app/controller/admin/system/merchant/MerchantType.php b/app/controller/admin/system/merchant/MerchantType.php new file mode 100644 index 00000000..5d559878 --- /dev/null +++ b/app/controller/admin/system/merchant/MerchantType.php @@ -0,0 +1,104 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\merchant; + + +use app\common\repositories\system\auth\MenuRepository; +use app\common\repositories\system\merchant\MerchantTypeRepository; +use app\validate\admin\MerchantTypeValidate; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class MerchantType extends BaseController +{ + protected $repository; + + public function __construct(App $app, MerchantTypeRepository $repository) + { + parent::__construct($app); + + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + + return app('json')->success($this->repository->getList($page, $limit)); + } + + public function options() + { + return app('json')->success($this->repository->getOptions()); + } + + public function create() + { + $this->repository->create($this->getValidParams()); + return app('json')->success('添加成功'); + } + + public function update($id) + { + if (!$this->repository->exists($id)) { + return app('json')->fail('数据不存在'); + } + $this->repository->update($id, $this->getValidParams()); + return app('json')->success('修改成功'); + } + public function detail($id) + { + $data = $this->repository->detail($id); + return app('json')->success($data); + } + + public function markForm($id) + { + return app('json')->success(formToData($this->repository->markForm($id))); + } + + public function mark($id) + { + $this->repository->mark($id, $this->request->params(['mark'])); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->exists($id)) { + return app('json')->fail('数据不存在'); + } + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function mer_auth() + { + $options = app()->make(MenuRepository::class)->getAllOptions(1); + return app('json')->success(formatTree($options, 'menu_name')); + } + + protected function getValidParams() + { + $data = $this->request->params(['type_name', 'type_info', 'is_margin', 'margin', 'auth', 'description']); + $validate = app()->make(MerchantTypeValidate::class); + $validate->check($data); + if ($data['is_margin'] == 1) { + if ($data['margin'] <= 0) throw new ValidateException('保证金必须大于0'); + } else { + $data['margin'] = 0; + } + return $data; + } +} diff --git a/app/controller/admin/system/notice/SystemNotice.php b/app/controller/admin/system/notice/SystemNotice.php new file mode 100644 index 00000000..a8733e34 --- /dev/null +++ b/app/controller/admin/system/notice/SystemNotice.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\notice; + + +use app\common\repositories\system\notice\SystemNoticeRepository; +use app\validate\admin\SystemNoticeValidate; +use crmeb\basic\BaseController; +use think\App; + +/** + * Class SystemNotice + * @package app\controller\merchant\system\notice + * @author xaboy + * @day 2020/11/6 + */ +class SystemNotice extends BaseController +{ + /** + * @var SystemNoticeRepository + */ + protected $repository; + + /** + * SystemNotice constructor. + * @param App $app + * @param SystemNoticeRepository $repository + */ + public function __construct(App $app, SystemNoticeRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return \think\response\Json + * @author xaboy + * @day 2020/11/6 + */ + public function lst() + { + $where = $this->request->params(['keyword', 'date']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param SystemNoticeValidate $validate + * @return \think\response\Json + * @author xaboy + * @day 2020/11/6 + */ + public function create(SystemNoticeValidate $validate) + { + $data = $this->request->params(['type', 'mer_id', 'is_trader', 'category_id', 'notice_title', 'notice_content']); + $validate->check($data); + $this->repository->create($data, $this->request->adminId()); + return app('json')->success('发布成功'); + } + +} diff --git a/app/controller/admin/system/notice/SystemNoticeConfig.php b/app/controller/admin/system/notice/SystemNoticeConfig.php new file mode 100644 index 00000000..42bb06eb --- /dev/null +++ b/app/controller/admin/system/notice/SystemNoticeConfig.php @@ -0,0 +1,150 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\notice; + +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\validate\admin\SystemNoticeConfigValidate; +use crmeb\basic\BaseController; +use think\App; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; + +class SystemNoticeConfig extends BaseController +{ + /** + * @var CommunityTopicRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, SystemNoticeConfigRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + $where = $this->request->params(['keyword','type']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 10/26/21 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null))); + } + + public function create() + { + $data = $this->checkParams(); + $data['notice_key'] = trim($data['notice_key']); + if ($this->repository->fieldExists('notice_key', $data['notice_key'],null)) + return app('json')->fail('通知键名称重复'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $data = $this->checkParams(); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($this->repository->fieldExists('notice_key', $data['notice_key'],$id)) + return app('json')->fail('通知键名称重复'); + $this->repository->update($id,$data); + + return app('json')->success('编辑成功'); + } + + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['is_del' => 1]); + return app('json')->success('删除成功'); + } + + + public function checkParams() + { + $data = $this->request->params(['notice_title','notice_key','notice_info','notice_sys','notice_wechat','notice_routine','notice_sms','type']); + app()->make(SystemNoticeConfigValidate::class)->check($data); + return $data; + } + + public function getOptions() + { + return app('json')->success($this->repository->options()); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + $key = $this->request->param('key',''); + + if (!in_array($key,['notice_sys','notice_wechat','notice_routine','notice_sms'])) + return app('json')->fail('参数有误'); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + + $this->repository->swithStatus($id,$key, $status); + return app('json')->success('修改成功'); + } + + public function getTemplateId($id) + { + $data = $this->repository->changeForm($id); + return app('json')->success(formToData($data)); + } + + public function setTemplateId($id){ + $params = $this->request->params(['sms_tempid','sms_ali_tempid','routine_tempid','wechat_tempid',['notice_routine',-1],['notice_wechat',-1],['notice_sms',-1]]); + foreach ($params as $k => $v) { + if(!empty($v)) { + $data[$k] = $v; + } + } + $this->repository->save($id,$data); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/admin/system/safety/Database.php b/app/controller/admin/system/safety/Database.php new file mode 100644 index 00000000..be737bc2 --- /dev/null +++ b/app/controller/admin/system/safety/Database.php @@ -0,0 +1,157 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\safety; + +use crmeb\exceptions\UploadFailException; +use crmeb\services\MysqlBackupService; +use think\App; +use crmeb\basic\BaseController; +use think\facade\Db; +use think\facade\Env; + +class Database extends BaseController +{ + + protected $service; + + public function __construct(App $app) + { + parent::__construct($app); + $config = array( + 'level' => 5,//数据库备份卷大小 + 'compress' => 1,//数据库备份文件是否启用压缩 0不压缩 1 压缩 + ); + $this->service = new MysqlBackupService($config); + } + + /** + * @Author:Qinii + * @Date: 2020/5/21 + * @return mixed + */ + public function lst() + { + return app('json')->success( $this->service->dataList()); + } + + /** + * @Author:Qinii + * @Date: 2020/5/21 + * @return mixed + */ + public function fileList() + { + $files = $this->service->fileList(); + $data = []; + foreach ($files as $key => $t) { + $data[] = [ + 'filename' => $t['filename'], + 'part' => $t['part'], + 'size' => $t['size'] . 'B', + 'compress' => $t['compress'], + 'backtime' => $key, + 'time' => $t['time'], + ]; + } + // krsort($data);//根据时间降序 + + return app('json')->success($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/21 + * @param $name + * @return mixed + */ + public function detail($name) + { + $database = Env::get("database.database"); + $result = Db::query("select COLUMN_NAME,COLUMN_TYPE,COLUMN_DEFAULT,IS_NULLABLE,EXTRA,COLUMN_COMMENT from information_schema.columns where table_name = '" . $name . "' and table_schema = '" . $database . "'"); + return app('json')->success($result); + } + + /** + * @Author:Qinii + * @Date: 2020/5/21 + * @param $name + * @return mixed + */ + public function backups($name) + { + $data = []; + if(is_array($name)){ + foreach($name as $item){ + if(!$this->detail($item)) + return app('json')->fail('不存在的表名'); + $res = $this->service->backup($item,0); + if ($res == false && $res != 0) { + $data .= $item . '|'; + } + } + } + if($data) return app('json')->fail('备份失败' . $data); + return app('json')->success('备份成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/21 + * @param $name + * @return mixed + */ + public function optimize($name) + { + $this->service->optimize($name); + return app('json')->success('优化成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/21 + * @param $name + * @return mixed + */ + public function repair($name) + { + foreach ($name as $item){ + $this->service->repair($item); + } + return app('json')->success('修复成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/25 + * @return \think\response\File + */ + public function downloadFile() + { + try { + $time = intval($this->request->param('feilname')); + $file =$this->service->getFile('time', $time); + $fileName = $file[0]; + return download($fileName,$time); + }catch (UploadFailException $e){ + return app('json')->fail('下载失败'); + } + } + + public function deleteFile() + { + $feilname = intval($this->request->param('feilname')); + $files = $this->service->delFile($feilname); + return app('json')->success('删除成功'); + } + +} diff --git a/app/controller/admin/system/serve/Config.php b/app/controller/admin/system/serve/Config.php new file mode 100644 index 00000000..1584c181 --- /dev/null +++ b/app/controller/admin/system/serve/Config.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\admin\system\serve; + +use app\common\repositories\system\serve\ServeMealRepository; +use app\validate\admin\MealValidata; +use crmeb\basic\BaseController; +use think\App; + +class Config extends BaseController +{ + protected $repository; + + public function __construct(App $app, ServeMealRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status', 'type']); + $data = $this->repository->getList($where, $page, $limit); + return app('json')->success($data); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + public function create(MealValidata $validata) + { + $data = $this->request->params(['name', 'price', 'num', 'type', 'status', 'sort']); + $validata->scene('create')->check($data); + + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + public function detail($id) + { + $data = $this->repository->get($id); + if (!$data) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + public function update($id, MealValidata $validata) + { + $data = $this->request->params(['name', 'price', 'num', 'type', 'status', 'sort']); + $validata->scene('create')->check($data); + + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + public function detele($id) + { + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status',1) == 1 ?: 0 ; + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/system/serve/Export.php b/app/controller/admin/system/serve/Export.php new file mode 100644 index 00000000..228ddd9b --- /dev/null +++ b/app/controller/admin/system/serve/Export.php @@ -0,0 +1,81 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\serve; + +use app\common\repositories\store\product\ProductCopyRepository; +use app\common\repositories\system\serve\ServeDumpRepository; +use crmeb\services\CrmebServeServices; +use crmeb\services\ExpressService; +use crmeb\basic\BaseController; +use think\App; + +/** + * 一号通平台物流服务 + * Class Export + * @package app\controller\admin\v1\serve + */ +class Export extends BaseController +{ + + protected $services; + /** + * Export constructor. + * @param App $app + * @param ExpressService $services + */ + public function __construct(App $app, ExpressService $services) + { + parent::__construct($app); + $this->services = $services; + } + + /** + * 物流公司 + * @return mixed + */ + public function getExportAll(CrmebServeServices $services) + { + [$page, $limit] = $this->getPage(); + $ret = $services->express()->express(1); + $data['count'] = $ret['count']; + $data['list'] = $ret['data']; + return app('json')->success($data); + } + + /** + * + * 获取面单信息 + * @param string $com + * @return mixed + */ + public function getExportTemp(CrmebServeServices $services) + { + $com = $this->request->param('com'); + if(!$com) return app('json')->fail('请输入快递公司编号'); + return app('json')->success($services->express()->temp($com)); + } + + + public function dumpLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','mer_id']); + if($this->request->merId()) $where['mer_id'] = $this->request->merId(); + $where['type'] = 'mer_dump'; + $make = app()->make(ProductCopyRepository::class); + $data = $make->getList($where, $page, $limit); + + return app('json')->success($data); + } + + +} diff --git a/app/controller/admin/system/serve/Login.php b/app/controller/admin/system/serve/Login.php new file mode 100644 index 00000000..612f73db --- /dev/null +++ b/app/controller/admin/system/serve/Login.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\serve; + +use app\common\repositories\system\config\ConfigValueRepository; +use app\validate\admin\CrmebServeValidata; +use app\Request; +use crmeb\basic\BaseController; +use crmeb\services\CrmebServeServices; + +use think\App; +use think\facade\Cache; + +/** + * 服务登录 + * Class Login + * @package app\controller\admin\v1\serve + */ +class Login extends BaseController +{ + protected $services; + + public function __construct(App $app, CrmebServeServices $services) + { + parent::__construct($app); + $this->services = $services; + } + + /** + * 发送验证码 + * @param string $phone + * @return mixed + */ + public function captcha(string $phone,CrmebServeValidata $validata) + { + $validata->scene('phone')->check(['phone' => $phone]); + $this->services->user()->code($phone); + return app('json')->success('短信发送成功'); + } + + /** + * 验证验证码 + * @param string $phone + * @param $code + * @return mixed + */ + public function checkCode(CrmebServeValidata $validata) + { + $phone = $this->request->param('phone'); + $verify_code = $this->request->param('verify_code'); + $validata->scene('phone')->check(['phone' => $phone]); + $this->services->user()->checkCode($phone, $verify_code); + return app('json')->success('success'); + } + + /** + * 注册服务 + * @param Request $request + * @param SmsAdminServices $services + * @return mixed + */ + public function register(Request $request,CrmebServeValidata $validata) + { + $data = $this->request->params(['phone','account','password','verify_code']); + + $data['account'] = $data['phone']; + $validata->check($data); + $data['password'] = md5($data['password']); + $res = $this->services->user()->register($data); + if ($res) { + $arr = [ + 'serve_account' => $data['account'], + 'serve_token' => md5($data['account'] . md5($data['password'])), + ]; + app()->make(ConfigValueRepository::class)->setFormData($arr, 0); + return app('json')->success('一号通注册成功'); + } else { + return app('json')->fail('一号通注册失败'); + } + } + + /** + * 平台登录 + * @return mixed + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function login(CrmebServeValidata $validata) + { + $account = $this->request->param('account'); + $password = $this->request->param('password'); + $validata->scene('login')->check(['account' => $account, 'password' => $password]); + $password = md5($account . md5($password)); + $res = $this->services->user()->login($account, $password); + + if ($res) { + Cache::set('serve_account', $account); + $arr = [ + 'serve_account' => $account, + 'serve_token' => $password, + ]; + app()->make(ConfigValueRepository::class)->setFormData($arr, 0); + return app('json')->success('一号通登录成功', $res); + } else { + return app('json')->fail('一号通登录失败'); + } + } + +} diff --git a/app/controller/admin/system/serve/Serve.php b/app/controller/admin/system/serve/Serve.php new file mode 100644 index 00000000..1d68dcba --- /dev/null +++ b/app/controller/admin/system/serve/Serve.php @@ -0,0 +1,256 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\serve; + +//use app\validate\admin\serve\ServeValidata; +//use app\services\system\config\SystemConfigServices; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\validate\admin\ExpressValidata; +use app\validate\admin\MealValidata; +use crmeb\basic\BaseController; +use crmeb\services\CrmebServeServices; +use think\App; +use think\facade\Cache; +use app\validate\admin\CrmebServeValidata; + +/** + * Class Serve + * @package app\controller\admin\v1\serve + */ +class Serve extends BaseController +{ + protected $services; + /** + * Serve constructor. + * @param App $app + * @param ServeServices $services + */ + public function __construct(App $app, CrmebServeServices $services) + { + parent::__construct($app); + $this->services = $services; + } + + /** + * 检测登录 + * @return mixed + */ + public function is_login() + { + $sms_info = Cache::get('serve_account'); + if ($sms_info) { + return app('json')->success(['status' => true, 'info' => $sms_info]); + } else { + return app('json')->success(['status' => false]); + } + } + + /** + * 获取套餐列表 + * @param string $type 套餐类型:sms,短信;query,物流查询;dump,电子面单;copy,产品复制 + * @return mixed + */ + public function mealList(string $type) + { + $res = $this->services->user()->mealList($type); + if ($res) { + return app('json')->success($res); + } else { + return app('json')->fail('获取套餐列表失败'); + } + } + + /** + * 获取支付码 + * @return mixed + */ + public function payMeal() + { + $data = $this->request->params(['meal_id','price','num','type','pay_type']); + $openInfo = $this->services->user()->getUser(); + if (!$openInfo) app('json')->fail('获取支付码失败'); + switch ($data['type']) { + case "sms" : + if (!$openInfo['sms']['open']) return app('json')->fail('请先开通短信服务'); + break; + case "query" : + if (!$openInfo['query']['open']) return app('json')->fail('请先开通物流查询服务'); + break; + case "dump" : + if (!$openInfo['dump']['open']) return app('json')->fail('请先开通电子面单打印服务'); + break; + case "copy" : + if (!$openInfo['copy']['open']) return app('json')->fail('请先开通商品采集服务'); + break; + } + $this->validate($data, MealValidata::class); + + $res = $this->services->user()->payMeal($data); + if ($res) { + return app('json')->success($res); + } else { + return app('json')->fail('获取支付码失败'); + } + } + + /** + * 获取用户信息,用户信息内包含是否开通服务字段 + * @return mixed + */ + public function getUserInfo() + { + return app('json')->success($this->services->user()->getUser()); + } + + /** + * 查询使用记录 + * @return mixed + */ + public function getRecord() + { + [$page, $limit] = $this->getPage(); + $data = $this->request->params(['type']); + return app('json')->success($this->services->user()->record($page, $limit, $data['type'])); + } + + /** + * 开通服务 + * @param string $type 套餐类型:sms,短信;query,物流查询;dump,电子面单;copy,产品复制 + * @return mixed + */ + public function openServe() + { + $type = $this->request->param('type'); + switch ($type) + { + case 'sms': //短信呢 + $sign = $this->request->param('sign'); + if(!$sign) return app('json')->fail('请设置短信签名'); + $this->services->sms()->setSign($sign)->open(); + break; + case 'query': + $this->services->express()->open(); + break; + case 'dump': + $this->services->express()->open(); + break; + case 'copy': + $this->services->copy()->open(); + break; + } + return app('json')->success('开通成功'); + } + + /** + * 修改密码 + * @return mixed + */ + public function changePassword(CrmebServeValidata $validata) + { + + $data = $this->request->params(['phone','account','password','verify_code']); + $validata->check($data); + $data['password'] = md5($data['password']); + $this->services->user()->modify($data); + Cache::delete('serve_account'); + return app('json')->success('修改成功'); + } + + /** + * 修改手机号 + * @return mixed + */ + public function updatePhone(CrmebServeValidata $validata) + { + $data = $this->request->params(['phone','account','verify_code']); + $validata->scene('phone')->check($data); + + $this->services->user()->modifyPhone($data); + Cache::delete('sms_account'); + return app('json')->success('修改成功'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 7/17/21 + */ + public function getConfig() + { + $params = [ + 'express_app_code' => systemConfig('express_app_code'), + 'crmeb_serve_express' => systemConfig('crmeb_serve_express'), + 'crmeb_serve_dump' => systemConfig('crmeb_serve_dump'), + 'copy_product_status' => systemConfig('copy_product_status'), + 'copy_product_apikey' => systemConfig('copy_product_apikey'), + ]; + + return app('json')->success($params); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 7/17/21 + */ + public function setConfig() + { + $params = $this->request->params([ + 'express_app_code', + 'crmeb_serve_express', + 'crmeb_serve_dump', + 'copy_product_status', + 'copy_product_apikey' + ]); + app()->make(ConfigValueRepository::class)->setFormData($params,0); + return app('json')->success('保存成功'); + } + + /** + * TODO 购买记录 + * @return \think\response\Json + * @author Qinii + * @day 7/22/21 + */ + public function paylst() + { + [$page, $limit] = $this->getPage(); + $data = $this->services->user()->userBill($page, $limit); + return app('json')->success($data); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 7/22/21 + */ + public function merPaylst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type','mer_id','date']); + $data = app()->make(ServeOrderRepository::class)->getList($where,$page,$limit); + return app('json')->success($data); + } + + public function merLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['mer_id','date']); + $data = app()->make(MerchantRepository::class)->lst($where, $page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/system/serve/Sms.php b/app/controller/admin/system/serve/Sms.php new file mode 100644 index 00000000..96b6dd80 --- /dev/null +++ b/app/controller/admin/system/serve/Sms.php @@ -0,0 +1,94 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\system\serve; + +use app\validate\admin\CrmebServeValidata; +use crmeb\basic\BaseController; +use crmeb\services\CrmebServeServices; +use think\App; + +/** + * Class Sms + * @package app\controller\admin\v1\serve + */ +class Sms extends BaseController +{ + protected $services; + /** + * Sms constructor. + * @param App $app + * @param ServeServices $services + */ + public function __construct(App $app, CrmebServeServices $services) + { + parent::__construct($app); + $this->services = $services; + } + + /** + * 修改短信签名 + * @param string $sign + * @return mixed + */ + public function changeSign(CrmebServeValidata $validata) + { + $data = $this->request->params(['phone','sign','verify_code']); + + $validata->scene('phone')->check(['phone' => $data['phone']]); + + if (!$data['sign']) { + return app('json')->fail('请设置短信签名'); + } + $this->services->sms()->modify($data['sign'], $data['phone'], $data['verify_code']); + return app('json')->success('修改短信签名成功'); + } + + /** + * 获取短信模板 + * @return mixed + */ + public function temps() + { + [$page, $limit] = $this->getPage(); + $type = $this->request->param('type'); + + return app('json')->success($this->services->getSmsTempsList((int)$page, (int)$limit, (int)$type)); + } + + /** + * 申请模板 + * @return mixed + */ + public function apply() + { + $data = $this->request->params(['title','type','content']); + if (!$data['title'] || !$data['content'] || !$data['type']) { + return app('json')->success('请填写申请模板内容'); + } + $ret = $this->services->sms()->apply($data['title'], $data['content'], (int)$data['type']); + return app('json')->success($ret); + } + + /** + * 获取申请记录 + * @return mixed + */ + public function applyRecord() + { + [$page, $limit] = $this->getPage(); + $tempType = $this->request->param('temp_type',0); + if (is_null($tempType)) $tempType = 0; + $ret = $this->services->sms()->applys((int)$tempType, $page, $limit); + + return app('json')->success($ret); + } +} diff --git a/app/controller/admin/system/service/StoreService.php b/app/controller/admin/system/service/StoreService.php new file mode 100644 index 00000000..f487eee2 --- /dev/null +++ b/app/controller/admin/system/service/StoreService.php @@ -0,0 +1,252 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\service; + +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\user\UserRepository; +use app\validate\merchant\StoreServiceValidate; +use crmeb\basic\BaseController; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class StoreService + * @package app\controller\merchant\store\service + * @author xaboy + * @day 2020/5/29 + */ +class StoreService extends BaseController +{ + /** + * @var StoreServiceRepository + */ + protected $repository; + /** + * @var StoreServiceLogRepository + */ + protected $logRepository; + + /** + * StoreService constructor. + * @param App $app + * @param StoreServiceRepository $repository + */ + public function __construct(App $app, StoreServiceRepository $repository, StoreServiceLogRepository $logRepository) + { + parent::__construct($app); + $this->repository = $repository; + $this->logRepository = $logRepository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function lst() + { + $where = $this->request->params(['keyword', 'status']); + [$page, $limit] = $this->getPage(); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020/5/29 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->request->merId()))); + } + + /** + * @param StoreServiceValidate $validate + * @return mixed + * @author xaboy + * @day 2020/5/29 + */ + public function create(StoreServiceValidate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->request->merId(); + if ($this->repository->issetService($data['mer_id'], $data['uid'])) + return app('json')->fail('该用户已绑定客服'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @param StoreServiceValidate $validate + * @return array + * @author xaboy + * @day 2020/5/29 + */ + public function checkParams(StoreServiceValidate $validate) + { + $data = $this->request->params([['uid', []], 'nickname', 'status', 'customer', 'is_verify', 'is_goods', 'notify', 'avatar', 'phone', ['sort', 0]]); + if (!$this->request->merId()) { + $data['is_verify'] = 0; + $data['customer'] = 0; + $data['is_goods'] = 0; + $data['notify'] = 0; + $data['phone'] = ''; + } + $validate->check($data); + if (!$data['avatar']) $data['avatar'] = $data['uid']['src']; + $data['uid'] = $data['uid']['id']; + return $data; + } + + /** + * @param $id + * @return mixed + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function updateForm($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param $id + * @param StoreServiceValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function update($id, StoreServiceValidate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->merExists($merId = $this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->issetService($merId, $data['uid'], $id)) + return app('json')->fail('该用户已绑定客服'); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function changeStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_open' => $status == 1 ? 1 : 0]); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * TODO 客服的全部用户 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function serviceUserList($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getServiceUserList($id, $page, $limit)); + } + + + /** + * TODO 商户的全部用户列表 + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function merchantUserList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getMerchantUserList($this->request->merId(), $page, $limit)); + } + + /** + * TODO 用户与客服聊天记录 + * @param $id + * @param $uid + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function getUserMsnByService($id, $uid) + { + [$page, $limit] = $this->getPage(); + if (!$this->repository->getWhereCount(['service_id' => $id, 'mer_id' => $this->request->merId()])) + return app('json')->fail('客服不存在'); + return app('json')->success($this->logRepository->getUserMsn($uid, $page, $limit, $this->request->merId(), $id)); + } + + /** + * TODO 用户与商户聊天记录 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function getUserMsnByMerchant($id) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getUserMsn($id, $page, $limit, $this->request->merId())); + } + + public function getUserList() + { + [$page, $limit] = $this->getPage(); + $data = app()->make(UserRepository::class)->getList([],$page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/system/sms/Sms.php b/app/controller/admin/system/sms/Sms.php new file mode 100644 index 00000000..73cc0d42 --- /dev/null +++ b/app/controller/admin/system/sms/Sms.php @@ -0,0 +1,212 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\sms; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\sms\SmsRecordRepository; +use app\validate\admin\SmsRegisterValidate; +use crmeb\services\YunxinSmsService; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Cache; + +/** + * Class Sms + * @package app\controller\admin\system\sms + * @author xaboy + * @day 2020-05-18 + */ +class Sms extends BaseController +{ + /** + * @var YunxinSmsService + */ + protected $service; + + /** + * Sms constructor. + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + $this->service = YunxinSmsService::create(); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function captcha() + { + $phone = request()->param('phone'); + if (!$phone) + return app('json')->fail('请输入手机号'); + if (!preg_match('/^1[3456789]{1}\d{9}$/', $phone)) + return app('json')->fail('请输入正确的手机号'); + $res = $this->service->captcha($phone); + + if (!isset($res['status']) && $res['status'] !== 200) + return app('json')->fail($res['data']['message'] ?? $res['msg'] ?? '发送失败'); + + return app('json')->success($res['data']['message'] ?? $res['msg'] ?? '发送成功'); + } + + /** + * @param SmsRegisterValidate $validate + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function save(SmsRegisterValidate $validate) + { + $data = $this->request->params(['account', 'password', 'phone', 'code', 'url', 'sign']); + $validate->check($data); + $data['password'] = md5($data['password']); + $res = $this->service->registerData($data); + if ($res['status'] == 400) return app('json')->fail('短信平台:' . $res['msg']); + $this->service->setConfig($data['account'], $data['password']); + return app('json')->success('短信平台:' . $res['msg']); + } + + /** + * @param SmsRegisterValidate $validate + * @param ConfigValueRepository $repository + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function save_basics(SmsRegisterValidate $validate, ConfigValueRepository $repository) + { + $data = $this->request->params([ + 'account', 'password' + ]); + + $validate->isLogin()->check($data); + $this->service->setConfig($data['account'], md5($data['password'])); + + //添加公共短信模板 + $templateList = $this->service->publictemp([]); + if ($templateList['status'] != 400) { + $repository->setFormData(['sms_account' => $data['account'], 'sms_token' => md5($data['password'])], 0); + return app('json')->success('登录成功'); + } else { + return app('json')->fail('账号或密码错误'); + } + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function is_login() + { + if ($sms_info = $this->service->account()) { + return app('json')->success(['status' => true, 'info' => $sms_info]); + } else { + return app('json')->success(['status' => false]); + } + } + + /** + * @param SmsRecordRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-18 + */ + public function record(SmsRecordRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type',0]); + return app('json')->success($repository->getList($where, $page, $limit)); + } + + /** + * @param SmsRecordRepository $repository + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function data(SmsRecordRepository $repository) + { + $countInfo = $this->service->count(); + if ($countInfo['status'] == 400) { + $info['number'] = 0; + $info['total_number'] = 0; + } else { + $info['number'] = $countInfo['data']['number']; + $info['total_number'] = $countInfo['data']['send_total']; + } + $info['record_number'] = $repository->count(); + $info['sms_account'] = $this->service->account(); + return app('json')->success($info); + } + + /** + * @param ConfigValueRepository $repository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-18 + */ + public function logout(ConfigValueRepository $repository) + { + Cache::delete('sms_account'); + Cache::delete('serve_account'); + $repository->clear(['sms_account', 'sms_token','serve_account','serve_token'], 0); + return app('json')->success('退出成功'); + } + + /** + * 修改密码 + * @Author:Qinii + * @Date: 2020/9/2 + * @return mixed + */ + public function changePassword() + { + $data = $this->request->params(['password','phone','code']); + if(empty($data['password'])) + return app('json')->fail('密码不能为空'); + $data['password'] = md5($data['password']); + $res = $this->service->smsChange($data); + if ($res['status'] == 400) return app('json')->fail('短信平台:' . $res['msg']); + $this->service->setConfig($this->service->account(), $data['password']); + return app('json')->success('修改成功'); + } + + /** + * 修改签名 + * @Author:Qinii + * @Date: 2020/9/2 + * @return mixed + */ + public function changeSign() + { + $data = $this->request->params(['sign','phone','code']); + if(empty($data['sign'])) return app('json')->fail('签名不能为空'); + $res = $this->service->smsChange($data); + if ($res['status'] == 400) return app('json')->fail('短信平台:' . $res['msg']); + return app('json')->success('修改已提交,审核通过后自动更改'); + } +} diff --git a/app/controller/admin/system/sms/SmsPay.php b/app/controller/admin/system/sms/SmsPay.php new file mode 100644 index 00000000..78eec90a --- /dev/null +++ b/app/controller/admin/system/sms/SmsPay.php @@ -0,0 +1,97 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\sms; + + +use crmeb\basic\BaseController; +use crmeb\services\YunxinSmsService; +use think\App; + +/** + * Class SmsPay + * @package app\controller\admin\system\sms + * @author xaboy + * @day 2020-05-18 + */ +class SmsPay extends BaseController +{ + /** + * @var YunxinSmsService + */ + protected $service; + + /** + * Sms constructor. + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + $this->service = YunxinSmsService::create(); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function number() + { + $countInfo = $this->service->count(); + if ($countInfo['status'] == 400) return app('json')->fail($countInfo['msg']); + $info['account'] = $this->service->account(); + $info['number'] = $countInfo['data']['number']; + $info['send_total'] = $countInfo['data']['send_total']; + return app('json')->success($info); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function price() + { + [$page, $limit] = $this->getPage(); + $mealInfo = $this->service->meal($page, $limit); + if ($mealInfo['status'] == 400) return app('json')->fail($mealInfo['msg']); + return app('json')->success($mealInfo['data']); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function pay() + { + list($payType, $mealId, $price) = $this->request->params([ + ['payType', 'weixin'], + ['mealId', 0], + ['price', 0], + ], true); + $payInfo = $this->service->pay($payType, $mealId, $price, $this->request->adminId()); + if ($payInfo['status'] == 400) return app('json')->fail($payInfo['msg']); + return app('json')->success($payInfo['data']); + } + + /** + * @author xaboy + * @day 2020-05-18 + */ + public function notice() + { + //TODO 短信支付成功回调 + } +} diff --git a/app/controller/admin/system/sms/SmsTemplate.php b/app/controller/admin/system/sms/SmsTemplate.php new file mode 100644 index 00000000..53143466 --- /dev/null +++ b/app/controller/admin/system/sms/SmsTemplate.php @@ -0,0 +1,144 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\system\sms; + + +use crmeb\basic\BaseController; +use crmeb\services\YunxinSmsService; +use FormBuilder\Exception\FormBuilderException; +use think\App; + +/** + * Class SmsTemplate + * @package app\controller\admin\system\sms + * @author xaboy + * @day 2020-05-18 + */ +class SmsTemplate extends BaseController +{ + /** + * @var YunxinSmsService + */ + protected $service; + + /** + * Sms constructor. + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + $this->service = YunxinSmsService::create(); + } + + /** + * 异步获取公共模板列表 + */ + public function public() + { + $where = $this->request->params([ + ['is_have', ''], + ['page', 1], + ['limit', 20], + ]); + $templateList = $this->service->publictemp($where); + if ($templateList['status'] == 400) return app('json')->fail($templateList['msg']); + $arr = $templateList['data']['data']; + foreach ($arr as $key => $value) { + switch ($value['type']) { + case 1: + $arr[$key]['type'] = '验证码'; + break; + case 2: + $arr[$key]['type'] = '通知'; + break; + case 3: + $arr[$key]['type'] = '推广'; + break; + default: + $arr[$key]['type'] = ''; + break; + } + } + $templateList['data']['data'] = $arr; + return app('json')->success($templateList['data']); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-18 + */ + public function form() + { + return app('json')->success(formToData($this->service->form())); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function template() + { + $where = $this->request->params([ + ['status', ''], + ['title', ''], + ['temp_type', ''], + ['page', 1], + ['limit', 20] + ]); + $templateList = $this->service->template($where); + if ($templateList['status'] == 400) return app('json')->fail($templateList['msg']); + $arr = $templateList['data']['data']; + foreach ($arr as $key => $value) { + switch ($value['type']) { + case 1: + $arr[$key]['type'] = '验证码'; + break; + case 2: + $arr[$key]['type'] = '通知'; + break; + case 3: + $arr[$key]['type'] = '推广'; + break; + default: + $arr[$key]['type'] = ''; + break; + } + } + $templateList['data']['data'] = $arr; + return app('json')->success($templateList['data']); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function apply() + { + $data = $this->request->params([ + 'title', + 'content', + ['type', 0] + ]); + if (!$data['title']) return app('json')->fail('请输入模板名称'); + if (!$data['content']) return app('json')->fail('请输入模板内容'); + $applyStatus = $this->service->apply($data['title'], $data['content'], $data['type']); + if ($applyStatus['status'] == 400) return app('json')->fail($applyStatus['msg']); + return app('json')->success('申请成功'); + } +} diff --git a/app/controller/admin/user/FeedBack.php b/app/controller/admin/user/FeedBack.php new file mode 100644 index 00000000..f81699db --- /dev/null +++ b/app/controller/admin/user/FeedBack.php @@ -0,0 +1,102 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\user; + + +use crmeb\basic\BaseController; +use think\App; +use app\common\repositories\user\FeedbackRepository as repository; + +class FeedBack extends BaseController +{ + /** + * @var UserRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + $where = $this->request->params(['keyword', 'type', 'status','realname',['is_del',0]]); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function detail($id) + { + if (!$this->repository->fieldExists('feedback_id',$id)) + return app('json')->fail('数据不存在'); + $feedback = $this->repository->get($id)->toArray(); + [$feedback['category'], $feedback['type']] = explode('/', $feedback['type'], 2); + return app('json')->success($feedback); + } + + public function replyForm($id) + { + return app('json')->success(formToData($this->repository->replyForm($id))); + } + + /** + * @param $id + * @return mixed + * @throws \think\db\exception\DbException + * @author Qinii + */ + public function reply($id) + { + if (!$this->repository->fieldExists('feedback_id',$id)) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['reply', 'remake']); + if (!empty($data['reply'])) { + $data['status'] = 1; + $data['update_time'] = date('Y-m-d H:i:s'); + } + + $this->repository->update($id,$data); + if (!empty($data['reply'])) event('user.feedbackReply',compact('id','data')); + return app('json')->success('回复成功'); + } + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->fieldExists('feedback_id',$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['is_del' => 1]); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/user/FeedBackCategory.php b/app/controller/admin/user/FeedBackCategory.php new file mode 100644 index 00000000..c025380a --- /dev/null +++ b/app/controller/admin/user/FeedBackCategory.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\user; + + +use crmeb\basic\BaseController; +use think\App; +use app\common\repositories\user\FeedBackCategoryRepository as repository; + +class FeedBackCategory extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst() + { + return app('json')->success($this->repository->getFormatList(0)); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form(0))); + } + + public function updateForm($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm(0,$id))); + } + + + public function create() + { + $data = $this->request->params(['pid','cate_name','sort','pic','is_show']); + if(empty($data['cate_name'])) + return app('json')->fail('分类名不可为空'); + if(strlen($data['cate_name']) > 60) + return app('json')->fail('分类名不得超过20个汉字'); + if ($data['pid'] && !$this->repository->merExists(0, $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'])) + return app('json')->fail('不可添加更低阶分类'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + + public function update($id) + { + $data = $this->request->params(['pid','cate_name','sort','pic','is_show']); + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + if ($data['pid'] && !$this->repository->merExists(0, $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'])) + return app('json')->fail('不可添加更低阶分类'); + if (!$this->repository->checkChangeToChild($id,$data['pid'])) + return app('json')->fail('无法修改到当前分类到子集,请先修改子类'); + //todo 待优化 +// if (!$this->repository->checkChildLevel($id,$data['pid'])) +// return app('json')->fail('子类超过最低限制,请先修改子类'); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + + $this->repository->switchStatus($id, $status); + return app('json')->success('修改成功'); + } + + + public function delete($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->hasChild($id)) + return app('json')->fail('该分类存在子集,请先处理子集'); + + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function detail($id) + { + if (!$this->repository->merExists(0, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)); + } + +} diff --git a/app/controller/admin/user/MemberInterests.php b/app/controller/admin/user/MemberInterests.php new file mode 100644 index 00000000..86008802 --- /dev/null +++ b/app/controller/admin/user/MemberInterests.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\user; + +use app\common\repositories\user\MemberinterestsRepository; +use app\common\repositories\user\UserBrokerageRepository; +use app\validate\admin\UserBrokerageValidate; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class MemberInterests extends BaseController +{ + protected $repository; + + public function __construct(App $app, MemberinterestsRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['name',['type',$this->repository::TYPE_FREE]]); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + public function create() + { + $data = $this->checkParams(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id, $this->repository::TYPE_FREE))); + } + + public function update($id) + { + $id = (int)$id; + $data = $this->checkParams(); + if (!$id || !$this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + public function detail($id) + { + $id = (int)$id; + if (!$id || !$brokerage = $this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + return app('json')->success($brokerage->toArray()); + } + + public function delete($id) + { + $id = (int)$id; + if (!$id || !$brokerage = $this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + $brokerage->delete(); + return app('json')->success('删除成功'); + } + + public function checkParams() + { + $data = $this->request->params(['brokerage_level', 'name', 'info', 'pic', 'type',['has_type',0],['link',''],['value',''],['on_pic','']]); + if ($data['type'] == $this->repository::TYPE_FREE) { + if(!$data['name'] || !$data['pic'] || empty($data['brokerage_level'])) + throw new ValidateException('请填写正确的权益信息'); + $count = app()->make(UserBrokerageRepository::class)->getWhereCount(['brokerage_level' => $data['brokerage_level'], 'type' => $data['type']]); + if (!$count) throw new ValidateException('会员等级不存在'); + } else { + if (mb_strlen($data['name']) > 6) throw new ValidateException('名称必须小于6个字符'); + if ($data['value'] < 0 && in_array($data['has_type'],[$this->repository::HAS_TYPE_SIGN,$this->repository::HAS_TYPE_PAY,$this->repository::HAS_TYPE_MEMBER])){ + throw new ValidateException('倍数不能位负数'); + } + } + + return $data; + } + + public function getSvipInterests() + { + $where['type'] = $this->repository::TYPE_SVIP; + $data = $this->repository->getList($where,1,10); + return app('json')->success($data['list']); + } + public function updateSvipForm($id) + { + return app('json')->success(formToData($this->repository->svipForm($id))); + } + + public function switchWithStatus($id) + { + $status = $this->request->param('status') == 1 ? 1 :0; + try{ + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + }catch (\Exception $exception) { + return app('json')->success('修改失败'); + } + } +} diff --git a/app/controller/admin/user/Svip.php b/app/controller/admin/user/Svip.php new file mode 100644 index 00000000..ce5a7278 --- /dev/null +++ b/app/controller/admin/user/Svip.php @@ -0,0 +1,194 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\groupData\GroupRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\common\repositories\user\MemberinterestsRepository; +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserOrderRepository; +use app\validate\admin\UserBrokerageValidate; +use crmeb\basic\BaseController; +use think\App; + +class Svip extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBrokerageRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 购买会员套餐的列表 + * @param GroupRepository $groupRepository + * @param GroupDataRepository $groupDataRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/4 + */ + public function getTypeLst(GroupRepository $groupRepository,GroupDataRepository $groupDataRepository) + { + [$page, $limit] = $this->getPage(); + $group_id = $groupRepository->getSearch(['group_key' => 'svip_pay'])->value('group_id'); + $lst = $groupDataRepository->getGroupDataLst(0, intval($group_id), $page, $limit); + return app('json')->success($lst); + } + + /** + * TODO 添加够没类型 + * @param GroupRepository $groupRepository + * @param GroupDataRepository $groupDataRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/4 + */ + public function createTypeCreateForm(GroupRepository $groupRepository, GroupDataRepository $groupDataRepository) + { + $group_id = $groupRepository->getSearch(['group_key' => 'svip_pay'])->value('group_id'); + $data = $groupDataRepository->reSetDataForm($group_id, null, null); + return app('json')->success(formToData($data)); + } + + /** + * TODO 编辑会员购买类型 + * @param $id + * @param GroupRepository $groupRepository + * @param GroupDataRepository $groupDataRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/8 + */ + public function updateTypeCreateForm($id, GroupRepository $groupRepository, GroupDataRepository $groupDataRepository) + { + $group_id = $groupRepository->getSearch(['group_key' => 'svip_pay'])->value('group_id'); + $data = $groupDataRepository->reSetDataForm($group_id, $id, null); + return app('json')->success(formToData($data)); + } + + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 2022/11/8 + */ + public function getInterestsLst(MemberinterestsRepository $memberinterestsRepository) + { + $data = $memberinterestsRepository->getInterestsByLevel($memberinterestsRepository::TYPE_SVIP); + return app('json')->success($data); + } + + + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + public function create() + { + $data = $this->checkParams(); + if ($this->repository->fieldExists('brokerage_level', $data['brokerage_level'],null, $data['type'])) { + return app('json')->fail('会员等级已存在'); + } + if ($data['type']) { + $data['brokerage_rule'] = [ + 'image' => $data['image'], + 'value' => $data['value'], + ]; + } + unset($data['image'], $data['value']); + + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $id = (int)$id; + $data = $this->checkParams(); + if (!$id || !$this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + if ($this->repository->fieldExists('brokerage_level', $data['brokerage_level'], $id, $data['type'])) { + return app('json')->fail('会员等级已存在'); + } + + if ($data['type']) { + $data['brokerage_rule'] = [ + 'image' => $data['image'], + 'value' => $data['value'], + ]; + } + unset($data['image'], $data['value']); + + $data['brokerage_rule'] = json_encode($data['brokerage_rule'], JSON_UNESCAPED_UNICODE); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + public function detail($id) + { + $id = (int)$id; + if (!$id || !$brokerage = $this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + return app('json')->success($brokerage->toArray()); + } + + public function delete($id) + { + $id = (int)$id; + if (!$id || !$brokerage = $this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + if ($brokerage->user_num > 0) { + return app('json')->fail('该等级下有数据,不能进行删除操作!'); + } + $brokerage->delete(); + return app('json')->success('删除成功'); + } + + public function checkParams() + { + $data = $this->request->params(['brokerage_level', 'brokerage_name', 'brokerage_icon', 'brokerage_rule', 'extension_one', 'extension_two', 'image', 'value', ['type',0]]); + app()->make(UserBrokerageValidate::class)->check($data); + return $data; + } + + /** + * TODO 会员购买记录 + * @param UserOrderRepository $userOrderRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/12 + */ + public function payList(UserOrderRepository $userOrderRepository) + { + [$page, $limit] = $this->getPage(); + $type = $this->request->param('svip_type',''); + $where = $this->request->params(['pay_type','title','date','nickname','keyword']); + if($type) $where['type'] = $userOrderRepository::TYPE_SVIP.$type; + $data = $userOrderRepository->getList($where,$page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/user/User.php b/app/controller/admin/user/User.php new file mode 100644 index 00000000..7c286f47 --- /dev/null +++ b/app/controller/admin/user/User.php @@ -0,0 +1,594 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\user\UserSpreadLogRepository; +use app\common\repositories\user\UserVisitRepository; +use crmeb\basic\BaseController; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserGroupRepository; +use app\common\repositories\user\UserLabelRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\wechat\WechatNewsRepository; +use app\common\repositories\wechat\WechatUserRepository; +use app\validate\admin\UserNowMoneyValidate; +use app\validate\admin\UserValidate; +use crmeb\services\ExcelService; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Db; + +/** + * Class User + * @package app\controller\admin\user + * @author xaboy + * @day 2020-05-07 + */ +class User extends BaseController +{ + /** + * @var UserRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param UserRepository $repository + */ + public function __construct(App $app, UserRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function lst() + { + /* + * 昵称,分组,标签,地址,性别, + */ + $where = $this->request->params([ + 'label_id', + 'user_type', + 'sex', + 'is_promoter', + 'country', + 'pay_count', + 'user_time_type', + 'user_time', + 'nickname', + 'province', + 'city', + 'group_id', + 'phone', + 'uid', + ]); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function spreadList($uid) + { + $where = $this->request->params(['level', 'keyword', 'date']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getLevelList($uid, $where, $page, $limit)); + } + + public function spreadOrder($uid) + { + $where = $this->request->params(['level', 'keyword', 'date']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->subOrder($uid, $page, $limit, $where)); + } + + public function clearSpread($uid) + { + $this->repository->update($uid, ['spread_uid' => 0]); + return app('json')->success('清除成功'); + } + + + public function createForm() + { + return app('json')->success(formToData($this->repository->createForm())); + } + + public function create(UserValidate $validate) + { + $data = $this->request->params([ + 'account', + 'pwd', + 'repwd', + 'nickname', + 'avatar', + 'real_name', + 'phone', + 'sex', + 'status', + 'card_id', + ['is_promoter', 0] + ]); + + $validate->scene('create')->check($data); + $data['pwd'] = $this->repository->encodePassword($data['repwd']); + unset($data['repwd']); + if ($data['is_promoter']) $data['promoter_time'] = date('Y-m-d H:i:s'); + $this->repository->create('h5',$data); + + return app('json')->success('添加成功'); + } + + public function changePasswordForm($id) + { + return app('json')->success(formToData($this->repository->changePasswordForm($id))); + } + + public function changePassword($id) + { + $data = $this->request->params([ + 'pwd', + 'repwd', + ]); + if (!$data['pwd'] || !$data['repwd']) + return app('json')->fail('密码不能为空'); + if ($data['pwd'] !== $data['repwd']) + return app('json')->fail('密码不一致'); + $data['pwd'] = $this->repository->encodePassword($data['repwd']); + unset($data['repwd']); + $this->repository->update($id,$data); + + return app('json')->success('修改成功'); + } + + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-09 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->userForm($id))); + } + + /** + * @param $id + * @param UserValidate $validate + * @param UserLabelRepository $labelRepository + * @param UserGroupRepository $groupRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-09 + */ + public function update($id, UserValidate $validate, UserLabelRepository $labelRepository, UserGroupRepository $groupRepository) + { + $data = $this->request->params(['real_name', 'phone', 'birthday', 'card_id', 'addres', 'mark', 'group_id', ['label_id', []], ['is_promoter', 0], ['status', 0]]); + $validate->check($data); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($data['group_id'] && !$groupRepository->exists($data['group_id'])) + return app('json')->fail('分组不存在'); + $label_id = (array)$data['label_id']; + foreach ($label_id as $k => $value) { + $label_id[$k] = (int)$value; + if (!$labelRepository->exists((int)$value)) + return app('json')->fail('标签不存在'); + } + $data['label_id'] = implode(',', $label_id); + if ($data['is_promoter']) + $data['promoter_time'] = date('Y-m-d H:i:s'); + if(!$data['birthday']) unset($data['birthday']); + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + + /** + * @param $id + * @param UserLabelRepository $labelRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-08 + */ + public function changeLabel($id, UserLabelRepository $labelRepository) + { + $label_id = (array)$this->request->param('label_id', []); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + foreach ($label_id as $k => $value) { + $label_id[$k] = (int)$value; + if (!$labelRepository->exists((int)$value)) + return app('json')->fail('标签不存在'); + } + $label_id = implode(',', $label_id); + $this->repository->update($id, compact('label_id')); + return app('json')->success('修改成功'); + } + + /** + * @param UserLabelRepository $labelRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-08 + */ + public function batchChangeLabel(UserLabelRepository $labelRepository) + { + $label_id = (array)$this->request->param('label_id', []); + $ids = (array)$this->request->param('ids', []); + if (!count($ids)) + return app('json')->fail('数据不存在'); + foreach ($label_id as $k => $value) { + $label_id[$k] = (int)$value; + if (!$labelRepository->exists((int)$value)) + return app('json')->fail('标签不存在'); + } + $this->repository->batchChangeLabelId($ids, $label_id); + return app('json')->success('修改成功'); + } + + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-08 + */ + public function changeLabelForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeLabelForm($id))); + } + + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-08 + */ + public function batchChangeLabelForm() + { + $ids = $this->request->param('ids', ''); + $ids = array_filter(explode(',', $ids)); + if (!count($ids)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeLabelForm($ids))); + } + + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-08 + */ + public function batchChangeGroupForm() + { + $ids = $this->request->param('ids', ''); + $ids = array_filter(explode(',', $ids)); + if (!count($ids)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeGroupForm($ids))); + } + + /** + * @param $id + * @param UserGroupRepository $groupRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function changeGroup($id, UserGroupRepository $groupRepository) + { + $group_id = (int)$this->request->param('group_id', 0); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + if ($group_id && !$groupRepository->exists($group_id)) + return app('json')->fail('分组不存在'); + $this->repository->update($id, compact('group_id')); + return app('json')->success('修改成功'); + } + + /** + * @param UserGroupRepository $groupRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function batchChangeGroup(UserGroupRepository $groupRepository) + { + $group_id = (int)$this->request->param('group_id', 0); + $ids = (array)$this->request->param('ids', []); + if (!count($ids)) + return app('json')->fail('数据不存在'); + if ($group_id && !$groupRepository->exists($group_id)) + return app('json')->fail('分组不存在'); + $this->repository->batchChangeGroupId($ids, $group_id); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function changeGroupForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeGroupForm($id))); + } + + /** + * @param $id + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function changeNowMoneyForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeNowMoneyForm($id))); + } + + public function changeIntegralForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeIntegralForm($id))); + } + + /** + * @param $id + * @param UserNowMoneyValidate $validate + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function changeNowMoney($id, UserNowMoneyValidate $validate) + { + $data = $this->request->params(['now_money', 'type']); + $validate->check($data); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->changeNowMoney($id, $this->request->adminId(), $data['type'], $data['now_money']); + + return app('json')->success('修改成功'); + } + + public function changeIntegral($id, UserNowMoneyValidate $validate) + { + $data = $this->request->params(['now_money', 'type']); + $validate->check($data); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->changeIntegral($id, $this->request->adminId(), $data['type'], $data['now_money']); + + return app('json')->success('修改成功'); + } + + /** + * @param WechatNewsRepository $wechatNewsRepository + * @param WechatUserRepository $wechatUserRepository + * @return mixed + * @author xaboy + * @day 2020-05-11 + */ + public function sendNews(WechatNewsRepository $wechatNewsRepository, WechatUserRepository $wechatUserRepository) + { + $ids = $this->request->param('ids'); + if (!is_array($ids)) $ids = explode(',', $this->request->param('ids')); + $ids = array_filter(array_unique($ids)); + $news_id = (int)$this->request->param('news_id', 0); + if (!$news_id) + return app('json')->fail('请选择图文消息'); + if (!$wechatNewsRepository->exists($news_id)) + return app('json')->fail('数据不存在'); + if (!count($ids)) + return app('json')->fail('请选择微信用户'); + $wechatUserRepository->sendNews($news_id, $ids); + return app('json')->success('发送成功'); + } + + public function promoterList() + { + $where = $this->request->params(['keyword', 'date', 'brokerage_level']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->promoterList($where, $page, $limit)); + } + + public function promoterCount() + { + return app('json')->success($this->repository->promoterCount()); + } + + public function detail($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->userOrderDetail($id)); + } + + public function order($id, StoreOrderRepository $repository) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->userList($id, $page, $limit)); + } + + public function coupon($id, StoreCouponUserRepository $repository) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->userList(['uid' => $id], $page, $limit)); + } + + public function bill($id, UserBillRepository $repository) + { + if (!$this->repository->exists(intval($id))) + return app('json')->fail('数据不存在'); + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->userList([ + 'now_money' => 0, + 'status' => 1 + ], $id, $page, $limit)); + } + + public function spreadLog($id) + { + if (!$this->repository->exists((int)$id)) + return app('json')->fail('数据不存在'); + [$page, $limit] = $this->getPage(); + return app('json')->success(app()->make(UserSpreadLogRepository::class)->getList(['uid' => $id], $page, $limit)); + } + + public function spreadForm($id) + { + if (!$this->repository->exists((int)$id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeSpreadForm($id))); + } + + public function spread($id) + { + if (!$this->repository->exists((int)$id)) + return app('json')->fail('数据不存在'); + $spid = $this->request->param('spid'); + $spid = (int)($spid['id'] ?? $spid); + if ($spid == $id) + return app('json')->fail('不能选自己'); + if ($spid && !$this->repository->exists($spid)) + return app('json')->fail('推荐人不存在'); + $this->repository->changeSpread($id, $spid, $this->request->adminId()); + return app('json')->success('修改成功'); + } + + public function searchLog() + { + $where = $this->request->params(['date', 'keyword', 'nickname', 'user_type']); + $merId = $this->request->merId(); + $where['type'] = ['searchMerchant', 'searchProduct']; + if ($merId) { + $where['mer_id'] = $merId; + } + [$page, $limit] = $this->getPage(); + return app('json')->success(app()->make(UserVisitRepository::class)->getSearchLog($where, $page, $limit)); + } + + public function exportSearchLog() + { + $where = $this->request->params(['date', 'keyword', 'nickname', 'user_type']); + $merId = $this->request->merId(); + $where['type'] = ['searchMerchant', 'searchProduct']; + if ($merId) { + $where['mer_id'] = $merId; + } + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->searchLog($where, $page, $limit); + return app('json')->success($data); + + } + + public function memberForm($id) + { + return app('json')->success(formToData($this->repository->memberForm($id,1))); + } + + public function memberSave($id) + { + $data = $this->request->params(['member_level']); + if (!$this->repository->exists((int)$id)) + return app('json')->fail('数据不存在'); + $this->repository->updateLevel($id, $data, 1); + return app('json')->success('修改成功'); + } + + public function spreadLevelForm($id) + { + return app('json')->success(formToData($this->repository->memberForm($id,0))); + } + + public function spreadLevelSave($id) + { + $brokerage_level = $this->request->params(['brokerage_level']); + if (!$this->repository->exists((int)$id)) + return app('json')->fail('数据不存在'); + $this->repository->updateLevel($id, $brokerage_level, 0); + return app('json')->success('修改成功'); + } + + public function svipForm($id) + { + return app('json')->success(formToData($this->repository->svipForm($id))); + } + + public function svipUpdate($id) + { + $data = $this->request->params(['is_svip','add_time','type']); + $this->repository->svipUpdate($id, $data,$this->request->adminId()); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/admin/user/UserBill.php b/app/controller/admin/user/UserBill.php new file mode 100644 index 00000000..1e63e5a5 --- /dev/null +++ b/app/controller/admin/user/UserBill.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use app\common\repositories\store\ExcelRepository; +use crmeb\basic\BaseController; +use app\common\repositories\user\UserBillRepository; +use crmeb\services\ExcelService; +use think\App; + +class UserBill extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBillRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'date', 'type']); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function type() + { + return app('json')->success($this->repository->type()); + } + + + public function export() + { + $where = $this->request->params(['keyword', 'date', 'type']); + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->bill($where,$page,$limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/user/UserBrokerage.php b/app/controller/admin/user/UserBrokerage.php new file mode 100644 index 00000000..e7263c9f --- /dev/null +++ b/app/controller/admin/user/UserBrokerage.php @@ -0,0 +1,126 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use app\common\repositories\user\UserBrokerageRepository; +use app\validate\admin\UserBrokerageValidate; +use crmeb\basic\BaseController; +use think\App; + +class UserBrokerage extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBrokerageRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function options() + { + $where = $this->request->params(['type']); + return app('json')->success($this->repository->options($where)); + } + + public function getLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['brokerage_name','type']); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + public function create() + { + $data = $this->checkParams(); + if ($this->repository->fieldExists('brokerage_level', $data['brokerage_level'],null, $data['type'])) { + return app('json')->fail('会员等级已存在'); + } + + if ($data['type']) { + $data['brokerage_rule'] = [ + 'image' => $data['image'], + 'value' => $data['value'], + ]; + } + unset($data['image'], $data['value']); + + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $id = (int)$id; + $data = $this->checkParams(); + if (!$id || !$this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + if ($this->repository->fieldExists('brokerage_level', $data['brokerage_level'], $id, $data['type'])) { + return app('json')->fail('会员等级已存在'); + } + + if ($data['type']) { + $data['brokerage_rule'] = [ + 'image' => $data['image'], + 'value' => $data['value'], + ]; + } + unset($data['image'], $data['value']); + + $data['brokerage_rule'] = json_encode($data['brokerage_rule'], JSON_UNESCAPED_UNICODE); + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + public function detail($id) + { + $id = (int)$id; + if (!$id || !$brokerage = $this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + return app('json')->success($brokerage->toArray()); + } + + public function delete($id) + { + $id = (int)$id; + if (!$id || !$brokerage = $this->repository->get($id)) { + return app('json')->fail('数据不存在'); + } + if ($brokerage->user_num > 0) { + return app('json')->fail('该等级下有数据,不能进行删除操作!'); + } + $brokerage->delete(); + return app('json')->success('删除成功'); + } + + public function checkParams() + { + $data = $this->request->params(['brokerage_level', 'brokerage_name', 'brokerage_icon', 'brokerage_rule', 'extension_one', 'extension_two', 'image', 'value', ['type',0]]); + app()->make(UserBrokerageValidate::class)->check($data); + return $data; + } +} diff --git a/app/controller/admin/user/UserExtract.php b/app/controller/admin/user/UserExtract.php new file mode 100644 index 00000000..eed007bc --- /dev/null +++ b/app/controller/admin/user/UserExtract.php @@ -0,0 +1,82 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\user; + +use app\common\repositories\store\ExcelRepository; +use crmeb\basic\BaseController; +use crmeb\services\ExcelService; +use think\App; +use app\validate\api\UserExtractValidate as validate; +use app\common\repositories\user\UserExtractRepository as repository; + +class UserExtract extends BaseController +{ + /** + * @var repository + */ + public $repository; + + /** + * UserExtract constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-16 + */ + public function lst() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['status','keyword','date','extract_type']); + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-16 + */ + public function switchStatus($id) + { + $data = $this->request->params(['status','fail_msg','mark']); + if($data['status'] == '-1' && empty($data['fail_msg'])) + return app('json')->fail('请填写拒绝原因'); + if(!$this->repository->getWhereCount($id)) + return app('json')->fail('数据不存在或状态错误'); + $data['admin_id'] = $this->request->adminId(); + $data['status_time'] = date('Y-m-d H:i:s',time()); + $this->repository->switchStatus($id,$data); + return app('json')->success('审核成功'); + } + + public function export() + { + $where = $this->request->params(['status','keyword','date','extract_type']); + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->extract($where,$page,$limit); + return app('json')->success($data); + } +} diff --git a/app/controller/admin/user/UserGroup.php b/app/controller/admin/user/UserGroup.php new file mode 100644 index 00000000..62ec1179 --- /dev/null +++ b/app/controller/admin/user/UserGroup.php @@ -0,0 +1,152 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserGroupRepository; +use app\validate\admin\UserGroupValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class UserGroup + * @package app\controller\admin\user + * @author xaboy + * @day 2020-05-07 + */ +class UserGroup extends BaseController +{ + /** + * @var UserGroupRepository + */ + protected $repository; + + /** + * UserGroup constructor. + * @param App $app + * @param UserGroupRepository $repository + */ + public function __construct(App $app, UserGroupRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList([], $page, $limit)); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param UserGroupValidate $validate + * @return mixed + * @author xaboy + * @day 2020-05-07 + */ + public function create(UserGroupValidate $validate) + { + $data = $this->checkParams($validate); + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param $id + * @param UserGroupValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function update($id, UserGroupValidate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function delete($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + + return app('json')->success('删除成功'); + } + + /** + * @param UserGroupValidate $validate + * @return array + * @author xaboy + * @day 2020-05-07 + */ + protected function checkParams(UserGroupValidate $validate) + { + $data = $this->request->params(['group_name']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/user/UserIntegral.php b/app/controller/admin/user/UserIntegral.php new file mode 100644 index 00000000..c2d3de8c --- /dev/null +++ b/app/controller/admin/user/UserIntegral.php @@ -0,0 +1,91 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\system\CacheRepository; +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\user\UserBillRepository; +use app\validate\admin\IntegralConfigValidate; +use crmeb\basic\BaseController; +use crmeb\services\ExcelService; +use think\App; + +class UserIntegral extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBillRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 积分日志 + * @return \think\response\Json + * @author Qinii + * @day 6/9/21 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'date']); + $where['category'] = 'integral'; + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 6/9/21 + */ + public function getTitle() + { + return app('json')->success($this->repository->getStat()); + } + + public function excel() + { + $where = $this->request->params(['keyword', 'date']); + $where['category'] = 'integral'; + + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->integralLog($where,$page,$limit); + return app('json')->success($data); + } + + public function getConfig() + { + $config = systemConfig(['integral_status', 'integral_clear_time', 'integral_order_rate', 'integral_freeze', 'integral_user_give', 'integral_money']); + $config = array_filter($config, function ($v) { + return $v !== ''; + }) + ['integral_status' => 0, 'integral_clear_time' => 0, 'integral_order_rate' => 0, 'integral_freeze' => 0, 'integral_user_give' => 0, 'integral_money' => 0]; + $config['rule'] = app()->make(CacheRepository::class)->getResultByKey(CacheRepository::INTEGRAL_RULE); + return app('json')->success($config); + } + + public function saveConfig(IntegralConfigValidate $validate) + { + $config = $this->request->params(['integral_status', 'integral_clear_time', 'integral_order_rate', 'integral_freeze', 'integral_user_give', 'integral_money', 'rule']); + $validate->check($config); + app()->make(CacheRepository::class)->save('sys_integral_rule', $config['rule']); + unset($config['rule']); + if (!($cid = app()->make(ConfigClassifyRepository::class)->keyById('integral'))) return app('json')->fail('保存失败'); + app()->make(ConfigValueRepository::class)->save($cid, $config, 0); + return app('json')->success('保存成功'); + } +} diff --git a/app/controller/admin/user/UserLabel.php b/app/controller/admin/user/UserLabel.php new file mode 100644 index 00000000..6d8fd284 --- /dev/null +++ b/app/controller/admin/user/UserLabel.php @@ -0,0 +1,160 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserLabelRepository; +use app\validate\admin\UserLabelValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class UserLabel + * @package app\controller\admin\user + * @author xaboy + * @day 2020-05-07 + */ +class UserLabel extends BaseController +{ + /** + * @var UserLabelRepository + */ + protected $repository; + + /** + * UserGroup constructor. + * @param App $app + * @param UserLabelRepository $repository + */ + public function __construct(App $app, UserLabelRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type', 'all']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-07 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param UserLabelValidate $validate + * @return mixed + * @author xaboy + * @day 2020-05-07 + */ + public function create(UserLabelValidate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->request->merId(); + if ($this->repository->existsName($data['label_name'], $data['mer_id'], 0)) + return app('json')->fail('标签名已存在'); + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-07 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param $id + * @param UserLabelValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function update($id, UserLabelValidate $validate) + { + $data = $this->checkParams($validate); + $merId = $this->request->merId(); + if (!$this->repository->exists($id, $merId)) + return app('json')->fail('数据不存在'); + if ($this->repository->existsName($data['label_name'], $merId, 0, $id)) + return app('json')->fail('标签名已存在'); + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-07 + */ + public function delete($id) + { + if (!$this->repository->exists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + + return app('json')->success('删除成功'); + } + + /** + * @param UserLabelValidate $validate + * @return array + * @author xaboy + * @day 2020-05-07 + */ + protected function checkParams(UserLabelValidate $validate) + { + $data = $this->request->params(['label_name']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/user/UserRecharge.php b/app/controller/admin/user/UserRecharge.php new file mode 100644 index 00000000..66e3b8d7 --- /dev/null +++ b/app/controller/admin/user/UserRecharge.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserRechargeRepository; +use think\App; + +class UserRecharge extends BaseController +{ + + protected $repository; + + public function __construct(App $app, UserRechargeRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getList() + { + $where = $this->request->params(['date', 'paid', 'keyword']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function total() + { + $totalRefundPrice = $this->repository->totalRefundPrice(); + $totalPayPrice = $this->repository->totalPayPrice(); + $totalRoutinePrice = $this->repository->totalRoutinePrice(); + $totalWxPrice = $this->repository->totalWxPrice(); + return app('json')->success(compact('totalWxPrice', 'totalRoutinePrice', 'totalPayPrice', 'totalRefundPrice')); + } +} diff --git a/app/controller/admin/wechat/TemplateMessage.php b/app/controller/admin/wechat/TemplateMessage.php new file mode 100644 index 00000000..35e17eb7 --- /dev/null +++ b/app/controller/admin/wechat/TemplateMessage.php @@ -0,0 +1,195 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\wechat; + +use think\App; +use crmeb\basic\BaseController; +use app\validate\admin\TemplateMessageValidate; +use app\common\repositories\wechat\TemplateMessageRepository; +use think\exception\ValidateException; + +class TemplateMessage extends BaseController +{ + /** + * @var TemplateMessageRepository + */ + protected $repository; + + /** + * TemplateMessage constructor. + * @param App $app + * @param TemplateMessageRepository $repository + */ + public function __construct(App $app, TemplateMessageRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function lst() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['status','keyword']); + $where['type'] = 1; + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function minList() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['status','keyword']); + $where['type'] = 0; + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null,1))); + } + + + /** + * TODO + * @param $type + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function createMinForm() + { + return app('json')->success(formToData($this->repository->form(null,0))); + } + + /** + * TODO + * @param TemplateMessageValidate $validate + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function create(TemplateMessageValidate $validate) + { + $data = $this->chekcParams($validate); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function updateForm($id) + { + if(!$this->repository->getWhereCount(['template_id' => $id])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function update($id) + { + $data = $this->request->params(['tempid','status']); + if(!$data['tempid']) + return app('json')->fail('请填写模板ID'); + if(!$this->repository->getWhereCount(['template_id' => $id])) + return app('json')->fail('数据不存在'); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function delete($id) + { + if(!$this->repository->getWhereCount(['template_id' => $id])) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function switchStatus($id) + { + $status = $this->request->param('status',0) == 1 ? 1:0; + if(!$this->repository->getWhereCount(['template_id' => $id])) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + + /** + * TODO + * @param TemplateMessageValidate $validate + * @return array + * @author Qinii + * @day 2020-06-18 + */ + public function chekcParams(TemplateMessageValidate $validate) + { + $data = $this->request->params(['tempkey','name','tempid','status','content','type']); + $validate->check($data); + return $data; + } + + public function sync() + { + $type = $this->request->param('type'); + if ($type){ + $msg = $this->repository->syncWechatSubscribe(); + } else { + $msg = $this->repository->syncMinSubscribe(); + } + return app('json')->success($msg); + } + + +} diff --git a/app/controller/admin/wechat/WechatGroup.php b/app/controller/admin/wechat/WechatGroup.php new file mode 100644 index 00000000..4a9a908a --- /dev/null +++ b/app/controller/admin/wechat/WechatGroup.php @@ -0,0 +1,113 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\wechat; + + +use crmeb\basic\BaseController; +use crmeb\services\WechatUserGroupService; +use crmeb\services\WechatUserTagService; +use FormBuilder\Exception\FormBuilderException; +use think\App; + +/** + * Class WechatGroup + * @package app\controller\admin\wechat + * @author xaboy + * @day 2020-04-27 + */ +class WechatGroup extends BaseController +{ + /** + * @var WechatUserGroupService + */ + protected $service; + + /** + * WechatTag constructor. + * @param App $app + * @param WechatUserGroupService $service + */ + public function __construct(App $app, WechatUserGroupService $service) + { + parent::__construct($app); + $this->service = $service; + } + + public function lst() + { + return app('json')->success($this->service->lst()); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-27 + */ + public function createForm() + { + return app('json')->success(formToData($this->service->form())); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function create() + { + $name = $this->request->param('group_name'); + if (!$name) return app('json')->fail('请输入分组名称'); + $this->service->create($name); + return app('json')->success('添加成功'); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function update($id) + { + $name = $this->request->param('group_name'); + if (!$name) return app('json')->fail('请输入分组名称'); + $this->service->update($id, $name); + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-27 + */ + public function updateForm($id) + { + return app('json')->success(formToData($this->service->form($id, ''))); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function delete($id) + { + $this->service->delete($id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/wechat/WechatMenu.php b/app/controller/admin/wechat/WechatMenu.php new file mode 100644 index 00000000..111c5df5 --- /dev/null +++ b/app/controller/admin/wechat/WechatMenu.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\wechat; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\CacheRepository; +use crmeb\services\WechatService; +use Exception; +use think\db\exception\DbException; + +/** + * Class WechatMenu + * @package app\controller\admin\wechat + * @author xaboy + * @day 2020-04-24 + */ +class WechatMenu extends BaseController +{ + /** + * @param CacheRepository $repository + * @return mixed + * @author xaboy + * @day 2020-04-24 + */ + public function info(CacheRepository $repository) + { + $data['wechat_menus'] = $repository->getResultByKey('wechat_menus') ?? []; + return app('json')->success($data); + } + + /** + * @param CacheRepository $repository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-24 + */ + public function save(CacheRepository $repository) + { + $buttons = (array)$this->request->param('button', []); + if (!count($buttons)) return app('json')->fail('请添加至少一个按钮'); + + try { + WechatService::create()->getApplication()->menu->add($buttons); + } catch (Exception $e) { + return app('json')->fail('设置失败:' . $e->getMessage()); + } + $repository->save('wechat_menus', $buttons); + return app('json')->success('设置成功'); + } +} diff --git a/app/controller/admin/wechat/WechatNews.php b/app/controller/admin/wechat/WechatNews.php new file mode 100644 index 00000000..8c38a0da --- /dev/null +++ b/app/controller/admin/wechat/WechatNews.php @@ -0,0 +1,104 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\admin\wechat; + +use crmeb\basic\BaseController; +use app\common\repositories\wechat\WechatNewsRepository; +use app\validate\admin\WechatNewsValidate; +use think\App; +use think\Request; + +class WechatNews extends BaseController +{ + + /** + * @var WechatNewsRepository + */ + protected $repositories; + + /** + * WechatNews constructor. + * @param App $app + * @param WechatNewsRepository $repository + */ + public function __construct(App $app,WechatNewsRepository $repository) + { + parent::__construct($app); + $this->repositories = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where['cate_name'] = $this->request->param('cate_name'); + $result = $this->repositories->search($where, $page, $limit); + return app('json')->success($result); + } + + /** + * 添加 + * @param WechatNewsValidate $validate + * @return mixed + * @author Qinii + */ + public function create(WechatNewsValidate $validate) + { + $data =$this->checkParams($validate,true); + $this->repositories->create($data,$this->request->merId(),$this->request->adminId()); + return app('json')->success('添加成功'); + } + + /** + * 编辑 + * @param $id + * @param WechatNewsValidate $validate + * @return mixed + * @author Qinii + */ + public function update($id,WechatNewsValidate $validate) + { + $data =$this->checkParams($validate); + if (!$this->repositories->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repositories->update($id,$data,$this->request->merId(),$this->request->adminId()); + return app('json')->success('编辑成功'); + } + + public function delete($id) + { + if (!$this->repositories->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repositories->delete($id,$this->request->merId()); + return app('json')->success('删除成功'); + } + + public function detail($id) + { + if (!$this->repositories->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repositories->git($id,$this->request->merId())); + } + /** + * 验证 + * @param WechatNewsValidate $validate + * @param bool $isCreate + * @return array + * @author Qinii + */ + public function checkParams(WechatNewsValidate $validate) + { + $data = $this->request->params(['status','data']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/admin/wechat/WechatReply.php b/app/controller/admin/wechat/WechatReply.php new file mode 100644 index 00000000..cb1ee00c --- /dev/null +++ b/app/controller/admin/wechat/WechatReply.php @@ -0,0 +1,204 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\wechat; + + +use crmeb\basic\BaseController; +use app\common\repositories\wechat\WechatReplyRepository; +use app\validate\admin\WechatReplyValidate; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Filesystem; + +/** + * Class WechatReply + * @package app\controller\admin\wechat + * @author xaboy + * @day 2020-04-24 + */ +class WechatReply extends BaseController +{ + /** + * @var WechatReplyRepository + */ + protected $repository; + + /** + * WechatReply constructor. + * @param App $app + * @param WechatReplyRepository $repository + */ + public function __construct(App $app, WechatReplyRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword']); + + return app('json')->success($this->repository->getLst($where, $page, $limit)); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function info($id) + { + $type = $this->request->param('type', 0); + $reply = !$type ? $this->repository->get((int)$id) : $this->repository->keyByReply($id); + if ($reply) + return app('json')->success($reply->toArray()); + else + return app('json')->fail('数据不存在'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-24 + */ + public function changeStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status == 1 ? 1 : 0]); + return app('json')->success('修改成功'); + } + + /** + * @param WechatReplyValidate $validate + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function create(WechatReplyValidate $validate) + { + $data = $this->request->params(['key', 'type', 'data', 'status']); + $validate->check($data); + if ($this->repository->fieldExists('key', $data['key'])) + return app('json')->fail('关键字已存在'); + $this->repository->create($data); + return app('json')->success('保存成功'); + } + + /** + * @param $id + * @param WechatReplyValidate $validate + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-27 + */ + public function update($id, WechatReplyValidate $validate) + { + $data = $this->request->params(['key', 'type', 'data', 'status']); + $validate->check($data); + if ($this->repository->fieldExists('key', $data['key'], $id)) + return app('json')->fail('关键字已存在'); + $this->repository->updateReply($id, $data); + return app('json')->success('保存成功'); + } + + /** + * @param string $key + * @param WechatReplyValidate $validate + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-24 + */ + public function save($key, WechatReplyValidate $validate) + { + [$type, $data, $status] = $this->request->params(['type', 'data', 'status'], true); + $validate->isUpdate()->check(compact('type', 'data', 'status')); + if (!in_array($key, ['default', 'subscribe'])) + return app('json')->fail('修改失败'); + $this->repository->save($key, $type, (array)$data, $status == 1 ? 1 : 0, 1); + return app('json')->success('保存成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-24 + */ + public function delete($id) + { + $this->repository->delete($id); + + return app('json')->success('删除成功'); + } + + public function uploadImage() + { + $file = $this->request->file('file'); + if (!$file) + return app('json')->fail('请上传图片'); + $file = is_array($file) ? $file[0] : $file; + + validate(["file|图片" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'jpg,jpeg,png,bmp,gif', + 'fileMime' => 'image/jpeg,image/png,image/gif', + ]])->check(['file' => $file]); + + $path = Filesystem::putFile('wechat/img', $file, 'md5'); + return app('json')->success(['src' => '/uploads/' . $path]); + } + + public function uploadVoice() + { + $file = $this->request->file('file'); + if (!$file) + return app('json')->fail('请上传声音'); + $file = is_array($file) ? $file[0] : $file; + validate(["file|声音" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'wav,aif,mp3', + 'fileMime' => 'audio/x-wav,audio/x-aiff,audio/x-mpeg,audio/mpeg,audio/wav,audio/aiff', + ]])->check(['file' => $file]); + + $path = Filesystem::putFile('wechat/voice', $file, 'md5'); + return app('json')->success(['src' => '/uploads/' . $path]); + } + +} diff --git a/app/controller/admin/wechat/WechatTag.php b/app/controller/admin/wechat/WechatTag.php new file mode 100644 index 00000000..591228bf --- /dev/null +++ b/app/controller/admin/wechat/WechatTag.php @@ -0,0 +1,112 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\wechat; + + +use crmeb\basic\BaseController; +use crmeb\services\WechatUserTagService; +use FormBuilder\Exception\FormBuilderException; +use think\App; + +/** + * Class WechatTag + * @package app\controller\admin\wechat + * @author xaboy + * @day 2020-04-27 + */ +class WechatTag extends BaseController +{ + /** + * @var WechatUserTagService + */ + protected $service; + + /** + * WechatTag constructor. + * @param App $app + * @param WechatUserTagService $service + */ + public function __construct(App $app, WechatUserTagService $service) + { + parent::__construct($app); + $this->service = $service; + } + + public function lst() + { + return app('json')->success($this->service->lst()); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-27 + */ + public function createForm() + { + return app('json')->success(formToData($this->service->form())); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function create() + { + $name = $this->request->param('tag_name'); + if (!$name) return app('json')->fail('请输入标签名称'); + $this->service->create($name); + return app('json')->success('添加成功'); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function update($id) + { + $name = $this->request->param('tag_name'); + if (!$name) return app('json')->fail('请输入标签名称'); + $this->service->update($id, $name); + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-27 + */ + public function updateForm($id) + { + return app('json')->success(formToData($this->service->form($id, ''))); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020-04-27 + */ + public function delete($id) + { + $this->service->delete($id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/admin/wechat/WechatUser.php b/app/controller/admin/wechat/WechatUser.php new file mode 100644 index 00000000..68832f88 --- /dev/null +++ b/app/controller/admin/wechat/WechatUser.php @@ -0,0 +1,181 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\admin\wechat; + + +use crmeb\basic\BaseController; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\services\WechatUserGroupService; +use crmeb\services\WechatUserTagService; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class WechatUser + * @package app\controller\admin\wechat + * @author xaboy + * @day 2020-04-29 + */ +class WechatUser extends BaseController +{ + /** + * @var WechatUserRepository + */ + protected $repository; + + /** + * WechatUser constructor. + * @param App $app + * @param WechatUserRepository $repository + */ + public function __construct(App $app, WechatUserRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function lst() + { + $where = $this->request->params([ + ['page', 1], + ['limit', 20], + ['nickname', ''], + ['tagid_list', ''], + ['groupid', '-1'], + ['sex', ''], + ['export', ''], + ['subscribe', ''] + ]); + $where['tagid_list'] = implode(',', array_filter(array_unique(explode(',', $where['tagid_list'])))); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param $id + * @param WechatUserTagService $service + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function syncTag($id, WechatUserTagService $service) + { + $user = $this->repository->get($id); + if (!$user) + return app('json')->fail('数据不存在'); + $tag = $service->userTags($user->openid); + if ($tag['tagid_list']) $data['tagid_list'] = implode(',', $tag['tagid_list']); + else $data['tagid_list'] = ''; + $user->save($tag); + return app('json')->success('同步成功'); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function tagForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateUserTagForm($id))); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function tag($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $tags = explode(',', $this->request->param('tag_id')); + $this->repository->updateTag($id, $tags); + return app('json')->success('操作成功'); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function groupForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateUserGroupForm($id))); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-29 + */ + public function group($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $groupId = $this->request->param('group_id'); + $this->repository->updateGroup($id, $groupId); + return app('json')->success('操作成功'); + } + + /** + * @param WechatUserTagService $wechatUserTagService + * @param WechatUserGroupService $wechatUserGroupService + * @return mixed + * @author xaboy + * @day 2020-04-29 + */ + public function tagGroup(WechatUserTagService $wechatUserTagService, WechatUserGroupService $wechatUserGroupService) + { + $groupList = $wechatUserGroupService->lst(); + $tagList = $wechatUserTagService->lst(); + return app('json')->success(compact('groupList', 'tagList')); + } +} diff --git a/app/controller/api/Auth.php b/app/controller/api/Auth.php new file mode 100644 index 00000000..928d8fdb --- /dev/null +++ b/app/controller/api/Auth.php @@ -0,0 +1,721 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\user\UserSignRepository; +use app\common\repositories\wechat\RoutineQrcodeRepository; +use app\common\repositories\wechat\WechatUserRepository; +use app\validate\api\ChangePasswordValidate; +use app\validate\api\UserAuthValidate; +use crmeb\basic\BaseController; +use crmeb\services\MiniProgramService; +use crmeb\services\SmsService; +use crmeb\services\WechatService; +use crmeb\services\WechatTemplateMessageService; +use Exception; +use Firebase\JWT\JWT; +use Gregwar\Captcha\CaptchaBuilder; +use Gregwar\Captcha\PhraseBuilder; +use Overtrue\Socialite\AccessToken; +use Symfony\Component\HttpFoundation\Request; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Log; +use think\facade\Queue; +use crmeb\jobs\SendSmsJob; + +/** + * Class Auth + * @package app\controller\api + * @author xaboy + * @day 2020-05-06 + */ +class Auth extends BaseController +{ + public function test() + { +// $data = [ +// 'tempId' => '', +// 'id' => '', +// ]; +// Queue::push(SendSmsJob::class,$data); +// $status = app()->make(SystemNoticeConfigRepository::class)->getNoticeStatusByConstKey($data['tempId']); +// if ($status['notice_sms'] == 1) { +// SmsService::sendMessage($data); +// } +// if ($status['notice_wechat'] == 1) { +// app()->make(WechatTemplateMessageService::class)->sendTemplate($data); +// } +// if ($status['notice_routine'] == 1) { +// app()->make(WechatTemplateMessageService::class)->subscribeSendTemplate($data); +// } + } + + /** + * @param UserRepository $repository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/6/1 + */ + public function login(UserRepository $repository) + { + $account = $this->request->param('account'); + $auth_token = $this->request->param('auth_token'); + if (Cache::get('api_login_freeze_' . $account)) + return app('json')->fail('账号或密码错误次数太多,请稍后在尝试'); + if (!$account) + return app('json')->fail('请输入账号'); + $user = $repository->accountByUser($this->request->param('account')); +// if($auth_token && $user){ +// return app('json')->fail('用户已存在'); +// } + if (!$user) $this->loginFailure($account); + if (!password_verify($pwd = (string)$this->request->param('password'), $user['pwd'])) $this->loginFailure($account); + $auth = $this->parseAuthToken($auth_token); + if ($auth && !$user['wechat_user_id']) { + $repository->syncBaseAuth($auth, $user); + } + $user = $repository->mainUser($user); + $pid = $this->request->param('spread', 0); + $repository->bindSpread($user, intval($pid)); + + $tokenInfo = $repository->createToken($user); + $repository->loginAfter($user); + + return app('json')->success($repository->returnToken($user, $tokenInfo)); + } + + /** + * TODO 登录尝试次数限制 + * @param $account + * @param int $number + * @param int $n + * @author Qinii + * @day 7/6/21 + */ + public function loginFailure($account, $number = 5, $n = 3) + { + $key = 'api_login_failuree_' . $account; + $numb = Cache::get($key) ?? 0; + $numb++; + if ($numb >= $number) { + $fail_key = 'api_login_freeze_' . $account; + Cache::set($fail_key, 1, 15 * 60); + throw new ValidateException('账号或密码错误次数太多,请稍后在尝试'); + + } else { + Cache::set($key, $numb, 5 * 60); + + $msg = '账号或密码错误'; + $_n = $number - $numb; + if ($_n <= $n) { + $msg .= ',还可尝试' . $_n . '次'; + } + throw new ValidateException($msg); + } + } + + + /** + * @return mixed + * @author xaboy + * @day 2020/6/1 + */ + public function userInfo() + { + $user = $this->request->userInfo()->hidden(['label_id', 'group_id', 'pwd', 'addres', 'card_id', 'last_time', 'last_ip', 'create_time', 'mark', 'status', 'spread_uid', 'spread_time', 'real_name', 'birthday', 'brokerage_price']); + $user->append(['service', 'topService', 'total_collect_product', 'total_collect_store', 'total_coupon', 'total_visit_product', 'total_unread', 'total_recharge', 'lock_integral', 'total_integral']); + $data = $user->toArray(); + $data['total_consume'] = $user['pay_price']; + $data['extension_status'] = systemConfig('extension_status'); + if (systemConfig('member_status')) + $data['member_icon'] = $this->request->userInfo()->member->brokerage_icon ?? ''; + if ($data['is_svip'] == 3) + $data['svip_endtime'] = date('Y-m-d H:i:s',strtotime("+100 year")); + + $day = date('Y-m-d',time()); + $key = 'sign_'.$user['uid'].'_'.$day; + $data['sign_status'] = false; + if (Cache::get($key)) { + $data['sign_status'] = true; + } else { + $nu = app()->make(UserSignRepository::class)->getSign($user->uid,$day); + if ($nu) { + $data['sign_status'] = true; + Cache::set($key,true, new \DateTime($day.' 23:59:59')); + } + } + return app('json')->success($data); + } + + /** + * @param UserRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/1 + */ + public function logout(UserRepository $repository) + { + $repository->clearToken($this->request->token()); + return app('json')->success('退出登录'); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-11 + */ + public function auth() + { + if (systemConfig('is_phone_login') === '1') { + return app('json')->fail('请绑定手机号'); + } + + $request = $this->request; + $oauth = WechatService::create()->getApplication()->oauth; + $oauth->setRequest(new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent())); + try { + $wechatInfo = $oauth->user()->getOriginal(); + } catch (Exception $e) { + return app('json')->fail('授权失败[001]', ['message' => $e->getMessage()]); + } + if (!isset($wechatInfo['nickname'])) { + return app('json')->fail('授权失败[002]'); + } + /** @var WechatUserRepository $make */ + $make = app()->make(WechatUserRepository::class); + + $user = $make->syncUser($wechatInfo['openid'], $wechatInfo); + if (!$user) + return app('json')->fail('授权失败[003]'); + /** @var UserRepository $make */ + $userRepository = app()->make(UserRepository::class); + $user[1] = $userRepository->mainUser($user[1]); + + $pid = $this->request->param('spread', 0); + $userRepository->bindSpread($user[1], intval($pid)); + + $tokenInfo = $userRepository->createToken($user[1]); + $userRepository->loginAfter($user[1]); + + return app('json')->success($userRepository->returnToken($user[1], $tokenInfo)); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-11 + */ + public function mpAuth() + { + list($code, $post_cache_key) = $this->request->params([ + 'code', + 'cache_key', + ], true); + + if (systemConfig('is_phone_login') === '1') { + return app('json')->fail('请绑定手机号'); + } + + $userInfoCong = Cache::get('eb_api_code_' . $code); + if (!$code && !$userInfoCong) + return app('json')->fail('授权失败,参数有误'); + $miniProgramService = MiniProgramService::create(); + if ($code && !$userInfoCong) { + try { + $userInfoCong = $miniProgramService->getUserInfo($code); + Cache::set('eb_api_code_' . $code, $userInfoCong, 86400); + } catch (Exception $e) { + return app('json')->fail('获取session_key失败,请检查您的配置!', ['line' => $e->getLine(), 'message' => $e->getMessage()]); + } + } + + $data = $this->request->params([ + ['spread_spid', 0], + ['spread_code', ''], + ['iv', ''], + ['encryptedData', ''], + ]); + + try { + //解密获取用户信息 + $userInfo = $miniProgramService->encryptor($userInfoCong['session_key'], $data['iv'], $data['encryptedData']); + } catch (Exception $e) { + if ($e->getCode() == '-41003') return app('json')->fail('获取会话密匙失败'); + throw $e; + } + if (!$userInfo) return app('json')->fail('openid获取失败'); + if (!isset($userInfo['openId'])) $userInfo['openId'] = $userInfoCong['openid'] ?? ''; + $userInfo['unionId'] = $userInfoCong['unionid'] ?? $userInfo['unionId'] ?? ''; + if (!$userInfo['openId']) return app('json')->fail('openid获取失败'); + + /** @var WechatUserRepository $make */ + $make = app()->make(WechatUserRepository::class); + $user = $make->syncRoutineUser($userInfo['openId'], $userInfo); + if (!$user) + return app('json')->fail('授权失败'); + /** @var UserRepository $make */ + $userRepository = app()->make(UserRepository::class); + $user[1] = $userRepository->mainUser($user[1]); + $code = intval($data['spread_code']['id'] ?? $data['spread_code']); + //获取是否有扫码进小程序 + if ($code && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($code))) { + $data['spread_spid'] = $info['third_id']; + } + $userRepository->bindSpread($user[1], intval($data['spread_spid'])); + $tokenInfo = $userRepository->createToken($user[1]); + $userRepository->loginAfter($user[1]); + + return app('json')->success($userRepository->returnToken($user[1], $tokenInfo)); + } + + public function getCaptcha() + { + $codeBuilder = new CaptchaBuilder(null, new PhraseBuilder(4)); + $key = uniqid(microtime(true), true); + Cache::set('api_captche' . $key, $codeBuilder->getPhrase(), 300); + $captcha = $codeBuilder->build()->inline(); + return app('json')->success(compact('key', 'captcha')); + } + + protected function checkCaptcha($uni, string $code): bool + { + $cacheName = 'api_captche' . $uni; + if (!Cache::has($cacheName)) return false; + $key = Cache::get($cacheName); + $res = strtolower($key) == strtolower($code); + if ($res) Cache::delete($cacheName); + return $res; + } + + public function verify(UserAuthValidate $validate) + { + $data = $this->request->params(['phone', ['type', 'login'],['captchaType', ''], ['captchaVerification', ''],'token']); + //二次验证 + try { + aj_captcha_check_two($data['captchaType'], $data['captchaVerification']); + } catch (\Throwable $e) { + return app('json')->fail($e->getMessage()); + } + $validate->sceneVerify()->check($data); + $sms_limit_key = 'sms_limit_' . $data['phone']; + $limit = Cache::get($sms_limit_key) ? Cache::get($sms_limit_key) : 0; + $sms_limit = systemConfig('sms_limit'); + if ($sms_limit && $limit > $sms_limit) { + return app('json')->fail('请求太频繁请稍后再试'); + } +// if(!env('APP_DEBUG', false)){ + try { + $sms_code = str_pad(random_int(1, 9999), 4, 0, STR_PAD_LEFT); + $sms_time = systemConfig('sms_time') ? systemConfig('sms_time') : 30; + SmsService::create()->send($data['phone'], 'VERIFICATION_CODE', ['code' => $sms_code, 'time' => $sms_time]); + } catch (Exception $e) { + return app('json')->fail($e->getMessage()); + } +// }else{ +// $sms_code = 1234; +// $sms_time = 5; +// } + $sms_key = app()->make(SmsService::class)->sendSmsKey($data['phone'], $data['type']); + Cache::set($sms_key, $sms_code, $sms_time * 60); + Cache::set($sms_limit_key, $limit + 1, 60); + //'短信发送成功' + return app('json')->success('短信发送成功'); + } + + + public function smsLogin(UserAuthValidate $validate, UserRepository $repository) + { + $data = $this->request->params(['phone', 'sms_code', 'spread', 'auth_token',['user_type','h5']]); + $validate->sceneSmslogin()->check($data); + $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'login'); + if (!$sms_code) return app('json')->fail('验证码不正确'); + $user = $repository->accountByUser($data['phone']); + $auth = $this->parseAuthToken($data['auth_token']); + if (!$user) $user = $repository->registr($data['phone'], null, $data['user_type']); + if ($auth && !$user['wechat_user_id']){ + $repository->syncBaseAuth($auth, $user); + } + $user = $repository->mainUser($user); + $repository->bindSpread($user, intval($data['spread'])); + + $tokenInfo = $repository->createToken($user); + $repository->loginAfter($user); + + return app('json')->success($repository->returnToken($user, $tokenInfo)); + } + + public function changePassword(ChangePasswordValidate $validate, UserRepository $repository) + { + $data = $this->request->params(['phone', 'sms_code', 'pwd']); + $validate->check($data); + $user = $repository->accountByUser($data['phone']); + if (!$user) return app('json')->fail('用户不存在'); + $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'change_pwd'); + if (!$sms_code) + return app('json')->fail('验证码不正确'); + $user->pwd = $repository->encodePassword($data['pwd']); + $user->save(); + return app('json')->success('修改成功'); + } + + public function spread(UserRepository $userRepository) + { + $data = $this->request->params([ + ['spread_spid', 0], + ['spread_code', null], + ]); + if (isset($data['spread_code']['id']) && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($data['spread_code']['id']))) { + $data['spread_spid'] = $info['third_id']; + } + $userRepository->bindSpread($this->request->userInfo(), intval($data['spread_spid'])); + return app('json')->success(); + } + + /** + * TODO 注册账号 + * @param UserAuthValidate $validate + * @param UserRepository $repository + * @return \think\response\Json + * @author Qinii + * @day 5/27/21 + */ + public function register(UserAuthValidate $validate, UserRepository $repository) + { + $data = $this->request->params(['phone', 'sms_code', 'spread', 'pwd', 'auth_token',['user_type','h5']]); + $validate->check($data); + $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'login'); + if (!$sms_code) + return app('json')->fail('验证码不正确'); + $user = $repository->accountByUser($data['phone']); + if ($user) return app('json')->fail('用户已存在'); + $auth = $this->parseAuthToken($data['auth_token']); + $user = $repository->registr($data['phone'], $data['pwd'], $data['user_type']); + if ($auth){ + $repository->syncBaseAuth($auth, $user); + } + $user = $repository->mainUser($user); + $repository->bindSpread($user, intval($data['spread'])); + + $tokenInfo = $repository->createToken($user); + $repository->loginAfter($user); + + return app('json')->success($repository->returnToken($user, $tokenInfo)); + } + + private function parseAuthToken($authToken) + { + $auth = Cache::get('u_try' . $authToken); + $auth && Cache::delete('u_try' . $authToken); + return $auth; + } + + private function authInfo($auth, $createUser = false) + { + if (!in_array($auth['type'] ?? '', ['wechat', 'routine', 'apple', 'app_wechat']) || !isset($auth['auth'])) + throw new ValidateException('授权信息类型有误'); + $data = $auth['auth']; + if ($auth['type'] === 'routine') { + $code = $data['code'] ?? ''; + $userInfoCong = Cache::get('eb_api_code_' . $code); + if (!$code && !$userInfoCong) + throw new ValidateException('授权失败,参数有误'); + $miniProgramService = MiniProgramService::create(); + if ($code && !$userInfoCong) { + try { + $userInfoCong = $miniProgramService->getUserInfo($code); + Cache::set('eb_api_code_' . $code, $userInfoCong, 86400); + } catch (Exception $e) { + throw new ValidateException('获取session_key失败,请检查您的配置!'); + } + } + try { + //解密获取用户信息 + $userInfo = $miniProgramService->encryptor($userInfoCong['session_key'], $data['iv'], $data['encryptedData']); + } catch (Exception $e) { + if ($e->getCode() == '-41003') throw new ValidateException('获取会话密匙失败'); + throw $e; + } + if (!$userInfo) throw new ValidateException('openid获取失败'); + if (!isset($userInfo['openId'])) $userInfo['openId'] = $userInfoCong['openid'] ?? ''; + $userInfo['unionId'] = $userInfoCong['unionid'] ?? $userInfo['unionId'] ?? ''; + if (!$userInfo['openId']) throw new ValidateException('openid获取失败'); + + /** @var WechatUserRepository $make */ + $make = app()->make(WechatUserRepository::class); + $user = $make->syncRoutineUser($userInfo['openId'], $userInfo, $createUser); + if (!$user) + throw new ValidateException('授权失败'); + return $user; + } else if ($auth['type'] === 'wechat') { + $request = $this->request; + $oauth = WechatService::create()->getApplication()->oauth; + $oauth->setRequest(new Request($data, $data, [], [], [], $request->server(), $request->getContent())); + try { + $wechatInfo = $oauth->user()->getOriginal(); + } catch (Exception $e) { + throw new ValidateException('授权失败[001]'); + } + if (!isset($wechatInfo['nickname'])) { + throw new ValidateException('授权失败[002]'); + } + /** @var WechatUserRepository $make */ + $make = app()->make(WechatUserRepository::class); + + $user = $make->syncUser($wechatInfo['openid'], $wechatInfo, false, $createUser); + if (!$user) + throw new ValidateException('授权失败[003]'); + return $user; + } else if ($auth['type'] === 'app_wechat') { + $oauth = WechatService::create()->getApplication()->oauth; + try { + $wechatInfo = $oauth->user(new AccessToken(['access_token'=>$data['code'],'openid'=>$data['openid']]))->getOriginal(); + } catch (Exception $e) { + throw new ValidateException('授权失败[001]'.$e->getMessage()); + } + $user = app()->make(WechatUserRepository::class)->syncAppUser($wechatInfo['unionid'], $wechatInfo, 'App', $createUser); + if (!$user) + throw new ValidateException('授权失败'); + return $user; + } else if ($auth['type'] === 'apple') { + $identityToken = $data['userInfo']['identityToken']; + $tks = explode('.', $identityToken); + if (count($tks) != 3) { + throw new ValidateException('Wrong number of segments'); + } + list($headb64, $bodyb64, $cryptob64) = $tks; + if (null === ($payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64)))) { + throw new ValidateException('Invalid header encoding'); + } + if($payload->sub != $data['openId']){ + throw new ValidateException('授权失败'); + } + $user = app()->make(WechatUserRepository::class)->syncAppUser($data['openId'], [ + 'nickName' => (string)$data['nickname'] ?: '用户' . strtoupper(substr(md5(time()), 0, 12)) + ], 'App', $createUser); + if (!$user) + throw new ValidateException('授权失败'); + return $user; + } + } + + public function authLogin() + { + $auth = $this->request->param('auth'); + $users = $this->authInfo($auth, systemConfig('is_phone_login') !== '1'); + if (!$users) + return app('json')->fail('授权失败'); + $authInfo = $users[0]; + $userRepository = app()->make(UserRepository::class); + $user = $users[1] ?? $userRepository->wechatUserIdBytUser($authInfo['wechat_user_id']); + $code = (int)($auth['auth']['spread_code']['id'] ?? $auth['auth']['spread_code'] ?? ''); + //获取是否有扫码进小程序 + if ($code && ($info = app()->make(RoutineQrcodeRepository::class)->getRoutineQrcodeFindType($code))) { + $auth['auth']['spread'] = $info['third_id']; + } + if (!$user) { + $uni = uniqid(true, false) . random_int(1, 100000000); + $key = 'U' . md5(time() . $uni); + Cache::set('u_try' . $key, ['id' => $authInfo['wechat_user_id'], 'type' => $authInfo['user_type'], 'spread' => $auth['auth']['spread'] ?? 0], 3600); + return app('json')->status(201, compact('key')); + } + + if ($auth['auth']['spread'] ?? 0) { + $userRepository->bindSpread($user, (int)($auth['auth']['spread'])); + } + $tokenInfo = $userRepository->createToken($user); + $userRepository->loginAfter($user); + return app('json')->status(200, $userRepository->returnToken($user, $tokenInfo)); + } + + + /** + * App微信登陆 + * @param Request $request + * @return mixed + */ + public function appAuth() + { + $data = $this->request->params(['userInfo']); + + if (systemConfig('is_phone_login') === '1') { + return app('json')->fail('请绑定手机号'); + } + + $user = app()->make(WechatUserRepository::class)->syncAppUser($data['userInfo']['unionId'], $data['userInfo']); + if (!$user) + return app('json')->fail('授权失败'); + /** @var UserRepository $make */ + $userRepository = app()->make(UserRepository::class); + $user[1] = $userRepository->mainUser($user[1]); + $tokenInfo = $userRepository->createToken($user[1]); + $userRepository->loginAfter($user[1]); + + return app('json')->success($userRepository->returnToken($user[1], $tokenInfo)); + } + + public function getMerCertificate($merId) + { + $merId = (int)$merId; + $data = $this->request->params(['key', 'code']); + if (!$this->checkCaptcha($data['key'], $data['code'])) + return app('json')->fail('验证码输入有误'); + $certificate = merchantConfig($merId, 'mer_certificate') ?: []; + if (!count($certificate)) + return app('json')->fail('该商户未上传证书'); + return app('json')->success($certificate); + } + + public function appleAuth() + { + $data = $this->request->params(['openId', 'nickname']); + + if (systemConfig('is_phone_login') === '1') { + return app('json')->fail('请绑定手机号'); + } + + $user = app()->make(WechatUserRepository::class)->syncAppUser($data['openId'], [ + 'nickName' => (string)$data['nickname'] ?: '用户' . strtoupper(substr(md5(time()), 0, 12)) + ], 'apple'); + if (!$user) + return app('json')->fail('授权失败'); + /** @var UserRepository $make */ + $userRepository = app()->make(UserRepository::class); + $user[1] = $userRepository->mainUser($user[1]); + $tokenInfo = $userRepository->createToken($user[1]); + $userRepository->loginAfter($user[1]); + return app('json')->success($userRepository->returnToken($user[1], $tokenInfo)); + } + + /** + * 注销账号 + */ + public function cancel() + { + $userRepository = app()->make(UserRepository::class); + $user = $this->request->userInfo(); + $order = app()->make(StoreOrderRepository::class)->search(['uid' => $user['uid'], 'paid' => 1])->where('StoreOrder.status', 0)->count(); + $refund = app()->make(StoreRefundOrderRepository::class)->search(['uid' => $user['uid'], 'type' => 1])->count(); + $key = $this->request->param('key'); + $flag = false; + if ($user->now_money > 0 || $user->integral > 0 || $order > 0 || $refund > 0) { + $flag = true; + if (!$key) { + $uni = uniqid(true, false) . random_int(1, 100000000); + $key = 'L' . md5(time() . $uni); + Cache::set('u_out' . $user['uid'], $key, 600); + return app('json')->status(201, '该账号下有未完成业务,注销后不可恢复,您确定继续注销?', compact('key')); + } + } + if ($flag && (!$key || (Cache::get('u_out' . $user['uid']) != $key))) { + return app('json')->fail('操作超时'); + } + $userRepository->cancel($user); + $userRepository->clearToken($user); + return app('json')->status(200, '注销成功'); + } + + public function mpPhone() + { + $code = $this->request->param('code'); + $auth_token = $this->request->param('auth_token'); + $iv = $this->request->param('iv'); + $encryptedData = $this->request->param('encryptedData'); + $miniProgramService = MiniProgramService::create(); + $userInfoCong = Cache::get('eb_api_code_' . $code); + if (!$code && !$userInfoCong) + throw new ValidateException('授权失败,参数有误'); + if ($code && !$userInfoCong) { + try { + $userInfoCong = $miniProgramService->getUserInfo($code); + Cache::set('eb_api_code_' . $code, $userInfoCong, 86400); + } catch (Exception $e) { + throw new ValidateException('获取session_key失败,请检查您的配置!'); + } + } + $session_key = $userInfoCong['session_key']; + + $data = $miniProgramService->encryptor($session_key, $iv, $encryptedData); + $userRepository = app()->make(UserRepository::class); + + $phone = $data['purePhoneNumber']; + $user = $userRepository->accountByUser($phone); +// if($user && $auth_token){ +// return app('json')->fail('用户已存在'); +// } + $auth = $this->parseAuthToken($auth_token); + if ($user && $auth) { + $userRepository->syncBaseAuth($auth, $user); + } else if (!$user) { + if (!$auth) { + return app('json')->fail('操作超时'); + } + $wechatUser = app()->make(WechatUserRepository::class)->get($auth['id']); + $user = $userRepository->syncWechatUser($wechatUser, 'routine'); + $user->phone = $phone; + $user->account = $phone; + $user->save(); + if ($auth['spread']) { + $userRepository->bindSpread($user, $auth['spread']); + } + } + $tokenInfo = $userRepository->createToken($user); + $userRepository->loginAfter($user); + return app('json')->success($userRepository->returnToken($user, $tokenInfo)); + } + + /** + * @return mixed + */ + public function ajcaptcha() + { + $captchaType = $this->request->get('captchaType'); + if (!$captchaType) return app('json')->fail('请输入类型'); + return app('json')->success(aj_captcha_create($captchaType)); + } + + /** + * 一次验证 + * @return mixed + */ + public function ajcheck() + { + $token = $this->request->param('token',''); + $pointJson = $this->request->param('pointJson',''); + $captchaType = $this->request->param('captchaType',''); + + try { + aj_captcha_check_one($captchaType, $token, $pointJson); + return app('json')->success(); + } catch (\Throwable $e) { + return app('json')->fail(400336); + } + } + +} diff --git a/app/controller/api/Common.php b/app/controller/api/Common.php new file mode 100644 index 00000000..561464df --- /dev/null +++ b/app/controller/api/Common.php @@ -0,0 +1,494 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api; + + +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\shipping\ExpressRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\CacheRepository; +use app\common\repositories\system\diy\DiyRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\user\UserSignRepository; +use app\common\repositories\user\UserVisitRepository; +use app\common\repositories\wechat\TemplateMessageRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\basic\BaseController; +use crmeb\services\AlipayService; +use crmeb\services\CopyCommand; +use crmeb\services\MiniProgramService; +use crmeb\services\UploadService; +use crmeb\services\WechatService; +use Exception; +use Joypack\Tencent\Map\Bundle\Location; +use Joypack\Tencent\Map\Bundle\LocationOption; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Log; +use think\Response; + +/** + * Class Common + * @package app\controller\api + * @author xaboy + * @day 2020/5/28 + */ +class Common extends BaseController +{ + /** + * @return mixed + * @author xaboy + * @day 2020/5/28 + */ + public function hotKeyword() + { + $type = $this->request->param('type'); + switch ($type) { + case 0: + $keyword = systemGroupData('hot_keyword'); + break; + case 1: + $keyword = systemGroupData('community_hot_keyword'); + break; + } + return app('json')->success($keyword); + } + + public function express(ExpressRepository $repository) + { + return app('json')->success($repository->options()); + } + + public function menus() + { + return app('json')->success([ + 'global_theme' => $this->getThemeVar(systemConfig('global_theme')), + 'banner' => systemGroupData('my_banner'), + 'menu' => systemGroupData('my_menus') + ]); + } + + public function refundMessage() + { + return app('json')->success(explode("\n", systemConfig('refund_message'))); + } + + private function getThemeVar($type) + { + return app()->make(DiyRepository::class)->getThemeVar($type); + } + + public function config() + { + $config = systemConfig(['open_update_info', 'store_street_theme', 'is_open_service', 'is_phone_login', 'global_theme', 'integral_status', 'mer_location', 'alipay_open', 'hide_mer_status', 'mer_intention_open', 'share_info', 'share_title', 'share_pic', 'store_user_min_recharge', 'recharge_switch', 'balance_func_status', 'yue_pay_status', 'site_logo', 'routine_logo', 'site_name', 'login_logo', 'procudt_increase_status', 'sys_extension_type', 'member_status', 'copy_command_status', 'community_status','community_reply_status','community_app_switch', 'withdraw_type', 'recommend_switch', 'member_interests_status', 'beian_sn', 'community_reply_auth','hot_ranking_switch','svip_switch_status','margin_ico','margin_ico_switch']); + $make = app()->make(TemplateMessageRepository::class); + + $cache = app()->make(CacheRepository::class)->search(['copyright_status', 'copyright_context', 'copyright_image', 'sys_intention_agree']); + + if (!isset($cache['sys_intention_agree'])) { + $cache['sys_intention_agree'] = systemConfig('sys_intention_agree'); + } + + $title = app()->make(UserSignRepository::class)->signConfig(); + if (!$title) { + $config['member_status'] = 0; + } + if (!is_array($config['withdraw_type'])) { + $config['withdraw_type'] = ['1', '2', '3']; + } + + $config['tempid'] = app()->make(SystemNoticeConfigRepository::class)->getSubscribe(); + $config['global_theme'] = $this->getThemeVar($config['global_theme']); + $config['navigation'] = app()->make(DiyRepository::class)->getNavigation(); + $config = array_merge($config, $cache); + return app('json')->success($config); + } + + /** + * @param GroupDataRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/3 + */ + public function userRechargeQuota(GroupDataRepository $repository) + { + $recharge_quota = $repository->groupDataId('user_recharge_quota', 0); + $recharge_attention = explode("\n", systemConfig('recharge_attention')); + return app('json')->success(compact('recharge_quota', 'recharge_attention')); + } + + /** + * @param $field + * @return mixed + * @author xaboy + * @day 2020/5/28 + */ + public function uploadImage($field) + { + $name = $this->request->param('name'); + $file = $this->request->file($field); + if (!$file) + return app('json')->fail('请上传图片'); + if ($name) { + $f = $this->request->getOriginFile($field); + if ($f) { + $f['name'] = $name; + } + $this->request->setOriginFile($field, $f); + $file = $this->request->file($field); + } + $file = is_array($file) ? $file[0] : $file; + validate(["$field|图片" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'jpg,jpeg,png,bmp,gif', + 'fileMime' => 'image/jpeg,image/png,image/gif,application/octet-stream' + ]])->check([$field => $file]); + $upload = UploadService::create(); + $info = $upload->to('def')->move($field); + if ($info === false) { + return app('json')->fail($upload->getError()); + } + $res = $upload->getUploadInfo(); + $res['dir'] = tidy_url($res['dir']); + return app('json')->success('上传成功', ['path' => $res['dir']]); + } + + /** + * @return Response + * @author xaboy + * @day 2020/6/3 + */ + public function wechatNotify() + { + try { + if($this->request->header('content-type') === 'application/json'){ + return response(WechatService::create()->handleNotifyV3()->getContent()); + } + return response(WechatService::create()->handleNotify()->getContent()); + } catch (Exception $e) { + Log::info('支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + /** + * 电商收付通合并支付回调 + */ + public function wechatCombinePayNotify($type) + { + if (!in_array($type, ['order', 'presell'], true)) + throw new ValidateException('参数错误'); + try { + return WechatService::create()->handleCombinePayNotify($type); + } catch (Exception $e) { + Log::info('电商收付通支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + /** + * 电商收付通合并支付回调 + */ + public function routineCombinePayNotify($type) + { + if (!in_array($type, ['order', 'presell'], true)) + throw new ValidateException('参数错误'); + try { + return WechatService::create()->handleCombinePayNotify($type); + } catch (Exception $e) { + Log::info('小程序电商收付通支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + public function routineNotify() + { + try { + if($this->request->header('content-type') === 'application/json'){ + return response(MiniProgramService::create()->handleNotifyV3()->getContent()); + } + return response(MiniProgramService::create()->handleNotify()->getContent()); + } catch (Exception $e) { + Log::info('支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine(),$this->request->header()], true)); + } + } + + public function alipayNotify($type) + { + if (!in_array($type, ['order', 'user_recharge', 'presell', 'user_order'], true)) + throw new ValidateException('参数错误'); + $post = $_POST; + $get = $_GET; + $_POST = $this->request->post(); + $_GET = $this->request->get(); + try { + AlipayService::create()->notify($type); + } catch (Exception $e) { + Log::info('支付宝回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } finally { + $_POST = $post; + $_GET = $get; + } + } + + public function getVersion() + { + return app('json')->success(['version' => get_crmeb_version(), 'host' => request()->host(), 'system' => PHP_OS, 'php' => @phpversion()]); + } + + /** + * 获取图片base64 + * @return mixed + */ + public function get_image_base64() + { + list($imageUrl, $codeUrl) = $this->request->params([ + ['image', ''], + ['code', ''], + ], true); + checkSuffix([$imageUrl, $codeUrl]); + try { + $codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : ''; + if (!$codeTmp) { + $putCodeUrl = put_image($codeUrl); + $code = $putCodeUrl ? image_to_base64('./runtime/temp' . $putCodeUrl) : ''; + $code && unlink('./runtime/temp' . $putCodeUrl); + } + + $imageTmp = $image = $imageUrl ? image_to_base64($imageUrl) : ''; + if (!$imageTmp) { + $putImageUrl = put_image($imageUrl); + $image = $putImageUrl ? image_to_base64('./runtime/temp' . $putImageUrl) : ''; + $image && unlink('./runtime/temp' . $putImageUrl); + } + return app('json')->success(compact('code', 'image')); + } catch (Exception $e) { + return app('json')->fail($e->getMessage()); + } + } + + public function home() + { + $banner = systemGroupData('home_banner', 1, 10); + $menu = systemGroupData('home_menu'); + $hot = systemGroupData('home_hot', 1, 4); + $activity = systemGroupData('sys_activity', 1, 1)[0] ?? null; + $activity_lst = systemGroupData('sys_activity', 1, 3); + $ad = systemConfig(['home_ad_pic', 'home_ad_url']); + $category = app()->make(StoreCategoryRepository::class)->getTwoLevel(); + return app('json')->success(compact('banner', 'menu', 'hot', 'ad', 'category', 'activity', 'activity_lst')); + } + + public function activityLst($id) + { + $merId = (int)$id; + [$page, $limit] = $this->getPage(); + return app('json')->success($merId ? merchantGroupData($merId, 'mer_activity', $page, $limit) : systemGroupData('sys_activity', $page, $limit)); + } + + public function activityInfo($id) + { + $activity = app()->make(GroupDataRepository::class)->getData((int)$id); + if (!$activity) { + return app('json')->fail('活动不存在'); + } + $activity['merchant'] = $activity['group_mer_id'] ? app()->make(MerchantRepository::class)->search(['mer_id' => $activity['group_mer_id']])->field('mer_name,mer_avatar')->find() : null; + return app('json')->success($activity); + } + + public function visit() + { + if (!$this->request->isLogin()) return app('json')->success(); + [$page, $type] = $this->request->params(['page', 'type'], true); + $uid = $this->request->uid(); + if (!$page || !$uid) return app('json')->fail(); + $userVisitRepository = app()->make(UserVisitRepository::class); + $type == 'routine' ? $userVisitRepository->visitSmallProgram($uid, $page) : $userVisitRepository->visitPage($uid, $page); + return app('json')->success(); + } + + public function hotBanner($type) + { + if (!in_array($type, ['new', 'hot', 'best', 'good'])) + $data = []; + else + $data = systemGroupData($type . '_home_banner'); + return app('json')->success($data); + } + + public function pay_key($key) + { + $cache = Cache::store('file'); + if (!$cache->has('pay_key' . $key)) { + return app('json')->fail('支付链接不存在'); + } + return app('json')->success($cache->get('pay_key' . $key)); + } + + public function lbs_geocoder() + { + $data = explode(',', $this->request->param('location', '')); + $locationOption = new LocationOption(systemConfig('tx_map_key')); + $locationOption->setLocation($data[0] ?? '', $data[1] ?? ''); + $location = new Location($locationOption); + $res = $location->request(); + if ($res->error) { + return app('json')->fail($res->error); + } + if ($res->status) { + return app('json')->fail($res->message); + } + if (!$res->result) { + return app('json')->fail('获取失败'); + } + return app('json')->success($res->result); + } + + + public function getCommand() + { + $key = $this->request->param('key'); + if (!preg_match('/^(\/@[1-9]{1}).*\*\//', $key)) { + return app('json')->fail('无效口令'); + } + $userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + $command = app()->make(CopyCommand::class)->getMassage($key); + if (empty($command)) return app('json')->fail('无效口令'); + $info = []; + if ($command['uid']) { + $user = app()->make(UserRepository::class)->get($command['uid']); + $info = [ + 'uid' => $user['uid'], + 'nickname' => $user['nickname'], + 'avatar' => $user['avatar'], + ]; + } + switch ($command['type']) { + case 0: + $data = app()->make(ProductRepository::class)->detail($command['id'], $userInfo); + $ret['product_id'] = $command['id']; + break; + case 1: + $data = app()->make(ProductRepository::class)->detail($command['id'], $userInfo); + $ret['product_id'] = $command['id']; + break; + case 2: + $data = app()->make(ProductPresellRepository::class)->apiDetail((int)$command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + case 4: + $data = app()->make(ProductGroupRepository::class)->apiDetail($command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + case 30: + $data = app()->make(ProductAssistSetRepository::class)->detail($command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + case 40: + $data = app()->make(ProductGroupBuyingRepository::class)->detail($command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + } + if ($userInfo && $command['uid']) app()->make(UserRepository::class)->bindSpread($userInfo, $command['uid']); + $ret['product_type'] = $command['type']; + $ret['user'] = $info; + $ret['com'] = $command['com']; + $ret['data'] = $data; + return app('json')->success($ret); + } + + public function script() + { + return \response(systemConfig('static_script')); + } + + public function appVersion() + { + return app('json')->success(systemConfig([ + 'appVersion', + 'iosAddress', + 'androidAddress', + 'openUpgrade' + ])); + } + + public function deliveryNotify() + { + try { + $params = $this->request->param(); + app()->make(DeliveryOrderRepository::class)->notify($params); + } catch (Exception $e) { + Log::info('同城配送订单回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + public function diy() + { + $merid = $this->request->param('id', 0); + return app('json')->success(app()->make(DiyRepository::class)->getDiyInfo(0, $merid)); + } + + public function getNavigation() + { + return app('json')->success(app()->make(DiyRepository::class)->getNavigation()); + } + + public function micro() + { + $id = $this->request->param('id', 0); + return app('json')->success(app()->make(DiyRepository::class)->getDiyInfo($id, 0, 0)); + } + + /** + * 是否关注 + * @return mixed + */ + public function subscribe() + { + if ($this->request->isLogin()) { + $user = $this->request->userInfo(); + if ($user && $user['wechat_user_id']) { + $wechatUserService = app()->make(WechatUserRepository::class); + $subscribe = $wechatUserService->getWhereCount([ + 'wechat_user_id' => $user['wechat_user_id'], + 'subscribe' => 1 + ]) > 0; + return app('json')->success(['subscribe' => $subscribe]); + } + } + return app('json')->success(['subscribe' => false, 'qrcode' => systemConfig('wechat_qrcode')]); + } + + //区县数据 + public function get_area($city_code){ + $select=Db::name('geo_area')->where('city_code',$city_code)->field('area_id id,area_code code,area_name name')->select(); + return app('json')->success($select); + } + //街道 乡镇数据 + public function get_street($area_code){ + $select=Db::name('geo_street')->where('area_code',$area_code)->field('street_id id,street_code code,street_name name')->select(); + return app('json')->success($select); + } + //村数据 + public function get_village($street_code){ + $select=Db::name('geo_village')->where('street_code',$street_code)->field('village_id id,village_code code,village_name name')->select(); + return app('json')->success($select); + } +} diff --git a/app/controller/api/Common.php.bak b/app/controller/api/Common.php.bak new file mode 100644 index 00000000..130879f5 --- /dev/null +++ b/app/controller/api/Common.php.bak @@ -0,0 +1,477 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api; + + +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\shipping\ExpressRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\CacheRepository; +use app\common\repositories\system\diy\DiyRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\user\UserSignRepository; +use app\common\repositories\user\UserVisitRepository; +use app\common\repositories\wechat\TemplateMessageRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\basic\BaseController; +use crmeb\services\AlipayService; +use crmeb\services\CopyCommand; +use crmeb\services\MiniProgramService; +use crmeb\services\UploadService; +use crmeb\services\WechatService; +use Exception; +use Joypack\Tencent\Map\Bundle\Location; +use Joypack\Tencent\Map\Bundle\LocationOption; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Log; +use think\Response; + +/** + * Class Common + * @package app\controller\api + * @author xaboy + * @day 2020/5/28 + */ +class Common extends BaseController +{ + /** + * @return mixed + * @author xaboy + * @day 2020/5/28 + */ + public function hotKeyword() + { + $type = $this->request->param('type'); + switch ($type) { + case 0: + $keyword = systemGroupData('hot_keyword'); + break; + case 1: + $keyword = systemGroupData('community_hot_keyword'); + break; + } + return app('json')->success($keyword); + } + + public function express(ExpressRepository $repository) + { + return app('json')->success($repository->options()); + } + + public function menus() + { + return app('json')->success([ + 'global_theme' => $this->getThemeVar(systemConfig('global_theme')), + 'banner' => systemGroupData('my_banner'), + 'menu' => systemGroupData('my_menus') + ]); + } + + public function refundMessage() + { + return app('json')->success(explode("\n", systemConfig('refund_message'))); + } + + private function getThemeVar($type) + { + return app()->make(DiyRepository::class)->getThemeVar($type); + } + + public function config() + { + $config = systemConfig(['open_update_info', 'store_street_theme', 'is_open_service', 'is_phone_login', 'global_theme', 'integral_status', 'mer_location', 'alipay_open', 'hide_mer_status', 'mer_intention_open', 'share_info', 'share_title', 'share_pic', 'store_user_min_recharge', 'recharge_switch', 'balance_func_status', 'yue_pay_status', 'site_logo', 'routine_logo', 'site_name', 'login_logo', 'procudt_increase_status', 'sys_extension_type', 'member_status', 'copy_command_status', 'community_status','community_reply_status','community_app_switch', 'withdraw_type', 'recommend_switch', 'member_interests_status', 'beian_sn', 'community_reply_auth','hot_ranking_switch','svip_switch_status','margin_ico','margin_ico_switch']); + $make = app()->make(TemplateMessageRepository::class); + + $cache = app()->make(CacheRepository::class)->search(['copyright_status', 'copyright_context', 'copyright_image', 'sys_intention_agree']); + + if (!isset($cache['sys_intention_agree'])) { + $cache['sys_intention_agree'] = systemConfig('sys_intention_agree'); + } + + $title = app()->make(UserSignRepository::class)->signConfig(); + if (!$title) { + $config['member_status'] = 0; + } + if (!is_array($config['withdraw_type'])) { + $config['withdraw_type'] = ['1', '2', '3']; + } + + $config['tempid'] = app()->make(SystemNoticeConfigRepository::class)->getSubscribe(); + $config['global_theme'] = $this->getThemeVar($config['global_theme']); + $config['navigation'] = app()->make(DiyRepository::class)->getNavigation(); + $config = array_merge($config, $cache); + return app('json')->success($config); + } + + /** + * @param GroupDataRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/3 + */ + public function userRechargeQuota(GroupDataRepository $repository) + { + $recharge_quota = $repository->groupDataId('user_recharge_quota', 0); + $recharge_attention = explode("\n", systemConfig('recharge_attention')); + return app('json')->success(compact('recharge_quota', 'recharge_attention')); + } + + /** + * @param $field + * @return mixed + * @author xaboy + * @day 2020/5/28 + */ + public function uploadImage($field) + { + $name = $this->request->param('name'); + $file = $this->request->file($field); + if (!$file) + return app('json')->fail('请上传图片'); + if ($name) { + $f = $this->request->getOriginFile($field); + if ($f) { + $f['name'] = $name; + } + $this->request->setOriginFile($field, $f); + $file = $this->request->file($field); + } + $file = is_array($file) ? $file[0] : $file; + validate(["$field|图片" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'jpg,jpeg,png,bmp,gif', + 'fileMime' => 'image/jpeg,image/png,image/gif,application/octet-stream' + ]])->check([$field => $file]); + $upload = UploadService::create(); + $info = $upload->to('def')->move($field); + if ($info === false) { + return app('json')->fail($upload->getError()); + } + $res = $upload->getUploadInfo(); + $res['dir'] = tidy_url($res['dir']); + return app('json')->success('上传成功', ['path' => $res['dir']]); + } + + /** + * @return Response + * @author xaboy + * @day 2020/6/3 + */ + public function wechatNotify() + { + try { + if($this->request->header('content-type') === 'application/json'){ + return response(WechatService::create()->handleNotifyV3()->getContent()); + } + return response(WechatService::create()->handleNotify()->getContent()); + } catch (Exception $e) { + Log::info('支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + /** + * 电商收付通合并支付回调 + */ + public function wechatCombinePayNotify($type) + { + if (!in_array($type, ['order', 'presell'], true)) + throw new ValidateException('参数错误'); + try { + return WechatService::create()->handleCombinePayNotify($type); + } catch (Exception $e) { + Log::info('电商收付通支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + /** + * 电商收付通合并支付回调 + */ + public function routineCombinePayNotify($type) + { + if (!in_array($type, ['order', 'presell'], true)) + throw new ValidateException('参数错误'); + try { + return WechatService::create()->handleCombinePayNotify($type); + } catch (Exception $e) { + Log::info('小程序电商收付通支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + public function routineNotify() + { + try { + if($this->request->header('content-type') === 'application/json'){ + return response(MiniProgramService::create()->handleNotifyV3()->getContent()); + } + return response(MiniProgramService::create()->handleNotify()->getContent()); + } catch (Exception $e) { + Log::info('支付回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine(),$this->request->header()], true)); + } + } + + public function alipayNotify($type) + { + if (!in_array($type, ['order', 'user_recharge', 'presell', 'user_order'], true)) + throw new ValidateException('参数错误'); + $post = $_POST; + $get = $_GET; + $_POST = $this->request->post(); + $_GET = $this->request->get(); + try { + AlipayService::create()->notify($type); + } catch (Exception $e) { + Log::info('支付宝回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } finally { + $_POST = $post; + $_GET = $get; + } + } + + public function getVersion() + { + return app('json')->success(['version' => get_crmeb_version(), 'host' => request()->host(), 'system' => PHP_OS, 'php' => @phpversion()]); + } + + /** + * 获取图片base64 + * @return mixed + */ + public function get_image_base64() + { + list($imageUrl, $codeUrl) = $this->request->params([ + ['image', ''], + ['code', ''], + ], true); + checkSuffix([$imageUrl, $codeUrl]); + try { + $codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : ''; + if (!$codeTmp) { + $putCodeUrl = put_image($codeUrl); + $code = $putCodeUrl ? image_to_base64('./runtime/temp' . $putCodeUrl) : ''; + $code && unlink('./runtime/temp' . $putCodeUrl); + } + + $imageTmp = $image = $imageUrl ? image_to_base64($imageUrl) : ''; + if (!$imageTmp) { + $putImageUrl = put_image($imageUrl); + $image = $putImageUrl ? image_to_base64('./runtime/temp' . $putImageUrl) : ''; + $image && unlink('./runtime/temp' . $putImageUrl); + } + return app('json')->success(compact('code', 'image')); + } catch (Exception $e) { + return app('json')->fail($e->getMessage()); + } + } + + public function home() + { + $banner = systemGroupData('home_banner', 1, 10); + $menu = systemGroupData('home_menu'); + $hot = systemGroupData('home_hot', 1, 4); + $activity = systemGroupData('sys_activity', 1, 1)[0] ?? null; + $activity_lst = systemGroupData('sys_activity', 1, 3); + $ad = systemConfig(['home_ad_pic', 'home_ad_url']); + $category = app()->make(StoreCategoryRepository::class)->getTwoLevel(); + return app('json')->success(compact('banner', 'menu', 'hot', 'ad', 'category', 'activity', 'activity_lst')); + } + + public function activityLst($id) + { + $merId = (int)$id; + [$page, $limit] = $this->getPage(); + return app('json')->success($merId ? merchantGroupData($merId, 'mer_activity', $page, $limit) : systemGroupData('sys_activity', $page, $limit)); + } + + public function activityInfo($id) + { + $activity = app()->make(GroupDataRepository::class)->getData((int)$id); + if (!$activity) { + return app('json')->fail('活动不存在'); + } + $activity['merchant'] = $activity['group_mer_id'] ? app()->make(MerchantRepository::class)->search(['mer_id' => $activity['group_mer_id']])->field('mer_name,mer_avatar')->find() : null; + return app('json')->success($activity); + } + + public function visit() + { + if (!$this->request->isLogin()) return app('json')->success(); + [$page, $type] = $this->request->params(['page', 'type'], true); + $uid = $this->request->uid(); + if (!$page || !$uid) return app('json')->fail(); + $userVisitRepository = app()->make(UserVisitRepository::class); + $type == 'routine' ? $userVisitRepository->visitSmallProgram($uid, $page) : $userVisitRepository->visitPage($uid, $page); + return app('json')->success(); + } + + public function hotBanner($type) + { + if (!in_array($type, ['new', 'hot', 'best', 'good'])) + $data = []; + else + $data = systemGroupData($type . '_home_banner'); + return app('json')->success($data); + } + + public function pay_key($key) + { + $cache = Cache::store('file'); + if (!$cache->has('pay_key' . $key)) { + return app('json')->fail('支付链接不存在'); + } + return app('json')->success($cache->get('pay_key' . $key)); + } + + public function lbs_geocoder() + { + $data = explode(',', $this->request->param('location', '')); + $locationOption = new LocationOption(systemConfig('tx_map_key')); + $locationOption->setLocation($data[0] ?? '', $data[1] ?? ''); + $location = new Location($locationOption); + $res = $location->request(); + if ($res->error) { + return app('json')->fail($res->error); + } + if ($res->status) { + return app('json')->fail($res->message); + } + if (!$res->result) { + return app('json')->fail('获取失败'); + } + return app('json')->success($res->result); + } + + + public function getCommand() + { + $key = $this->request->param('key'); + if (!preg_match('/^(\/@[1-9]{1}).*\*\//', $key)) { + return app('json')->fail('无效口令'); + } + $userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + $command = app()->make(CopyCommand::class)->getMassage($key); + if (empty($command)) return app('json')->fail('无效口令'); + $info = []; + if ($command['uid']) { + $user = app()->make(UserRepository::class)->get($command['uid']); + $info = [ + 'uid' => $user['uid'], + 'nickname' => $user['nickname'], + 'avatar' => $user['avatar'], + ]; + } + switch ($command['type']) { + case 0: + $data = app()->make(ProductRepository::class)->detail($command['id'], $userInfo); + $ret['product_id'] = $command['id']; + break; + case 1: + $data = app()->make(ProductRepository::class)->detail($command['id'], $userInfo); + $ret['product_id'] = $command['id']; + break; + case 2: + $data = app()->make(ProductPresellRepository::class)->apiDetail((int)$command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + case 4: + $data = app()->make(ProductGroupRepository::class)->apiDetail($command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + case 30: + $data = app()->make(ProductAssistSetRepository::class)->detail($command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + case 40: + $data = app()->make(ProductGroupBuyingRepository::class)->detail($command['id'], $userInfo); + $ret['activity_id'] = $command['id']; + break; + } + if ($userInfo && $command['uid']) app()->make(UserRepository::class)->bindSpread($userInfo, $command['uid']); + $ret['product_type'] = $command['type']; + $ret['user'] = $info; + $ret['com'] = $command['com']; + $ret['data'] = $data; + return app('json')->success($ret); + } + + public function script() + { + return \response(systemConfig('static_script')); + } + + public function appVersion() + { + return app('json')->success(systemConfig([ + 'appVersion', + 'iosAddress', + 'androidAddress', + 'openUpgrade' + ])); + } + + public function deliveryNotify() + { + try { + $params = $this->request->param(); + app()->make(DeliveryOrderRepository::class)->notify($params); + } catch (Exception $e) { + Log::info('同城配送订单回调失败:' . var_export([$e->getMessage(), $e->getFile() . ':' . $e->getLine()], true)); + } + } + + public function diy() + { + $merid = $this->request->param('id', 0); + return app('json')->success(app()->make(DiyRepository::class)->getDiyInfo(0, $merid)); + } + + public function getNavigation() + { + return app('json')->success(app()->make(DiyRepository::class)->getNavigation()); + } + + public function micro() + { + $id = $this->request->param('id', 0); + return app('json')->success(app()->make(DiyRepository::class)->getDiyInfo($id, 0, 0)); + } + + /** + * 是否关注 + * @return mixed + */ + public function subscribe() + { + if ($this->request->isLogin()) { + $user = $this->request->userInfo(); + if ($user && $user['wechat_user_id']) { + $wechatUserService = app()->make(WechatUserRepository::class); + $subscribe = $wechatUserService->getWhereCount([ + 'wechat_user_id' => $user['wechat_user_id'], + 'subscribe' => 1 + ]) > 0; + return app('json')->success(['subscribe' => $subscribe]); + } + } + return app('json')->success(['subscribe' => false, 'qrcode' => systemConfig('wechat_qrcode')]); + } +} diff --git a/app/controller/api/Wechat.php b/app/controller/api/Wechat.php new file mode 100644 index 00000000..0a5fe805 --- /dev/null +++ b/app/controller/api/Wechat.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api; + + +use crmeb\basic\BaseController; +use crmeb\services\WechatService; + +class Wechat extends BaseController +{ + public function jsConfig() + { + $data = WechatService::create()->jsSdk($this->request->param('url')?:$this->request->host()); + $data['openTagList'] = ['wx-open-launch-weapp']; + return app('json')->success($data); + } +} diff --git a/app/controller/api/article/Article.php b/app/controller/api/article/Article.php new file mode 100644 index 00000000..a6bfc15c --- /dev/null +++ b/app/controller/api/article/Article.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\article; + +use think\App; +use app\common\repositories\article\ArticleRepository as repository; +use crmeb\basic\BaseController; + +class Article extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * StoreBrand constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function lst($cid) + { + [$page, $limit] = $this->getPage(); + $where = ['status' => 1,'cid' => $cid]; + return app('json')->success($this->repository->search(0,$where, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->merApiExists($id)) + return app('json')->fail('文章不存在'); + + return app('json')->success($this->repository->get($id,0)); + } + + public function list() + { + $where = ['status' => 1]; + return app('json')->success($this->repository->search(0,$where, 1, 9)); + } +} diff --git a/app/controller/api/article/ArticleCategory.php b/app/controller/api/article/ArticleCategory.php new file mode 100644 index 00000000..8ecc3533 --- /dev/null +++ b/app/controller/api/article/ArticleCategory.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\article; + +use think\App; +use app\common\repositories\article\ArticleCategoryRepository as repository; +use crmeb\basic\BaseController; + +class ArticleCategory extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * StoreBrand constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author Qinii + */ + public function lst() + { + return app('json')->success($this->repository->apiGetArticleCategory()); + } +} diff --git a/app/controller/api/community/Community.php b/app/controller/api/community/Community.php new file mode 100644 index 00000000..04be94f1 --- /dev/null +++ b/app/controller/api/community/Community.php @@ -0,0 +1,428 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\community; + +use app\common\repositories\community\CommunityRepository; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\system\RelevanceRepository; +use app\common\repositories\user\UserHistoryRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserRepository; +use app\validate\api\CommunityValidate; +use crmeb\basic\BaseController; +use crmeb\services\MiniProgramService; +use think\App; +use app\common\repositories\community\CommunityRepository as repository; +use think\exception\ValidateException; + +class Community extends BaseController +{ + /** + * @var CommunityRepository + */ + protected $repository; + protected $user; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->user = $this->request->isLogin() ? $this->request->userInfo() : null; + if (!systemConfig('community_status') ) throw new ValidateException('未开启社区功能'); + } + + /** + * TODO 文章列表 + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function lst() + { + $where = $this->request->params(['keyword','topic_id','is_hot','category_id','spu_id']); + if (!$where['category_id']) { + unset($where['category_id']); + } else if ($where['category_id'] == -1) { + $where['is_type'] = $this->repository::COMMUNIT_TYPE_VIDEO; + unset($where['category_id']); + } + $where = array_merge($where,$this->repository::IS_SHOW_WHERE); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getApiList($where, $page, $limit, $this->user)); + } + + /** + * TODO 视频列表 + * @return \think\response\Json + * @author Qinii + * @day 2022/11/29 + */ + public function videoShow() + { + [$page, $limit] = $this->getPage(); + $where['community_id'] = $this->request->param('id',''); + $where = array_merge($where,$this->repository::IS_SHOW_WHERE); + return app('json')->success($this->repository->getApiVideoList($where, $page, $limit, $this->user)); + } + + /** + * TODO 关注的人的文章 + * @param RelevanceRepository $relevanceRepository + * @return \think\response\Json + * @author Qinii + * @day 11/2/21 + */ + public function focuslst(RelevanceRepository $relevanceRepository) + { + $where = $this->repository::IS_SHOW_WHERE; + $where_ = [ + 'left_id' => $this->user->uid ?? null , + 'type' => RelevanceRepository::TYPE_COMMUNITY_FANS, + ]; + $where['uids'] = $relevanceRepository->getSearch($where_)->column('right_id'); + [$page, $limit] = $this->getPage(); + $type = $this->request->param('type'); + if ($type) $where['is_type'] = $this->repository::COMMUNIT_TYPE_VIDEO; + return app('json')->success($this->repository->getApiList($where, $page, $limit, $this->user)); + } + + /** + * TODO 某个用户的文章 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function userCommunitylst($id) + { + $where = []; + if (!$this->user || $this->user->uid != $id) { + $where = $this->repository::IS_SHOW_WHERE; + } + $where['uid'] = $id; + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getApiList($where, $page, $limit, $this->user)); + } + + /** + * TODO 某个用户的视频 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function userCommunityVideolst($id) + { + $where = []; + [$page, $limit] = $this->getPage(); + $is_start = $this->request->param('is_star',0); + if ($is_start) { + //某人赞过的视频 + $where = $this->repository::IS_SHOW_WHERE; + } else { + //某个人的视频 + if (!$this->user || $this->user->uid != $id) { + $where =$this->repository::IS_SHOW_WHERE; + } + $where['uid'] = $id; + } + $where['is_del'] = 0; + $where['community_id'] = $this->request->param('community_id',''); + + $data = $this->repository->getApiVideoList($where, $page, $limit, $this->user,$is_start); + return app('json')->success($data); + } + + + /** + * TODO 我赞过的文章 + * @param RelevanceRepository $relevanceRepository + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function getUserStartCommunity(RelevanceRepository $relevanceRepository) + { + [$page, $limit] = $this->getPage(); + $where['uid'] = $this->user->uid; + $data = $relevanceRepository->getUserStartCommunity($where,$page, $limit); + return app('json')->success($data); + } + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function show($id) + { + return app('json')->success($this->repository->show($id, $this->user)); + } + + /** + * TODO 已购商品 + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function payList() + { + [$page, $limit] = $this->getPage(); + $keyword = $this->request->param('keyword'); + $data = app()->make(StoreOrderProductRepository::class)->getUserPayProduct($keyword, $this->user->uid, $page, $limit); + return app('json')->success($data); + } + + /** + * TODO 收藏商品 + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function relationList() + { + [$page, $limit] = $this->getPage(); + $keyword = $this->request->param('keyword'); + $data = app()->make(UserRelationRepository::class)->getUserProductToCommunity($keyword, $this->user->uid, $page, $limit); + return app('json')->success($data); + } + + public function historyList() + { + [$page, $limit] = $this->getPage(); + $where['keyword'] = $this->request->param('keyword'); + $where['uid'] = $this->request->userInfo()->uid; + $where['type'] = 1; + $data = app()->make(UserHistoryRepository::class)->historyLst($where, $page,$limit); + return app('json')->success($data); + } + + /** + * TODO 发布文章 + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function create() + { + $data = $this->checkParams(); + $this->checkUserAuth(); + $data['uid'] = $this->request->uid(); + $res = $this->repository->create($data); + return app('json')->success(['community_id' => $res]); + } + + /** + * TODO + * @return bool|\think\response\Json + * @author Qinii + * @day 10/30/21 + */ + public function checkUserAuth() + { + $user = $this->request->userInfo(); + if ( systemConfig('community_auth') ) { + if ($user->phone) { + return true; + } + throw new ValidateException('请先绑定您的手机号'); + } else { + return true; + } + } + + + /** + * TODO 编辑 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function update($id) + { + $data = $this->checkParams(); + $this->checkUserAuth(); + if(!$this->repository->uidExists($id, $this->user->uid)) + return app('json')->success('内容不存在或不属于您'); + $this->repository->edit($id, $data); + return app('json')->success(['community_id' => $id]); + } + + public function checkParams() + { + $data = $this->request->params(['image','topic_id','content','spu_id','order_id',['is_type',1],'video_link']); + $config = systemConfig(["community_app_switch",'community_audit','community_video_audit']); + $data['status'] = 0; + $data['is_show'] = 0; + if ($data['is_type'] == 1) { + if (!in_array($this->repository::COMMUNIT_TYPE_FONT,$config['community_app_switch'])) + throw new ValidateException('社区图文未开启'); + if ($config['community_audit']) { + $data['status'] = 1; + $data['is_show'] = 1; + $data['status_time'] = date('Y-m-d H:i:s', time()); + } + } else { + if (!in_array($this->repository::COMMUNIT_TYPE_VIDEO,$config['community_app_switch'])) + throw new ValidateException('短视频未开启'); + if ($config['community_video_audit']) { + $data['status'] = 1; + $data['is_show'] = 1; + $data['status_time'] = date('Y-m-d H:i:s', time()); + } + if (!$data['video_link']) throw new ValidateException('请上传视频'); + + } + + $data['content'] = filter_emoji($data['content']); + MiniProgramService::create()->msgSecCheck($this->request->userInfo(), $data['content'],3,0); + app()->make(CommunityValidate::class)->check($data); + $arr = explode("\n", $data['content']); + $title = rtrim(ltrim($arr[0])); + if (mb_strlen($title) > 40 ){ + $data['title'] = mb_substr($title,0,30,'utf-8'); + } else { + $data['title'] = $title; + } + if ($data['image']) $data['image'] = implode(',',$data['image']); + return $data; + } + + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->uidExists($id, $this->user->uid)) + return app('json')->fail('内容不存在或不属于您'); + $this->repository->destory($id, $this->user); + + return app('json')->success('删除成功'); + } + + /** + * TODO 文章点赞/取消 + * @param $id + * @param RelevanceRepository $relevanceRepository + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function startCommunity($id) + { + $status = $this->request->param('status') == 1 ? 1 :0; + if (!$this->repository->exists($id)) + return app('json')->fail('内容不存在'); + $this->repository->setCommunityStart($id, $this->user, $status); + if ($status) { + return app('json')->success('点赞成功'); + } else { + return app('json')->success('取消点赞'); + } + } + + /** + * TODO 用户关注/取消 + * @param $id + * @param RelevanceRepository $relevanceRepository + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function setFocus($id) + { + $id = (int)$id; + $status = $this->request->param('status') == 1 ? 1 :0; + if ($this->user->uid == $id) + return app('json')->fail('请勿关注自己'); + $make = app()->make(UserRepository::class); + if (!$user = $make->get($id)) return app('json')->fail('未查询到该用户'); + + $this->repository->setFocus($id, $this->user->uid, $status); + + if ($status) { + return app('json')->success('关注成功'); + } else { + return app('json')->success('取消关注'); + } + } + + /** + * TODO 我的粉丝 + * @param RelevanceRepository $relevanceRepository + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function getUserFans(RelevanceRepository $relevanceRepository) + { + [$page, $limit] = $this->getPage(); + $fans = $relevanceRepository->getUserFans($this->user->uid, $page, $limit); + return app('json')->success($fans); + } + + /** + * TODO 我的关注 + * @param RelevanceRepository $relevanceRepository + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function getUserFocus(RelevanceRepository $relevanceRepository) + { + [$page, $limit] = $this->getPage(); + $start = $relevanceRepository->getUserFocus($this->user->uid, $page, $limit); + return app('json')->success($start); + } + + + /** + * TODO 用户信息 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/28/21 + */ + public function userInfo($id) + { + if (!$id) return app('json')->fail('缺少参数'); + $data = $this->repository->getUserInfo($id, $this->user); + return app('json')->success($data); + } + + public function getSpuByOrder($id) + { + $data = $this->repository->getSpuByOrder($id,7233); + return app('json')->success($data); + } + + public function qrcode($id) + { + $id = (int)$id; + $type = $this->request->param('type'); + if ($this->request->isLogin()) { + $url = $this->repository->qrcode($id, $type, $this->request->userInfo()); + } + if (!$url) return app('json')->fail('二维码生成失败'); + return app('json')->success(compact('url')); + } +} diff --git a/app/controller/api/community/CommunityCategory.php b/app/controller/api/community/CommunityCategory.php new file mode 100644 index 00000000..6e4f1f33 --- /dev/null +++ b/app/controller/api/community/CommunityCategory.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\community; + +use crmeb\basic\BaseController; +use crmeb\traits\CategoresRepository; +use think\App; +use app\validate\admin\StoreCategoryValidate; +use app\common\repositories\community\CommunityCategoryRepository as repository; +use think\exception\ValidateException; + +class CommunityCategory extends BaseController +{ + /** + * @var CommunityCategoryRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + if (!systemConfig('community_status') ) throw new ValidateException('未开启社区功能'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 10/27/21 + */ + public function lst() + { + return app('json')->success($this->repository->getApiList()); + } +} diff --git a/app/controller/api/community/CommunityReply.php b/app/controller/api/community/CommunityReply.php new file mode 100644 index 00000000..98d224e3 --- /dev/null +++ b/app/controller/api/community/CommunityReply.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\community; + +use app\common\repositories\community\CommunityRepository; +use app\common\repositories\system\RelevanceRepository; +use crmeb\basic\BaseController; +use crmeb\services\MiniProgramService; +use think\App; +use app\common\repositories\community\CommunityReplyRepository as repository; +use think\exception\ValidateException; + +class CommunityReply extends BaseController +{ + /** + * @var CommunityReplyRepository + */ + protected $repository; + + /** + * User constructor. + * @param App $app + * @param $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + if (!systemConfig('community_status')) throw new ValidateException('未开启社区功能'); + } + + /** + * @return mixed + * @author Qinii + */ + public function lst($id) + { + if (!systemConfig('community_reply_status')) + return app('json')->success([ + 'count' => 0, + 'all' => 0, + 'start' => 0, + 'list' => [] + ]); + $where['community_id'] = $id; + [$page, $limit] = $this->getPage(); + $userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + return app('json')->success($this->repository->getApiList($where, $page, $limit, $userInfo)); + } + + /** + * TODO 发评论 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function create($id) + { + if (!systemConfig('community_reply_status')) + return app('json')->fail('评论功能未开启'); + if (systemConfig('community_reply_auth') && !$this->request->userInfo()->phone) + return app('json')->fail('请先绑定手机号'); + + $replyId = $this->request->param('reply_id', 0); + + $data = $this->request->params(['content']); + if (empty($data['content'])) return app('json')->fail('请输入回复内容'); + MiniProgramService::create()->msgSecCheck($this->request->userInfo(), $data['content'],2,0); + $data['uid'] = $this->request->userInfo()->uid; + $data['community_id'] = $id; + + $data['status'] = 1; + $msg = '回复成功'; + if (systemConfig('community_reply_audit')) { + $data['status'] = 0; + $msg = '回复成功,正在审核中'; + } + $ret = $this->repository->create($replyId, $data); + return app('json')->success($msg, $ret); + } + + public function delete($id) + { + if (!$this->repository->uidExists($id, $this->request->userInfo()->uid)) + return app('json')->fail('评论不存在'); + $this->repository->delete($id); + return app('json')->success('评论删除'); + } + + /** + * TODO 评论点赞 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 10/29/21 + */ + public function start($id) + { + if (!systemConfig('community_reply_status')) + return app('json')->success('评论不存在'); + $status = $this->request->param('status') == 1 ? 1 : 0; + if (!$this->repository->exists($id)) + return app('json')->fail('评论不存在'); + + $uid = $this->request->userInfo()->uid; + $this->repository->setStart($id, $uid, $status); + if ($status) { + return app('json')->success('点赞成功'); + } else { + return app('json')->success('取消点赞'); + } + } +} diff --git a/app/controller/api/server/ShippingTemplate.php b/app/controller/api/server/ShippingTemplate.php new file mode 100644 index 00000000..71010ed3 --- /dev/null +++ b/app/controller/api/server/ShippingTemplate.php @@ -0,0 +1,136 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\server; + +use think\App; +use crmeb\basic\BaseController; +use think\exception\HttpResponseException; +use app\validate\merchant\ShippingTemplateValidate; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; + +class ShippingTemplate extends BaseController +{ + + protected $merId; + protected $repository; + + public function __construct(App $app, ShippingTemplateRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->route('merId'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type','name']); + return app('json')->success($this->repository->search($this->merId, $where, $page, $limit)); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function getList() + { + return app('json')->success($this->repository->getList($this->merId)); + } + + /** + * TODO + * @param ShippingTemplateValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function create(ShippingTemplateValidate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->merId; + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function detail($id) + { + if(!$this->repository->merExists($this->merId,$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getOne($id,1)); + } + + /** + * TODO + * @param $id + * @param ShippingTemplateValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function update($id, ShippingTemplateValidate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->merExists($this->merId,$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,$data, $this->merId); + + return app('json')->success('编辑成功'); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function batchDelete() + { + $ids = $this->request->param('ids'); + foreach ($ids as $id) { + $this->repository->check($this->merId, $id); + } + $this->repository->delete($ids); + return app('json')->success('删除成功'); + } + + /** + * TODO + * @param ShippingTemplateValidate $validate + * @return array + * @author Qinii + * @day 8/24/21 + */ + public function checkParams(ShippingTemplateValidate $validate) + { + $data = $this->request->params(['name','type','appoint','undelivery','region','free','undelives','sort','info']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/api/server/StoreCategory.php b/app/controller/api/server/StoreCategory.php new file mode 100644 index 00000000..6510f223 --- /dev/null +++ b/app/controller/api/server/StoreCategory.php @@ -0,0 +1,170 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\server; + +use app\common\repositories\store\StoreCategoryRepository; +use think\App; +use crmeb\basic\BaseController; +use think\exception\HttpResponseException; +use app\validate\admin\StoreCategoryValidate; +use app\common\repositories\store\service\StoreServiceRepository; + +class StoreCategory extends BaseController +{ + protected $merId; + protected $repository; + + public function __construct(App $app, StoreCategoryRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->route('merId'); + } + + public function lst($merId) + { + return app('json')->success($this->repository->getFormatList($merId)); + } + + public function create($merId, StoreCategoryValidate $validate) + { + $data = $this->checkParams($validate); + $data['cate_name'] = trim($data['cate_name']); + if($data['cate_name'] == '') return app('json')->fail('分类名不可为空'); + + if ($data['pid'] && !$this->repository->merExists($merId, $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'],0,$merId)) + return app('json')->fail('不可添加更低阶分类'); + $data['mer_id'] = $merId; + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function update($merId, $id, StoreCategoryValidate $validate) + { + $data = $this->checkParams($validate); + + if(!$this->repository->checkUpdate($id,$data['pid'])){ + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + if ($data['pid'] && !$this->repository->merExists($merId, $data['pid'])) + return app('json')->fail('上级分类不存在'); + if ($data['pid'] && !$this->repository->checkLevel($data['pid'],0, $merId)) + return app('json')->fail('不可添加更低阶分类'); + if (!$this->repository->checkChangeToChild($id,$data['pid'])) + return app('json')->fail('无法修改到当前分类到子集,请先修改子类'); + if (!$this->repository->checkChildLevel($id,$data['pid'],$merId)) + return app('json')->fail('子类超过最低限制,请先修改子类'); + } + $this->repository->update($id,$data); + + return app('json')->success('编辑成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + + $this->repository->switchStatus($id, $status); + return app('json')->success('修改成功'); + } + + public function detail($id) + { + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)); + } + + public function delete($id) + { + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->hasChild($id)) + return app('json')->fail('该分类存在子集,请先处理子集'); + + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function getTreeList() + { + $data = $this->repository->getTreeList($this->merId,1); + $ret = []; + foreach ($data as $datum) { + if (isset($datum['children'])) { + $ret[] = $datum; + } + } + return app('json')->success($ret); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function getList() + { + $data = $this->repository->getList(1); + $ret = []; + foreach ($data as $key => $value) { + if (isset($value['children'])) { + $level = []; + foreach ($value['children'] as $child) { + if (isset($child['children'])) { + $level[] = $child; + } + } + if (isset($level) && !empty($level)) { + $value['children'] = $level; + $ret[] = $value; + } + } + } + return app('json')->success($ret); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function BrandList() + { + return app('json')->success($this->repository->getBrandList()); + } + + /** + * TODO + * @param StoreCategoryValidate $validate + * @return array + * @author Qinii + * @day 8/24/21 + */ + public function checkParams(StoreCategoryValidate $validate) + { + $data = $this->request->params(['pid','cate_name','is_show','pic','sort']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/api/server/StoreOrder.php b/app/controller/api/server/StoreOrder.php new file mode 100644 index 00000000..d0b18658 --- /dev/null +++ b/app/controller/api/server/StoreOrder.php @@ -0,0 +1,342 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\server; + + +use app\common\repositories\delivery\DeliveryStationRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\controller\merchant\Common; +use crmeb\basic\BaseController; +use think\App; +use think\exception\HttpResponseException; +use think\exception\ValidateException; +use think\facade\Db; +use think\response\Json; + +class StoreOrder extends BaseController +{ + public function __construct(App $app) + { + parent::__construct($app); + } + + public function orderStatistics($merId, StoreOrderRepository $repository) + { + + $product_type=$this->request->param('product_type',0); + $order = $repository->OrderTitleNumber($merId, null,$product_type); + $order['refund'] = app()->make(StoreRefundOrderRepository::class)->getWhereCount(['is_system_del' => 0, 'mer_id' => $merId]); + $common = app()->make(Common::class); + $data = []; + $data['today'] = $common->mainGroup('today', $merId); + $data['yesterday'] = $common->mainGroup('yesterday', $merId); + $data['month'] = $common->mainGroup('month', $merId); + return app('json')->success(compact('order', 'data')); + } + + public function orderDetail($merId, StoreOrderRepository $repository) + { + [$page, $limit] = $this->getPage(); + list($start, $stop) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + ], true); + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $where = $this->request->has('start') ? ['dateRange' => compact('start', 'stop')] : []; + $list = $repository->orderGroupNumPage($where, $page, $limit, $merId); + return app('json')->success($list); + } + + public function orderList($merId, StoreOrderRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where['status'] = $this->request->param('status'); + $where['product_type'] = $this->request->param('product_type',0); + if ($where['product_type']==0){ + unset($where['product_type']); + } + $where['is_verify'] = $this->request->param('is_verify'); + $where['search'] = $this->request->param('store_name'); + $where['mer_id'] = $merId; + $where['is_del'] = 0; + if($where['status'] == 2) $where['order_type'] = 0; + return app('json')->success($repository->merchantGetList($where, $page, $limit)); + } + + public function order($merId, $id, StoreOrderRepository $repository) + { + $detail = $repository->getDetail($id); + if (!$detail) + return app('json')->fail('订单不存在'); + if ($detail['mer_id'] != $merId) + return app('json')->fail('没有权限'); + return app('json')->success($detail->toArray()); + } + + + protected function checkOrderAuth($merId, $id) + { + if (!app()->make(StoreOrderRepository::class)->existsWhere(['mer_id' => $merId, 'order_id' => $id])) + throw new ValidateException('没有权限'); + } + + public function mark($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + $data = $this->request->params(['remark']); + $repository->update($id, $data); + return app('json')->success('备注成功'); + } + + public function price($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + + $data = $this->request->params(['total_price', 'pay_postage']); + + if ($data['total_price'] < 0 || $data['pay_postage'] < 0) + return app('json')->fail('金额不可未负数'); + if (!$repository->merStatusExists((int)$id, $merId)) + return app('json')->fail('订单信息或状态错误'); + $repository->eidt($id, $data); + return app('json')->success('修改成功'); + } + + /** + * TODO 发货操作 + * @param $merId + * @param $id + * @param StoreOrderRepository $repository + * @return Json + * @author Qinii + * @day 6/1/22 + */ + public function delivery($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + $type = $this->request->param('delivery_type'); + $split = $this->request->params(['is_split',['split',[]]]); + if (!$repository->merDeliveryExists($id, $merId)) + return app('json')->fail('订单信息或状态错误'); + switch ($type) + { + case 3: //虚拟发货 + $data = $this->request->params([ + 'delivery_type', + 'remark', + ]); + $data['delivery_name'] = ''; + $data['delivery_id'] = ''; + $method = 'delivery'; + break; + case 4: //电子面单 + if (!systemConfig('crmeb_serve_dump')) + return app('json')->fail('电子面单功能未开启'); + $data = $this->request->params([ + 'delivery_type', + 'delivery_name', + 'from_name', + 'from_tel', + 'from_addr', + 'temp_id', + 'remark', + ]); + if (!$data['from_name'] || + !$data['delivery_name'] || + !$data['from_tel'] || + !$data['from_addr'] || + !$data['temp_id'] + ) + return app('json')->fail('填写配送信息'); + $method = 'dump'; + break; + case 5: //同城配送 + if (systemConfig('delivery_status') != 1) + return app('json')->fail('未开启同城配送'); + $data = $this->request->params([ + 'delivery_type', + 'station_id', + 'mark', + ['cargo_weight',0], + 'remark', + ]); + if ($data['cargo_weight'] < 0) return app('json')->fail('包裹重量能为负数'); + if (!$data['station_id']) return app('json')->fail('请选择门店'); + $method = 'cityDelivery'; + break; + default: //快递 + $data = $this->request->params([ + 'delivery_type', + 'delivery_type', + 'delivery_name', + 'delivery_id', + 'remark', + ]); + if (!$data['delivery_type'] || !$data['delivery_name'] || !$data['delivery_id']) + return app('json')->fail('填写配送信息'); + + $method = 'delivery'; + break; + } + $repository->runDelivery($id,$merId, $data, $split, $method, $this->request->serviceInfo()->service_id); + return app('json')->success('发货成功'); + } + + public function payPrice($merId, StoreOrderRepository $repository) + { + list($start, $stop, $month) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + 'month' + ], true); + + if ($month) { + $start = date('Y/m/d', strtotime(getStartModelTime('month'))); + $stop = date('Y/m/d H:i:s', strtotime('+ 1day')); + $front = date('Y/m/d', strtotime('first Day of this month', strtotime('-1 day', strtotime('first Day of this month')))); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } else { + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $space = bcsub($stop, $start, 0);//间隔时间段 + $front = bcsub($start, $space, 0);//第一个时间段 + + $front = date('Y/m/d H:i:s', $front); + $start = date('Y/m/d H:i:s', $start); + $stop = date('Y/m/d H:i:s', $stop); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } + $frontPrice = $repository->dateOrderPrice($front . '-' . $end, $merId); + $afterPrice = $repository->dateOrderPrice($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $chartInfo = $repository->chartTimePrice($start, date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $data['chart'] = $chartInfo;//营业额图表数据 + $data['time'] = $afterPrice;//时间区间营业额 + $increase = (float)bcsub((string)$afterPrice, (string)$frontPrice, 2); //同比上个时间区间增长营业额 + $growthRate = abs($increase); + if ($growthRate == 0) $data['growth_rate'] = 0; + else if ($frontPrice == 0) $data['growth_rate'] = bcmul($growthRate, 100, 0); + else $data['growth_rate'] = (int)bcmul((string)bcdiv((string)$growthRate, (string)$frontPrice, 2), '100', 0);//时间区间增长率 + $data['increase_time'] = abs($increase); //同比上个时间区间增长营业额 + $data['increase_time_status'] = $increase >= 0 ? 1 : 2; //同比上个时间区间增长营业额增长 1 减少 2 + + return app('json')->success($data); + } + + /** + * @param StoreOrderRepository $repository + * @return Json + * @author xaboy + * @day 2020/8/27 + */ + public function payNumber($merId, StoreOrderRepository $repository) + { + list($start, $stop, $month) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + 'month' + ], true); + + if ($month) { + $start = date('Y/m/d', strtotime(getStartModelTime('month'))); + $stop = date('Y/m/d H:i:s', strtotime('+ 1day')); + $front = date('Y/m/d', strtotime('first Day of this month', strtotime('-1 day', strtotime('first Day of this month')))); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } else { + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $space = bcsub($stop, $start, 0);//间隔时间段 + $front = bcsub($start, $space, 0);//第一个时间段 + + $front = date('Y/m/d H:i:s', $front); + $start = date('Y/m/d H:i:s', $start); + $stop = date('Y/m/d H:i:s', $stop); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } + $frontNumber = $repository->dateOrderNum($front . '-' . $end, $merId); + $afterNumber = $repository->dateOrderNum($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $chartInfo = $repository->chartTimeNum($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $data['chart'] = $chartInfo;//订单数图表数据 + $data['time'] = $afterNumber;//时间区间订单数 + $increase = $afterNumber - $frontNumber; //同比上个时间区间增长订单数 + $growthRate = abs($increase); + if ($growthRate == 0) $data['growth_rate'] = 0; + else if ($frontNumber == 0) $data['growth_rate'] = bcmul($growthRate, 100, 0); + else $data['growth_rate'] = (int)bcmul((string)bcdiv((string)$growthRate, (string)$frontNumber, 2), '100', 0);//时间区间增长率 + $data['increase_time'] = abs($increase); //同比上个时间区间增长营业额 + $data['increase_time_status'] = $increase >= 0 ? 1 : 2; //同比上个时间区间增长营业额增长 1 减少 2 + + return app('json')->success($data); + } + + public function getFormData($merId) + { + $config = [ + 'mer_from_com', + 'mer_from_name', + 'mer_from_tel', + 'mer_from_addr', + 'mer_config_siid', + 'mer_config_temp_id' + ]; + $data = merchantConfig($merId,$config); + return app('json')->success($data); + } + + public function getDeliveryConfig() + { + $data = systemConfig(['crmeb_serve_dump','delivery_status']); + return app('json')->success($data); + } + + public function getDeliveryOptions($merId, DeliveryStationRepository $repository) + { + if (!systemConfig('delivery_status')) { + return app('json')->success([]); + } + $where = [ + 'status' => 1, + 'mer_id' => $merId, + 'type' => systemConfig('delivery_type'), + ]; + $data = $repository->getOptions($where)->toArray(); + $type = systemConfig('delivery_type') == 1 ? 'UU' : '达达'; + if (empty($data)) return app('json')->fail('请前往商户后台添加'.$type.'发货点'); + return app('json')->success($data); + } + + public function verify($merId,$id,StoreOrderRepository $orderRepository) + { + $order = $orderRepository->getWhere(['order_id' => $id,'mer_id' => $merId]); + if (!$order) return app('json')->fail('数据不存在'); + $data = $this->request->params(['verify_code','data']); + $orderRepository->verifyOrder($order->verify_code, $merId, $data, $this->request->serviceInfo()->service_id); + return app('json')->success('订单核销成功'); + } + +} diff --git a/app/controller/api/server/StoreOrder.php.bak b/app/controller/api/server/StoreOrder.php.bak new file mode 100644 index 00000000..f956034f --- /dev/null +++ b/app/controller/api/server/StoreOrder.php.bak @@ -0,0 +1,336 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\server; + + +use app\common\repositories\delivery\DeliveryStationRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\controller\merchant\Common; +use crmeb\basic\BaseController; +use think\App; +use think\exception\HttpResponseException; +use think\exception\ValidateException; +use think\facade\Db; +use think\response\Json; + +class StoreOrder extends BaseController +{ + public function __construct(App $app) + { + parent::__construct($app); + } + + public function orderStatistics($merId, StoreOrderRepository $repository) + { + $order = $repository->OrderTitleNumber($merId, null); + $order['refund'] = app()->make(StoreRefundOrderRepository::class)->getWhereCount(['is_system_del' => 0, 'mer_id' => $merId]); + $common = app()->make(Common::class); + $data = []; + $data['today'] = $common->mainGroup('today', $merId); + $data['yesterday'] = $common->mainGroup('yesterday', $merId); + $data['month'] = $common->mainGroup('month', $merId); + return app('json')->success(compact('order', 'data')); + } + + public function orderDetail($merId, StoreOrderRepository $repository) + { + [$page, $limit] = $this->getPage(); + list($start, $stop) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + ], true); + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $where = $this->request->has('start') ? ['dateRange' => compact('start', 'stop')] : []; + $list = $repository->orderGroupNumPage($where, $page, $limit, $merId); + return app('json')->success($list); + } + + public function orderList($merId, StoreOrderRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where['status'] = $this->request->param('status'); + $where['is_verify'] = $this->request->param('is_verify'); + $where['search'] = $this->request->param('store_name'); + $where['mer_id'] = $merId; + $where['is_del'] = 0; + if($where['status'] == 2) $where['order_type'] = 0; + return app('json')->success($repository->merchantGetList($where, $page, $limit)); + } + + public function order($merId, $id, StoreOrderRepository $repository) + { + $detail = $repository->getDetail($id); + if (!$detail) + return app('json')->fail('订单不存在'); + if ($detail['mer_id'] != $merId) + return app('json')->fail('没有权限'); + return app('json')->success($detail->toArray()); + } + + + protected function checkOrderAuth($merId, $id) + { + if (!app()->make(StoreOrderRepository::class)->existsWhere(['mer_id' => $merId, 'order_id' => $id])) + throw new ValidateException('没有权限'); + } + + public function mark($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + $data = $this->request->params(['remark']); + $repository->update($id, $data); + return app('json')->success('备注成功'); + } + + public function price($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + + $data = $this->request->params(['total_price', 'pay_postage']); + + if ($data['total_price'] < 0 || $data['pay_postage'] < 0) + return app('json')->fail('金额不可未负数'); + if (!$repository->merStatusExists((int)$id, $merId)) + return app('json')->fail('订单信息或状态错误'); + $repository->eidt($id, $data); + return app('json')->success('修改成功'); + } + + /** + * TODO 发货操作 + * @param $merId + * @param $id + * @param StoreOrderRepository $repository + * @return Json + * @author Qinii + * @day 6/1/22 + */ + public function delivery($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + $type = $this->request->param('delivery_type'); + $split = $this->request->params(['is_split',['split',[]]]); + if (!$repository->merDeliveryExists($id, $merId)) + return app('json')->fail('订单信息或状态错误'); + switch ($type) + { + case 3: //虚拟发货 + $data = $this->request->params([ + 'delivery_type', + 'remark', + ]); + $data['delivery_name'] = ''; + $data['delivery_id'] = ''; + $method = 'delivery'; + break; + case 4: //电子面单 + if (!systemConfig('crmeb_serve_dump')) + return app('json')->fail('电子面单功能未开启'); + $data = $this->request->params([ + 'delivery_type', + 'delivery_name', + 'from_name', + 'from_tel', + 'from_addr', + 'temp_id', + 'remark', + ]); + if (!$data['from_name'] || + !$data['delivery_name'] || + !$data['from_tel'] || + !$data['from_addr'] || + !$data['temp_id'] + ) + return app('json')->fail('填写配送信息'); + $method = 'dump'; + break; + case 5: //同城配送 + if (systemConfig('delivery_status') != 1) + return app('json')->fail('未开启同城配送'); + $data = $this->request->params([ + 'delivery_type', + 'station_id', + 'mark', + ['cargo_weight',0], + 'remark', + ]); + if ($data['cargo_weight'] < 0) return app('json')->fail('包裹重量能为负数'); + if (!$data['station_id']) return app('json')->fail('请选择门店'); + $method = 'cityDelivery'; + break; + default: //快递 + $data = $this->request->params([ + 'delivery_type', + 'delivery_type', + 'delivery_name', + 'delivery_id', + 'remark', + ]); + if (!$data['delivery_type'] || !$data['delivery_name'] || !$data['delivery_id']) + return app('json')->fail('填写配送信息'); + + $method = 'delivery'; + break; + } + $repository->runDelivery($id,$merId, $data, $split, $method, $this->request->serviceInfo()->service_id); + return app('json')->success('发货成功'); + } + + public function payPrice($merId, StoreOrderRepository $repository) + { + list($start, $stop, $month) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + 'month' + ], true); + + if ($month) { + $start = date('Y/m/d', strtotime(getStartModelTime('month'))); + $stop = date('Y/m/d H:i:s', strtotime('+ 1day')); + $front = date('Y/m/d', strtotime('first Day of this month', strtotime('-1 day', strtotime('first Day of this month')))); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } else { + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $space = bcsub($stop, $start, 0);//间隔时间段 + $front = bcsub($start, $space, 0);//第一个时间段 + + $front = date('Y/m/d H:i:s', $front); + $start = date('Y/m/d H:i:s', $start); + $stop = date('Y/m/d H:i:s', $stop); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } + $frontPrice = $repository->dateOrderPrice($front . '-' . $end, $merId); + $afterPrice = $repository->dateOrderPrice($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $chartInfo = $repository->chartTimePrice($start, date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $data['chart'] = $chartInfo;//营业额图表数据 + $data['time'] = $afterPrice;//时间区间营业额 + $increase = (float)bcsub((string)$afterPrice, (string)$frontPrice, 2); //同比上个时间区间增长营业额 + $growthRate = abs($increase); + if ($growthRate == 0) $data['growth_rate'] = 0; + else if ($frontPrice == 0) $data['growth_rate'] = bcmul($growthRate, 100, 0); + else $data['growth_rate'] = (int)bcmul((string)bcdiv((string)$growthRate, (string)$frontPrice, 2), '100', 0);//时间区间增长率 + $data['increase_time'] = abs($increase); //同比上个时间区间增长营业额 + $data['increase_time_status'] = $increase >= 0 ? 1 : 2; //同比上个时间区间增长营业额增长 1 减少 2 + + return app('json')->success($data); + } + + /** + * @param StoreOrderRepository $repository + * @return Json + * @author xaboy + * @day 2020/8/27 + */ + public function payNumber($merId, StoreOrderRepository $repository) + { + list($start, $stop, $month) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + 'month' + ], true); + + if ($month) { + $start = date('Y/m/d', strtotime(getStartModelTime('month'))); + $stop = date('Y/m/d H:i:s', strtotime('+ 1day')); + $front = date('Y/m/d', strtotime('first Day of this month', strtotime('-1 day', strtotime('first Day of this month')))); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } else { + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $space = bcsub($stop, $start, 0);//间隔时间段 + $front = bcsub($start, $space, 0);//第一个时间段 + + $front = date('Y/m/d H:i:s', $front); + $start = date('Y/m/d H:i:s', $start); + $stop = date('Y/m/d H:i:s', $stop); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } + $frontNumber = $repository->dateOrderNum($front . '-' . $end, $merId); + $afterNumber = $repository->dateOrderNum($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $chartInfo = $repository->chartTimeNum($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $data['chart'] = $chartInfo;//订单数图表数据 + $data['time'] = $afterNumber;//时间区间订单数 + $increase = $afterNumber - $frontNumber; //同比上个时间区间增长订单数 + $growthRate = abs($increase); + if ($growthRate == 0) $data['growth_rate'] = 0; + else if ($frontNumber == 0) $data['growth_rate'] = bcmul($growthRate, 100, 0); + else $data['growth_rate'] = (int)bcmul((string)bcdiv((string)$growthRate, (string)$frontNumber, 2), '100', 0);//时间区间增长率 + $data['increase_time'] = abs($increase); //同比上个时间区间增长营业额 + $data['increase_time_status'] = $increase >= 0 ? 1 : 2; //同比上个时间区间增长营业额增长 1 减少 2 + + return app('json')->success($data); + } + + public function getFormData($merId) + { + $config = [ + 'mer_from_com', + 'mer_from_name', + 'mer_from_tel', + 'mer_from_addr', + 'mer_config_siid', + 'mer_config_temp_id' + ]; + $data = merchantConfig($merId,$config); + return app('json')->success($data); + } + + public function getDeliveryConfig() + { + $data = systemConfig(['crmeb_serve_dump','delivery_status']); + return app('json')->success($data); + } + + public function getDeliveryOptions($merId, DeliveryStationRepository $repository) + { + if (!systemConfig('delivery_status')) { + return app('json')->success([]); + } + $where = [ + 'status' => 1, + 'mer_id' => $merId, + 'type' => systemConfig('delivery_type'), + ]; + $data = $repository->getOptions($where)->toArray(); + $type = systemConfig('delivery_type') == 1 ? 'UU' : '达达'; + if (empty($data)) return app('json')->fail('请前往商户后台添加'.$type.'发货点'); + return app('json')->success($data); + } + + public function verify($merId,$id,StoreOrderRepository $orderRepository) + { + $order = $orderRepository->getWhere(['order_id' => $id,'mer_id' => $merId]); + if (!$order) return app('json')->fail('数据不存在'); + $data = $this->request->params(['verify_code','data']); + $orderRepository->verifyOrder($order->verify_code, $merId, $data, $this->request->serviceInfo()->service_id); + return app('json')->success('订单核销成功'); + } + +} diff --git a/app/controller/api/server/StoreProduct.php b/app/controller/api/server/StoreProduct.php new file mode 100644 index 00000000..21d17a96 --- /dev/null +++ b/app/controller/api/server/StoreProduct.php @@ -0,0 +1,211 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\server; + +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\product\ProductLabelRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\merchant\StoreProductValidate; +use crmeb\basic\BaseController; +use crmeb\services\UploadService; +use think\App; +use think\exception\HttpResponseException; +use think\exception\ValidateException; + +class StoreProduct extends BaseController +{ + protected $merId; + protected $repository; + + public function __construct(App $app, ProductRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->route('merId'); + } + + /** + * TODO 头部统计 + * @param $merId + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function title($merId) + { + return app('json')->success($this->repository->getFilter($merId, '', 0)); + } + + /** + * TODO 列表 + * @param $merId + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function lst($merId) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['cate_id', 'keyword', ['type',20], 'mer_cate_id', 'is_gift_bag', 'status', 'us_status', 'product_id', 'mer_labels',['order','sort']]); + $where = array_merge($where, $this->repository->switchType($where['type'], $merId, 0)); + return app('json')->success($this->repository->getList($merId, $where, $page, $limit)); + } + + /** + * TODO 添加 + * @param $merId + * @param StoreProductValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function create($merId, StoreProductValidate $validate) + { + $res = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($res,$merId); + $data['mer_id'] = $merId; + $data['is_gift_bag'] = 0; + $merchant = app()->make(MerchantRepository::class)->get($merId); + $data['status'] = $merchant->is_audit ? 0 : 1; + $data['mer_status'] = ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1; + $data['rate'] = 3; + if ($merchant['type_id']==12){ + $product_type=98;//供应链 + }else{ + $product_type=0;//普通商品 + } + $this->repository->create($data, $product_type, 1); + return app('json')->success('添加成功'); + } + + /** + * TODO 编辑 + * @param $merId + * @param $id + * @param StoreProductValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function update($merId, $id, StoreProductValidate $validate) + { + $res = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($res,$merId,$id); + + $merchant = app()->make(MerchantRepository::class)->get($merId); + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $pro = $this->repository->getWhere(['product_id' => $id]); + if ($pro->status == -2) { + $data['status'] = 0; + } else { + $data['status'] = $merchant->is_audit ? 0 : 1; + } + $data['mer_status'] = ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1; + $data['mer_id'] = $merId; + $this->repository->edit($id, $data, $merId, 0, 1); + return app('json')->success('编辑成功'); + } + + /** + * TODO 详情 + * @param $merId + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function detail($merId, $id) + { + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id, 0, 1)); + } + + /** + * TODO 修改状态 + * @param $merId + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function switchStatus($merId, $id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $this->repository->switchShow($id,$status, 'is_show',$merId); + return app('json')->success('修改成功'); + } + + /** + * TODO 加入回收站 + * @param $merId + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function delete($merId, $id) + { + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->getWhereCount(['product_id' => $id, 'is_show' => 1, 'status' => 1])) + return app('json')->fail('商品上架中'); + $this->repository->delete($id); + return app('json')->success('转入回收站'); + } + + public function config($merId) + { + $data['extension_status'] = systemConfig('extension_status'); + $data['integral_status'] = 0; + $data['integral_rate'] = 0; + if(systemConfig('integral_status') && merchantConfig($merId,'mer_integral_status')) { + $data['integral_status'] = 1; + $data['integral_rate'] = merchantConfig($merId,'mer_integral_rate'); + } + $merchant = app()->make(MerchantRepository::class)->get($merId); + $data['delivery_way'] = $merchant->delivery_way; + return app('json')->success($data); + } + + public function restore($id) + { + if (!$this->repository->merDeleteExists($this->merId, $id)) + return app('json')->fail('只能删除回收站的商品'); + $this->repository->restore($id); + return app('json')->success('商品已恢复'); + } + + public function destory($id) + { + if (!$this->repository->merDeleteExists($this->merId, $id)) + return app('json')->fail('只能删除回收站的商品'); + if (app()->make(StoreCartRepository::class)->getProductById($id)) + return app('json')->fail('商品有被加入购物车不可删除'); + $this->repository->destory($id); + return app('json')->success('删除成功'); + } + + public function updateGood($id) + { + $is_good = $this->request->param('is_good', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id, ['is_good' => $is_good]); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/api/server/StoreProduct.php.bak b/app/controller/api/server/StoreProduct.php.bak new file mode 100644 index 00000000..d39a5ffd --- /dev/null +++ b/app/controller/api/server/StoreProduct.php.bak @@ -0,0 +1,206 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\server; + +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\product\ProductLabelRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\merchant\StoreProductValidate; +use crmeb\basic\BaseController; +use crmeb\services\UploadService; +use think\App; +use think\exception\HttpResponseException; +use think\exception\ValidateException; + +class StoreProduct extends BaseController +{ + protected $merId; + protected $repository; + + public function __construct(App $app, ProductRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->route('merId'); + } + + /** + * TODO 头部统计 + * @param $merId + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function title($merId) + { + return app('json')->success($this->repository->getFilter($merId, '', 0)); + } + + /** + * TODO 列表 + * @param $merId + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function lst($merId) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['cate_id', 'keyword', ['type',20], 'mer_cate_id', 'is_gift_bag', 'status', 'us_status', 'product_id', 'mer_labels',['order','sort']]); + $where = array_merge($where, $this->repository->switchType($where['type'], $merId, 0)); + return app('json')->success($this->repository->getList($merId, $where, $page, $limit)); + } + + /** + * TODO 添加 + * @param $merId + * @param StoreProductValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function create($merId, StoreProductValidate $validate) + { + $res = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($res,$merId); + $data['mer_id'] = $merId; + $data['is_gift_bag'] = 0; + $merchant = app()->make(MerchantRepository::class)->get($merId); + $data['status'] = $merchant->is_audit ? 0 : 1; + $data['mer_status'] = ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1; + $data['rate'] = 3; + $this->repository->create($data, 0, 1); + return app('json')->success('添加成功'); + } + + /** + * TODO 编辑 + * @param $merId + * @param $id + * @param StoreProductValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function update($merId, $id, StoreProductValidate $validate) + { + $res = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($res,$merId,$id); + + $merchant = app()->make(MerchantRepository::class)->get($merId); + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $pro = $this->repository->getWhere(['product_id' => $id]); + if ($pro->status == -2) { + $data['status'] = 0; + } else { + $data['status'] = $merchant->is_audit ? 0 : 1; + } + $data['mer_status'] = ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1; + $data['mer_id'] = $merId; + $this->repository->edit($id, $data, $merId, 0, 1); + return app('json')->success('编辑成功'); + } + + /** + * TODO 详情 + * @param $merId + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function detail($merId, $id) + { + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id, 0, 1)); + } + + /** + * TODO 修改状态 + * @param $merId + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function switchStatus($merId, $id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $this->repository->switchShow($id,$status, 'is_show',$merId); + return app('json')->success('修改成功'); + } + + /** + * TODO 加入回收站 + * @param $merId + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 8/24/21 + */ + public function delete($merId, $id) + { + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->getWhereCount(['product_id' => $id, 'is_show' => 1, 'status' => 1])) + return app('json')->fail('商品上架中'); + $this->repository->delete($id); + return app('json')->success('转入回收站'); + } + + public function config($merId) + { + $data['extension_status'] = systemConfig('extension_status'); + $data['integral_status'] = 0; + $data['integral_rate'] = 0; + if(systemConfig('integral_status') && merchantConfig($merId,'mer_integral_status')) { + $data['integral_status'] = 1; + $data['integral_rate'] = merchantConfig($merId,'mer_integral_rate'); + } + $merchant = app()->make(MerchantRepository::class)->get($merId); + $data['delivery_way'] = $merchant->delivery_way; + return app('json')->success($data); + } + + public function restore($id) + { + if (!$this->repository->merDeleteExists($this->merId, $id)) + return app('json')->fail('只能删除回收站的商品'); + $this->repository->restore($id); + return app('json')->success('商品已恢复'); + } + + public function destory($id) + { + if (!$this->repository->merDeleteExists($this->merId, $id)) + return app('json')->fail('只能删除回收站的商品'); + if (app()->make(StoreCartRepository::class)->getProductById($id)) + return app('json')->fail('商品有被加入购物车不可删除'); + $this->repository->destory($id); + return app('json')->success('删除成功'); + } + + public function updateGood($id) + { + $is_good = $this->request->param('is_good', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + + $this->repository->update($id, ['is_good' => $is_good]); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/api/server/StoreProductAttrTemplate.php b/app/controller/api/server/StoreProductAttrTemplate.php new file mode 100644 index 00000000..1e51bdd0 --- /dev/null +++ b/app/controller/api/server/StoreProductAttrTemplate.php @@ -0,0 +1,96 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\server; + +use crmeb\basic\BaseController; +use app\common\repositories\store\service\StoreServiceRepository; +use app\validate\merchant\StoreAttrTemplateValidate; +use think\App; +use app\common\repositories\store\StoreAttrTemplateRepository; +use think\exception\HttpResponseException; + +class StoreProductAttrTemplate extends BaseController +{ + protected $merId; + protected $repository; + + public function __construct(App $app, StoreAttrTemplateRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->route('merId'); + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword']); + $data = $this->repository->getList($this->merId, $where, $page, $limit); + + return app('json')->success($data); + } + + public function getlist() + { + return app('json')->success($this->repository->list($this->merId)); + } + + public function create(StoreAttrTemplateValidate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->merId; + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + public function update($id, StoreAttrTemplateValidate $validate) + { + $merId = $this->merId; + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $data = $this->checkParams($validate); + $data['mer_id'] = $merId; + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + public function detail($id) + { + if (!$this->repository->merExists($this->merId, $id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id,$this->merId)); + } + + public function batchDelete() + { + $ids = $this->request->param('ids'); + $merId = $this->merId; + foreach ($ids as $id){ + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('ID:'.$id.' 不存在'); + } + $this->repository->delete($ids, $merId); + + return app('json')->success('删除成功'); + } + + public function checkParams(StoreAttrTemplateValidate $validate) + { + $data = $this->request->params(['template_name', ['template_value', []]]); + $validate->check($data); + return $data; + } + + +} diff --git a/app/controller/api/server/StoreRefundOrder.php b/app/controller/api/server/StoreRefundOrder.php new file mode 100644 index 00000000..2bbc68ef --- /dev/null +++ b/app/controller/api/server/StoreRefundOrder.php @@ -0,0 +1,99 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\server; + +use app\common\repositories\store\order\StoreRefundOrderRepository; +use crmeb\basic\BaseController; +use think\App; + +class StoreRefundOrder extends BaseController +{ + protected $merId; + protected $repository; + protected $service_id; + + public function __construct(App $app, StoreRefundOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->route('merId'); + $this->service_id = $this->request->serviceInfo()->service_id; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['order_type','delivery_id']); + $where['mer_id'] = $this->merId; + return app('json')->success($this->repository->getListByService($where,$page,$limit)); + } + + public function detail($id) + { + $data = $this->repository->getWhere([$this->repository->getPk() => $id,'mer_id' => $this->merId],'*',['order','refundProduct.product','user']); + return app('json')->success($data); + } + + public function getRefundPrice($id) + { + return app('json')->success($this->repository->serverRefundDetail($id,$this->merId)); + } + public function express($id) + { + $data['refund'] = $this->repository->getWhere(['refund_order_id' => $id,'mer_id'=> $this->merId,'status' =>2],'*', ['refundProduct.product']); + if(!$data['refund']) + return app('json')->fail('订单信息或状态错误'); + + $data['express'] = $this->repository->express($id); + return app('json')->success($data); + } + + public function switchStatus($id) + { + if(!$this->repository->getStatusExists($this->merId,$id)) + return app('json')->fail('信息或状态错误'); + $status = ($this->request->param('status') == 1) ? 1 : -1; + event('refund.status',compact('id','status')); + if($status == 1){ + $data = $this->request->params(['mer_delivery_user','mer_delivery_address','phone']); + if ($data['phone'] && isPhone($data['phone'])) + return app('json')->fail('请输入正确的手机号'); + $data['status'] = $status; + $this->repository->agree($id,$data,$this->service_id); + }else{ + $fail_message = $this->request->param('fail_message',''); + if($status == -1 && empty($fail_message)) + return app('json')->fail('未通过必须填写'); + $data['status'] = $status; + $data['fail_message'] = $fail_message; + $this->repository->refuse($id,$data, $this->service_id); + } + return app('json')->success('审核成功'); + } + + public function refundPrice($id) + { + if(!$this->repository->getRefundPriceExists($this->merId,$id)) + return app('json')->fail('信息或状态错误'); + $this->repository->adminRefund($id,$this->service_id); + return app('json')->success('退款成功'); + } + + public function mark($id){ + if(!$this->repository->getExistsById($this->merId,$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['mer_mark' => $this->request->param('mer_mark','')]); + + return app('json')->success('备注成功'); + } + +} diff --git a/app/controller/api/store/broadcast/BroadcastRoom.php b/app/controller/api/store/broadcast/BroadcastRoom.php new file mode 100644 index 00000000..e06405a3 --- /dev/null +++ b/app/controller/api/store/broadcast/BroadcastRoom.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\broadcast; + + +use app\common\repositories\store\broadcast\BroadcastRoomRepository; +use crmeb\basic\BaseController; +use think\App; + +class BroadcastRoom extends BaseController +{ + /** + * @var BroadcastRoomRepository + */ + protected $repository; + + public function __construct(App $app, BroadcastRoomRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->userList([], $page, $limit)); + } + + public function hot() + { + [$page, $limit] = $this->getPage(); + $where = ['hot' => 1]; + $where['mer_id'] = $this->request->param('mer_id'); + return app('json')->success($this->repository->userList($where, $page, $limit)); + } +} diff --git a/app/controller/api/store/merchant/Merchant.php b/app/controller/api/store/merchant/Merchant.php new file mode 100644 index 00000000..9911f07c --- /dev/null +++ b/app/controller/api/store/merchant/Merchant.php @@ -0,0 +1,317 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\merchant; + +use app\common\repositories\store\MerchantTakeRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\financial\FinancialRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserMerchantRepository; +use app\validate\merchant\MerchantFinancialAccountValidate; +use app\validate\merchant\MerchantTakeValidate; +use app\validate\merchant\MerchantUpdateValidate; +use crmeb\jobs\ChangeMerchantStatusJob; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantRepository as repository; +use think\facade\Db; +use think\facade\Queue; + +class Merchant extends BaseController +{ + protected $repository; + protected $userInfo; + + /** + * ProductCategory constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo =$this->request->isLogin() ? $this->request->userInfo():null; + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'order', 'is_best', 'location', 'category_id', 'type_id','is_trader']); + return app('json')->success($this->repository->getList($where, $page, $limit, $this->userInfo)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/29 + * @param $id + * @return mixed + */ + public function detail($id) + { + if (!$this->repository->apiGetOne($id)) + return app('json')->fail('店铺已打烊'); + + if ($this->request->isLogin()) { + app()->make(UserMerchantRepository::class)->updateLastTime($this->request->uid(), intval($id)); + } + + return app('json')->success($this->repository->detail($id, $this->userInfo)); + } + + public function systemDetail() + { + $config = systemConfig(['site_logo', 'site_name','login_logo']); + return app('json')->success([ + 'mer_avatar' => $config['login_logo'], + 'mer_name' => $config['site_name'], + 'mer_id' => 0, + ]); + } + + + + /** + * @Author:Qinii + * @Date: 2020/5/29 + * @param $id + * @return mixed + */ + public function productList($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','order','mer_cate_id','cate_id', 'order', 'price_on', 'price_off', 'brand_id', 'pid']); + if(!$this->repository->apiGetOne($id)) return app('json')->fail(' 店铺已打烊'); + return app('json')->success($this->repository->productList($id,$where, $page, $limit,$this->userInfo)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/29 + * @param int $id + * @return mixed + */ + public function categoryList($id) + { + if(!$this->repository->merExists((int)$id)) + return app('json')->fail('店铺已打烊'); + return app('json')->success($this->repository->categoryList($id)); + } + + public function qrcode($id) + { + if(!$this->repository->merExists($id)) + return app('json')->fail('店铺已打烊'); + $url = $this->request->param('type') == 'routine' ? $this->repository->routineQrcode(intval($id)) : $this->repository->wxQrcode(intval($id)); + return app('json')->success(compact('url')); + } + + public function localLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'order', 'is_best', 'location', 'category_id', 'type_id']); + $where['delivery_way'] = 1; + return app('json')->success($this->repository->getList($where, $page, $limit, $this->userInfo)); + } + /** + * @param MerchantUpdateValidate $validate + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function update(MerchantUpdateValidate $validate, MerchantTakeValidate $takeValidate, MerchantTakeRepository $repository) + { + + $type = $this->request->param('type',1); + $id = $this->request->param('id'); + if(empty($id)){ + return app('json')->fail('参数错误'); + } + + $merchant = Db::name('merchant')->where('mer_id',$id)->find(); + if ($type == 2) { + $data = $this->request->params([ + 'mer_info', + 'mer_certificate', + 'service_phone', + 'mer_avatar', + 'mer_banner', + 'mer_state', + 'mini_banner', + 'mer_keyword', + 'mer_address', + 'long', + 'lat', + ['delivery_way',[2]], + ]); + + // 如果手机号不存在,则使用入驻时的手机号 + $data['service_phone'] = empty($data['service_phone'])?$merchant['mer_phone']:$data['service_phone']; + + $validate->check($data); + $sys_bases_status = systemConfig('sys_bases_status') === '0' ? 0 : 1; + if ($sys_bases_status && empty($data['mer_certificate'])) + return app('json')->fail('店铺资质不可为空'); + + app()->make(ConfigValueRepository::class)->setFormData([ + 'mer_certificate' => $data['mer_certificate'] + ], $id); + unset($data['mer_certificate']); + + foreach ($data['delivery_way'] as $datum) { + if ($datum == 1) { + $takeData = $this->request->params(['mer_take_status', 'mer_take_location', 'mer_take_day', 'mer_take_time']); + $takeData['mer_take_name'] = $merchant['mer_name']; + $takeData['mer_take_address'] = $data['mer_address']; + $takeData['mer_take_phone'] = $merchant['mer_phone']; + $takeValidate->check($takeData); + $repository->set($id, $takeData); + break; + } + } + $delivery_way = implode(',',$data['delivery_way']); + if (count($data['delivery_way']) == 1 && $data['delivery_way'] != $merchant['delivery_way']) { + app()->make(ProductRepository::class)->getSearch([]) + ->where('mer_id',$merchant['mer_id']) + ->update(['delivery_way' => $delivery_way]); + } + + $data['delivery_way'] = $delivery_way; + + } else { + $data = $this->request->params(['mer_state']); + + if ($merchant['is_margin'] == 1 && $data['mer_state'] == 1) + return app('json')->fail('开启店铺前请先支付保证金'); + + if ($data['mer_state'] && !$merchant['sub_mchid'] && systemConfig('open_wx_combine')) + return app('json')->fail('开启店铺前请先完成微信子商户入驻'); + } + Db::name('merchant')->where('mer_id',$id)->update($data); + + Queue::push(ChangeMerchantStatusJob::class, $id); + return app('json')->success('修改成功'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/7/21 + */ + public function info(MerchantTakeRepository $repository) + { + $id = $this->request->param('id'); + if(empty($id)){ + return app('json')->fail('参数错误'); + } + + $data = Db::name('merchant')->where('mer_id',$id)->find(); + // $append = ['merchantCategory', 'merchantType', 'mer_certificate']; + // if ($merchant['is_margin'] == -10) + // $append[] = 'refundMarginOrder'; + + // $data = $merchant->append($append)->hidden(['mark', 'reg_admin_id', 'sort'])->toArray(); + $delivery = $repository->get($id) + systemConfig(['tx_map_key']); + $data = array_merge($data,$delivery); + $data['sys_bases_status'] = systemConfig('sys_bases_status') === '0' ? 0 : 1; + + return app('json')->success($data); + } + + public function apply($merId){ + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $merId])->field('uid,mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay,financial_type')->find(); + if ($this->userInfo['uid'] != $merchant->uid){ + return app('json')->fail('你不是管理员无法进行提现操作'); + } + $extract_minimum_line = systemConfig('extract_minimum_line') ?: 0; + $extract_minimum_num = systemConfig('extract_minimum_num'); + $_line = bcsub($merchant->mer_money,$extract_minimum_line,2); + $_extract = ($_line < 0) ? 0 : $_line; + $data = [ + 'mer_id' => $merchant->mer_id,//商户id + 'mer_name' => $merchant->mer_name,//商户名称 + 'mer_money' => $merchant->mer_money,//商户余额 + 'extract_minimum_line' => $extract_minimum_line,//提现最低额度 + 'extract_minimum_num' => $extract_minimum_num,//提现最低次数 + 'extract_money' => $_extract,//可提现金额 + 'financial_bank_name' => $merchant->financial_bank->name,//银行卡信息 + 'financial_bank_bank' => $merchant->financial_bank->bank,//银行卡信息 + 'financial_bank_code' => $merchant->financial_bank->bank_code,//银行卡信息 + + 'financial_type' => $merchant->financial_type,//提现方式 + ]; + return app('json')->success($data); + } + public function createApply($merId) + { + $data = $this->request->param(['extract_money','financial_type']); + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $merId])->field('reg_admin_id,uid,mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay,financial_type')->find(); + if ($this->userInfo['uid'] != $merchant->uid){ + return app('json')->fail('你不是管理员无法进行提现操作'); + } + $data['mer_admin_id'] = $merchant['reg_admin_id']; + app()->make(FinancialRepository::class)->saveApply($merId,$data); + return app('json')->success('申请成功'); + } + + public function listApply($merId) + { + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $merId])->field('reg_admin_id,uid,mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay,financial_type')->find(); + if ($this->userInfo['uid'] != $merchant->uid){ + return app('json')->fail('你不是管理员无法进行提现操作'); + } + [$page, $limit] = $this->getPage(); + $where['mer_id'] = $merId; + $data = app()->make(FinancialRepository::class)->getAdminList($where,$page,$limit); + return app('json')->success($data); + + } + + public function account($merId) + { + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $merId])->field('uid,mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay,financial_type')->find(); + if ($this->userInfo['uid'] != $merchant->uid){ + return app('json')->fail('你不是管理员无法进行提现操作'); + } + $data = [ + 'financial_bank' => $merchant->financial_bank,//银行卡信息 + 'financial_wechat' => $merchant->financial_wechat,//微信信息 + 'financial_alipay' => $merchant->financial_alipay,//支付宝信息 + 'financial_type' => $merchant->financial_type,//提现方式 + ]; + return app('json')->success($data); + } + + public function account_info($merId) + { + $data = $this->request->param(['name','bank','bank_code','financial_type']); + app()->make(MerchantFinancialAccountValidate::class)->check($data); + $merchant = app()->make(MerchantRepository::class)->search(['mer_id' => $merId])->field('uid,mer_id,mer_name,mer_money,financial_bank,financial_wechat,financial_alipay,financial_type')->find(); + if ($this->userInfo['uid'] != $merchant->uid){ + return app('json')->fail('你不是管理员无法进行提现操作'); + } + $update = [ + 'name' => $data['name'], + 'bank' => $data['bank'], + 'bank_code' => $data['bank_code'], + ]; + app()->make(MerchantRepository::class)->update($merId,['financial_bank' => json_encode($update),'financial_type' => 1]); + return app('json')->success('提交成功'); + } +} diff --git a/app/controller/api/store/merchant/Merchant.php.bak b/app/controller/api/store/merchant/Merchant.php.bak new file mode 100644 index 00000000..0719b505 --- /dev/null +++ b/app/controller/api/store/merchant/Merchant.php.bak @@ -0,0 +1,122 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\merchant; + +use app\common\repositories\user\UserMerchantRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantRepository as repository; + +class Merchant extends BaseController +{ + protected $repository; + protected $userInfo; + + /** + * ProductCategory constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo =$this->request->isLogin() ? $this->request->userInfo():null; + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'order', 'is_best', 'location', 'category_id', 'type_id','is_trader']); + return app('json')->success($this->repository->getList($where, $page, $limit, $this->userInfo)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/29 + * @param $id + * @return mixed + */ + public function detail($id) + { + if (!$this->repository->apiGetOne($id)) + return app('json')->fail('店铺已打烊'); + + if ($this->request->isLogin()) { + app()->make(UserMerchantRepository::class)->updateLastTime($this->request->uid(), intval($id)); + } + + return app('json')->success($this->repository->detail($id, $this->userInfo)); + } + + public function systemDetail() + { + $config = systemConfig(['site_logo', 'site_name','login_logo']); + return app('json')->success([ + 'mer_avatar' => $config['login_logo'], + 'mer_name' => $config['site_name'], + 'mer_id' => 0, + ]); + } + + + + /** + * @Author:Qinii + * @Date: 2020/5/29 + * @param $id + * @return mixed + */ + public function productList($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','order','mer_cate_id','cate_id', 'order', 'price_on', 'price_off', 'brand_id', 'pid']); + if(!$this->repository->apiGetOne($id)) return app('json')->fail(' 店铺已打烊'); + return app('json')->success($this->repository->productList($id,$where, $page, $limit,$this->userInfo)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/29 + * @param int $id + * @return mixed + */ + public function categoryList($id) + { + if(!$this->repository->merExists((int)$id)) + return app('json')->fail('店铺已打烊'); + return app('json')->success($this->repository->categoryList($id)); + } + + public function qrcode($id) + { + if(!$this->repository->merExists($id)) + return app('json')->fail('店铺已打烊'); + $url = $this->request->param('type') == 'routine' ? $this->repository->routineQrcode(intval($id)) : $this->repository->wxQrcode(intval($id)); + return app('json')->success(compact('url')); + } + + public function localLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'order', 'is_best', 'location', 'category_id', 'type_id']); + $where['delivery_way'] = 1; + return app('json')->success($this->repository->getList($where, $page, $limit, $this->userInfo)); + } + +} diff --git a/app/controller/api/store/merchant/MerchantIntention.php b/app/controller/api/store/merchant/MerchantIntention.php new file mode 100644 index 00000000..b010941c --- /dev/null +++ b/app/controller/api/store/merchant/MerchantIntention.php @@ -0,0 +1,152 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\merchant; + +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\merchant\MerchantTypeRepository; +use app\validate\api\MerchantIntentionValidate; +use crmeb\services\SmsService; +use crmeb\services\SwooleTaskService; +use crmeb\services\YunxinSmsService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantIntentionRepository as repository; +use think\exception\ValidateException; + +class MerchantIntention extends BaseController +{ + protected $repository; + protected $userInfo; + + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + public function create() + { + $data = $this->checkParams(); + if (!systemConfig('mer_intention_open')) { + return app('json')->fail('未开启商户入驻'); + } + if ($this->userInfo) $data['uid'] = $this->userInfo->uid; + $make = app()->make(MerchantRepository::class); + if ($make->fieldExists('mer_name', $data['mer_name'])) + throw new ValidateException('商户名称已存在,不可申请'); + if ($make->fieldExists('mer_phone', $data['phone'])) + throw new ValidateException('手机号已存在,不可申请'); + $adminRepository = app()->make(MerchantAdminRepository::class); + if ($adminRepository->fieldExists('account', $data['phone'])) + throw new ValidateException('手机号已是管理员,不可申请'); + $intention = $this->repository->create($data); + SwooleTaskService::admin('notice', [ + 'type' => 'new_intention', + 'data' => [ + 'title' => '商户入驻申请', + 'message' => '您有一个新的商户入驻申请', + 'id' => $intention->mer_intention_id + ] + ]); + return app('json')->success('提交成功'); + } + + public function update($id) + { + if (!$this->repository->getWhere(['mer_intention_id' => (int)$id, 'uid' => $this->userInfo->uid, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + $data = $this->checkParams(); + if (!systemConfig('mer_intention_open')) { + return app('json')->fail('未开启商户入驻'); + } + $data['create_time'] = date('Y-m-d H:i:s', time()); + $this->repository->updateIntention((int)$id, $data); + SwooleTaskService::admin('notice', [ + 'type' => 'new_intention', + 'data' => [ + 'title' => '商户入驻申请', + 'message' => '您有一个新的商户入驻申请', + 'id' => $id + ] + ]); + return app('json')->success('修改成功'); + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $data = $this->repository->getList(['uid' => $this->userInfo->uid], $page, $limit); + return app('json')->success($data); + } + + function detail($id) + { + $data = $this->repository->detail((int)$id, $this->userInfo->uid); + if (!$data) { + return app('json')->fail('数据不存在'); + } + if ($data->status == 1) { + $data['login_url'] = rtrim(systemConfig('site_url'), '/') . '/' . config('admin.merchant_prefix'); + } + return app('json')->success($data); + } + + protected function checkParams() + { + $data = $this->request->params([ + 'phone', + 'mer_name', + 'name', + 'code', + 'images', + 'merchant_category_id', + 'mer_type_id', + 'area_id', + 'street_id', + 'village_id', + 'is_nmsc' + ]); + + app()->make(MerchantIntentionValidate::class)->check($data); + $check = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['code'], 'intention'); + $data['mer_type_id'] = (int)$data['mer_type_id']; + if (!$check) throw new ValidateException('验证码不正确'); + if (!app()->make(MerchantCategoryRepository::class)->get($data['merchant_category_id'])) throw new ValidateException('商户分类不存在'); + if ($data['mer_type_id'] && !app()->make(MerchantTypeRepository::class)->exists($data['mer_type_id'])) + throw new ValidateException('店铺类型不存在'); + unset($data['code']); + return $data; + } + + /** + * 商户分类 + * @Author:Qinii + * @Date: 2020/9/15 + * @return mixed + */ + public function cateLst() + { + $lst = app()->make(MerchantCategoryRepository::class)->getSelect(); + return app('json')->success($lst); + } + + public function typeLst() + { + $lst = app()->make(MerchantTypeRepository::class)->getSelect(); + return app('json')->success($lst); + } +} + diff --git a/app/controller/api/store/merchant/MerchantIntention.php.bak b/app/controller/api/store/merchant/MerchantIntention.php.bak new file mode 100644 index 00000000..cc0f8236 --- /dev/null +++ b/app/controller/api/store/merchant/MerchantIntention.php.bak @@ -0,0 +1,139 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\merchant; + +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\common\repositories\system\merchant\MerchantCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\merchant\MerchantTypeRepository; +use app\validate\api\MerchantIntentionValidate; +use crmeb\services\SmsService; +use crmeb\services\SwooleTaskService; +use crmeb\services\YunxinSmsService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantIntentionRepository as repository; +use think\exception\ValidateException; + +class MerchantIntention extends BaseController +{ + protected $repository; + protected $userInfo; + + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + public function create() + { + $data = $this->checkParams(); + if (!systemConfig('mer_intention_open')) { + return app('json')->fail('未开启商户入驻'); + } + if ($this->userInfo) $data['uid'] = $this->userInfo->uid; + $make = app()->make(MerchantRepository::class); + if ($make->fieldExists('mer_name', $data['mer_name'])) + throw new ValidateException('商户名称已存在,不可申请'); + if ($make->fieldExists('mer_phone', $data['phone'])) + throw new ValidateException('手机号已存在,不可申请'); + $adminRepository = app()->make(MerchantAdminRepository::class); + if ($adminRepository->fieldExists('account', $data['phone'])) + throw new ValidateException('手机号已是管理员,不可申请'); + $intention = $this->repository->create($data); + SwooleTaskService::admin('notice', [ + 'type' => 'new_intention', + 'data' => [ + 'title' => '商户入驻申请', + 'message' => '您有一个新的商户入驻申请', + 'id' => $intention->mer_intention_id + ] + ]); + return app('json')->success('提交成功'); + } + + public function update($id) + { + if (!$this->repository->getWhere(['mer_intention_id' => (int)$id, 'uid' => $this->userInfo->uid, 'is_del' => 0])) + return app('json')->fail('数据不存在'); + $data = $this->checkParams(); + if (!systemConfig('mer_intention_open')) { + return app('json')->fail('未开启商户入驻'); + } + $data['create_time'] = date('Y-m-d H:i:s', time()); + $this->repository->updateIntention((int)$id, $data); + SwooleTaskService::admin('notice', [ + 'type' => 'new_intention', + 'data' => [ + 'title' => '商户入驻申请', + 'message' => '您有一个新的商户入驻申请', + 'id' => $id + ] + ]); + return app('json')->success('修改成功'); + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $data = $this->repository->getList(['uid' => $this->userInfo->uid], $page, $limit); + return app('json')->success($data); + } + + function detail($id) + { + $data = $this->repository->detail((int)$id, $this->userInfo->uid); + if (!$data) { + return app('json')->fail('数据不存在'); + } + if ($data->status == 1) { + $data['login_url'] = rtrim(systemConfig('site_url'), '/') . '/' . config('admin.merchant_prefix'); + } + return app('json')->success($data); + } + + protected function checkParams() + { + $data = $this->request->params(['phone', 'mer_name', 'name', 'code', 'images', 'merchant_category_id', 'mer_type_id']); + app()->make(MerchantIntentionValidate::class)->check($data); + $check = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['code'], 'intention'); + $data['mer_type_id'] = (int)$data['mer_type_id']; + if (!$check) throw new ValidateException('验证码不正确'); + if (!app()->make(MerchantCategoryRepository::class)->get($data['merchant_category_id'])) throw new ValidateException('商户分类不存在'); + if ($data['mer_type_id'] && !app()->make(MerchantTypeRepository::class)->exists($data['mer_type_id'])) + throw new ValidateException('店铺类型不存在'); + unset($data['code']); + return $data; + } + + /** + * 商户分类 + * @Author:Qinii + * @Date: 2020/9/15 + * @return mixed + */ + public function cateLst() + { + $lst = app()->make(MerchantCategoryRepository::class)->getSelect(); + return app('json')->success($lst); + } + + public function typeLst() + { + $lst = app()->make(MerchantTypeRepository::class)->getSelect(); + return app('json')->success($lst); + } +} + diff --git a/app/controller/api/store/order/PresellOrder.php b/app/controller/api/store/order/PresellOrder.php new file mode 100644 index 00000000..9d4b519a --- /dev/null +++ b/app/controller/api/store/order/PresellOrder.php @@ -0,0 +1,65 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\order; + + +use app\common\repositories\store\order\PresellOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class PresellOrder extends BaseController +{ + protected $repository; + + public function __construct(App $app, PresellOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function pay($id) + { + $type = $this->request->param('type'); + if (!in_array($type, StoreOrderRepository::PAY_TYPE)) + return app('json')->fail('请选择正确的支付方式'); + + $order = $this->repository->userOrder($this->request->uid(), intval($id)); + if (!$order) + throw new ValidateException('尾款订单不存在'); + if ($order->paid) + throw new ValidateException('已支付'); + if (!$order->status) + throw new ValidateException('尾款订单以失效'); + if (strtotime($order->final_start_time) > time()) + throw new ValidateException('未到尾款支付时间'); + if (strtotime($order->final_end_time) < time()) + throw new ValidateException('已过尾款支付时间'); + + $order->pay_type = array_search($type, StoreOrderRepository::PAY_TYPE); + $order->save(); + + if ($order['pay_price'] == 0) { + $this->repository->paySuccess($order); + return app('json')->status('success', '支付成功', ['order_id' => $order['presell_order_id']]); + } + + try { + return $this->repository->pay($type, $this->request->userInfo(), $order, $this->request->param('return_url'), $this->request->isApp()); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $order->presell_order_id]); + } + } +} diff --git a/app/controller/api/store/order/StoreCart.php b/app/controller/api/store/order/StoreCart.php new file mode 100644 index 00000000..1ec93c24 --- /dev/null +++ b/app/controller/api/store/order/StoreCart.php @@ -0,0 +1,270 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\order; + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductAssistRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\StoreDiscountProductRepository; +use app\common\repositories\store\product\StoreDiscountRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\user\UserRepository; +use MongoDB\BSON\MaxKey; +use think\App; +use crmeb\basic\BaseController; +use app\validate\api\StoreCartValidate as validate; +use app\common\repositories\store\order\StoreCartRepository as repository; +use think\exception\ValidateException; + +class StoreCart extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * StoreBrand constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @return mixed + */ + public function lst($product_type=0) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($this->request->userInfo(),$product_type)); + } + + /** + * @param validate $validate + * @return mixed + * @author Qinii + */ + public function create(validate $validate) + { + $data = $this->checkParams($validate); + if(!in_array($data['product_type'],[0,1,2,3,4,98])) return app('json')->fail('商品类型错误'); + if ($data['cart_num'] <= 0) return app('json')->fail('购买数量有误'); + $user = $this->request->userInfo(); + event('user.cart.before',compact('user','data')); + switch ($data['product_type']) + { + case 0: //普通商品 + case 98: //供应链商品 + $result = app()->make(ProductRepository::class)->cartCheck($data,$this->request->userInfo()); + [$source, $sourceId, $pid] = explode(':', $this->request->param('source', '0'), 3) + ['', '', '']; + $data['source'] = (in_array($source, [0, 1]) && $pid == $data['product_id']) ? $source : 0; + if ($data['source'] > 0) $data['source_id'] = intval($sourceId); + break; + case 1: //秒杀商品 + $result = app()->make(ProductRepository::class)->cartSeckillCheck($data,$this->request->userInfo()); + break; + case 2: //预售商品 + $result = app()->make(ProductPresellRepository::class)->cartCheck($data,$this->request->userInfo()); + $data['source'] = $data['product_type']; + $data['source_id'] = $data['product_id']; + $data['product_id'] = $result['product']['product_id']; + break; + case 3: //助力商品 + $result = app()->make(ProductAssistSetRepository::class)->cartCheck($data,$this->request->userInfo()); + $data['source'] = $data['product_type']; + $data['source_id'] = $data['product_id']; + $data['product_id'] = $result['product']['product_id']; + break; + case 4: //拼团商品 + $result = app()->make(ProductGroupRepository::class)->cartCheck($data,$this->request->userInfo()); + $data['source'] = $data['product_type']; + $data['source_id'] = $data['group_buying_id']; + $data['product_id'] = $result['product']['product_id']; + break; + + } + + unset($data['group_buying_id']); + if ($cart = $result['cart']) { + //更新购物车 + $cart_id = $cart['cart_id']; + $cart_num = ['cart_num' => ($cart['cart_num'] + $data['cart_num'])]; + $storeCart = $this->repository->update($cart_id,$cart_num); + } else { + //添加购物车 + $data['uid'] = $this->request->uid(); + $data['mer_id'] = $result['product']['mer_id']; + $cart = $storeCart = $this->repository->create($data); + } + event('user.cart', compact('user','storeCart')); + return app('json')->success(['cart_id' => $cart['cart_id']]); + } + + + /** + * @param $id + * @return mixed + * @throws \think\db\exception\DbException + * @author Qinii + */ + public function change($id) + { + $where = $this->request->params(['cart_num']); + $product_attr_unique = $this->request->param('product_attr_unique'); + if (intval($where['cart_num']) < 0) + return app('json')->fail('数量必须大于0'); + if (!$cart = $this->repository->getOne($id, $this->request->uid())) + return app('json')->fail('购物车信息不存在'); + if ($cart->product->once_count) { + $cart_num = app()->make(ProductRepository::class)->productOnceCountCart($cart['product_id'], $this->request->uid()); + if (($cart_num - $cart['cart_num'] + $where['cart_num']) > $cart->product->once_count) + return app('json')->fail('单次购买限制 ' . $cart->product->once_count . ' 件'); + } + if (!$res = app()->make(ProductAttrValueRepository::class)->getOptionByUnique($product_attr_unique ?? $cart['product_attr_unique'])) + return app('json')->fail('SKU不存在'); + if ($res['stock'] < $where['cart_num']) + return app('json')->fail('库存不足'); + if($product_attr_unique){ + $where['product_attr_unique'] = $product_attr_unique; + } + $this->repository->update($id, $where); + return app('json')->success('修改成功'); + } + + /** + * @return mixed + * @author Qinii + */ + public function batchDelete() + { + $ids = $this->request->param('cart_id'); + if(!count($ids))return app('json')->fail('参数错误'); + $this->repository->batchDelete($ids,$this->request->uid()); + return app('json')->success('删除成功'); + } + + + /** + * @return mixed + * @author Qinii + */ + public function cartCount($product_type=0) + { + return app('json')->success($this->repository->getCartCount($this->request->uid(),$product_type)); + } + + /** + * @param $data + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function check($data) + { + $product = app()->make(ProductRepository::class)->get($data['product_id']); + if(!$product) + throw new ValidateException('商品不存在'); + if( $data['cart_num'] < 0 ) + throw new ValidateException('数量必须大于0'); + if(!$res= app()->make(ProductAttrValueRepository::class)->getOptionByUnique($data['product_attr_unique'])) + throw new ValidateException('SKU不存在'); + if($res['product_id'] != $data['product_id']) + throw new ValidateException('数据不一致'); + if($res['stock'] < $data['cart_num']) + throw new ValidateException('库存不足'); + $data['is_new'] = 1; + $data['uid'] = $this->request->uid(); + $data['mer_id'] = $product['mer_id']; + return $data; + } + + + /** + * @param validate $validate + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function again(validate $validate) + { + $param = $this->request->param('data',[]); + foreach ($param as $data){ + $validate->check($data); + $item[] = $this->check($data); + } + + foreach ($item as $it){ + $it__id = $this->repository->create($it); + $ids[] = $it__id['cart_id']; + } + return app('json')->success(['cart_id' => $ids]); + } + + + /** + * @param validate $validate + * @return array + * @author Qinii + * @day 2020-06-11 + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['product_id','product_attr_unique','cart_num','is_new',['product_type',0],['group_buying_id',0],['spread_id',0]]); + $validate->check($data); + if ($data['spread_id']) { + if ($data['spread_id'] !== $this->request->userInfo()->uid){ + $user = app()->make(UserRepository::class)->get($data['spread_id']); + if (!$user) $data['spread_id'] = 0; + } else { + $data['spread_id'] = 0; + } + } + return $data; + } + + /** + * TODO 套餐购买 + * @return \think\response\Json + * @author Qinii + * @day 1/7/22 + */ + public function batchCreate() + { + $data = $this->request->params(['data','discount_id','is_new']); + $productRepostory = app()->make(ProductRepository::class); + if (!$data['discount_id']) + return app('json')->fail('优惠套餐ID不能为空'); + if (!$data['is_new']) + return app('json')->fail('套餐不能加入购物车'); + + $cartData = app()->make(StoreDiscountRepository::class)->check($data['discount_id'], $data['data'], $this->request->userInfo()); + $cart_id = []; + if ($cartData){ + foreach ($cartData as $datum) { + $cart = $this->repository->create($datum); + $cart_id[] = $cart['cart_id']; + } + } + return app('json')->success(compact('cart_id')); + } +} diff --git a/app/controller/api/store/order/StoreCart.php.bak b/app/controller/api/store/order/StoreCart.php.bak new file mode 100644 index 00000000..6156aa4b --- /dev/null +++ b/app/controller/api/store/order/StoreCart.php.bak @@ -0,0 +1,271 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\order; + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductAssistRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\StoreDiscountProductRepository; +use app\common\repositories\store\product\StoreDiscountRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\user\UserRepository; +use MongoDB\BSON\MaxKey; +use think\App; +use crmeb\basic\BaseController; +use app\validate\api\StoreCartValidate as validate; +use app\common\repositories\store\order\StoreCartRepository as repository; +use think\exception\ValidateException; + +class StoreCart extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * StoreBrand constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($this->request->userInfo())); + } + + /** + * @param validate $validate + * @return mixed + * @author Qinii + */ + public function create(validate $validate) + { + $data = $this->checkParams($validate); + + if(!in_array($data['product_type'],[0,1,2,3,4])) return app('json')->fail('商品类型错误'); + if ($data['cart_num'] <= 0) return app('json')->fail('购买数量有误'); + $user = $this->request->userInfo(); + event('user.cart.before',compact('user','data')); + switch ($data['product_type']) + { + case 0: //普通商品 + $result = app()->make(ProductRepository::class)->cartCheck($data,$this->request->userInfo()); + + [$source, $sourceId, $pid] = explode(':', $this->request->param('source', '0'), 3) + ['', '', '']; + $data['source'] = (in_array($source, [0, 1]) && $pid == $data['product_id']) ? $source : 0; + if ($data['source'] > 0) $data['source_id'] = intval($sourceId); + break; + case 1: //秒杀商品 + $result = app()->make(ProductRepository::class)->cartSeckillCheck($data,$this->request->userInfo()); + break; + case 2: //预售商品 + $result = app()->make(ProductPresellRepository::class)->cartCheck($data,$this->request->userInfo()); + $data['source'] = $data['product_type']; + $data['source_id'] = $data['product_id']; + $data['product_id'] = $result['product']['product_id']; + break; + case 3: //助力商品 + $result = app()->make(ProductAssistSetRepository::class)->cartCheck($data,$this->request->userInfo()); + $data['source'] = $data['product_type']; + $data['source_id'] = $data['product_id']; + $data['product_id'] = $result['product']['product_id']; + break; + case 4: //拼团商品 + $result = app()->make(ProductGroupRepository::class)->cartCheck($data,$this->request->userInfo()); + $data['source'] = $data['product_type']; + $data['source_id'] = $data['group_buying_id']; + $data['product_id'] = $result['product']['product_id']; + break; + } + + unset($data['group_buying_id']); + + if ($cart = $result['cart']) { + //更新购物车 + $cart_id = $cart['cart_id']; + $cart_num = ['cart_num' => ($cart['cart_num'] + $data['cart_num'])]; + $storeCart = $this->repository->update($cart_id,$cart_num); + } else { + //添加购物车 + $data['uid'] = $this->request->uid(); + $data['mer_id'] = $result['product']['mer_id']; + $cart = $storeCart = $this->repository->create($data); + } + event('user.cart', compact('user','storeCart')); + return app('json')->success(['cart_id' => $cart['cart_id']]); + } + + + /** + * @param $id + * @return mixed + * @throws \think\db\exception\DbException + * @author Qinii + */ + public function change($id) + { + $where = $this->request->params(['cart_num']); + $product_attr_unique = $this->request->param('product_attr_unique'); + if (intval($where['cart_num']) < 0) + return app('json')->fail('数量必须大于0'); + if (!$cart = $this->repository->getOne($id, $this->request->uid())) + return app('json')->fail('购物车信息不存在'); + if ($cart->product->once_count) { + $cart_num = app()->make(ProductRepository::class)->productOnceCountCart($cart['product_id'], $this->request->uid()); + if (($cart_num - $cart['cart_num'] + $where['cart_num']) > $cart->product->once_count) + return app('json')->fail('单次购买限制 ' . $cart->product->once_count . ' 件'); + } + if (!$res = app()->make(ProductAttrValueRepository::class)->getOptionByUnique($product_attr_unique ?? $cart['product_attr_unique'])) + return app('json')->fail('SKU不存在'); + if ($res['stock'] < $where['cart_num']) + return app('json')->fail('库存不足'); + if($product_attr_unique){ + $where['product_attr_unique'] = $product_attr_unique; + } + $this->repository->update($id, $where); + return app('json')->success('修改成功'); + } + + /** + * @return mixed + * @author Qinii + */ + public function batchDelete() + { + $ids = $this->request->param('cart_id'); + if(!count($ids))return app('json')->fail('参数错误'); + $this->repository->batchDelete($ids,$this->request->uid()); + return app('json')->success('删除成功'); + } + + + /** + * @return mixed + * @author Qinii + */ + public function cartCount() + { + return app('json')->success($this->repository->getCartCount($this->request->uid())); + } + + /** + * @param $data + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function check($data) + { + $product = app()->make(ProductRepository::class)->get($data['product_id']); + if(!$product) + throw new ValidateException('商品不存在'); + if( $data['cart_num'] < 0 ) + throw new ValidateException('数量必须大于0'); + if(!$res= app()->make(ProductAttrValueRepository::class)->getOptionByUnique($data['product_attr_unique'])) + throw new ValidateException('SKU不存在'); + if($res['product_id'] != $data['product_id']) + throw new ValidateException('数据不一致'); + if($res['stock'] < $data['cart_num']) + throw new ValidateException('库存不足'); + $data['is_new'] = 1; + $data['uid'] = $this->request->uid(); + $data['mer_id'] = $product['mer_id']; + return $data; + } + + + /** + * @param validate $validate + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function again(validate $validate) + { + $param = $this->request->param('data',[]); + foreach ($param as $data){ + $validate->check($data); + $item[] = $this->check($data); + } + + foreach ($item as $it){ + $it__id = $this->repository->create($it); + $ids[] = $it__id['cart_id']; + } + return app('json')->success(['cart_id' => $ids]); + } + + + /** + * @param validate $validate + * @return array + * @author Qinii + * @day 2020-06-11 + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['product_id','product_attr_unique','cart_num','is_new',['product_type',0],['group_buying_id',0],['spread_id',0]]); + $validate->check($data); + if ($data['spread_id']) { + if ($data['spread_id'] !== $this->request->userInfo()->uid){ + $user = app()->make(UserRepository::class)->get($data['spread_id']); + if (!$user) $data['spread_id'] = 0; + } else { + $data['spread_id'] = 0; + } + } + return $data; + } + + /** + * TODO 套餐购买 + * @return \think\response\Json + * @author Qinii + * @day 1/7/22 + */ + public function batchCreate() + { + $data = $this->request->params(['data','discount_id','is_new']); + $productRepostory = app()->make(ProductRepository::class); + if (!$data['discount_id']) + return app('json')->fail('优惠套餐ID不能为空'); + if (!$data['is_new']) + return app('json')->fail('套餐不能加入购物车'); + + $cartData = app()->make(StoreDiscountRepository::class)->check($data['discount_id'], $data['data'], $this->request->userInfo()); + $cart_id = []; + if ($cartData){ + foreach ($cartData as $datum) { + $cart = $this->repository->create($datum); + $cart_id[] = $cart['cart_id']; + } + } + return app('json')->success(compact('cart_id')); + } +} diff --git a/app/controller/api/store/order/StoreMicropayOrder.php b/app/controller/api/store/order/StoreMicropayOrder.php new file mode 100644 index 00000000..5521995f --- /dev/null +++ b/app/controller/api/store/order/StoreMicropayOrder.php @@ -0,0 +1,179 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\order; + + +use app\common\repositories\store\order\PresellOrderRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderCreateRepository; +use app\common\repositories\store\product\ProductRepository; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\services\LockService; +use crmeb\services\PayService; +use crmeb\services\WechatService; +use think\facade\Db; +use app\common\repositories\store\order\StoreCartRepository; +use think\App; + +/** + * Class StoreOrder + * @package app\controller\api\store\order + * @author xaboy + * @day 2020/6/10 + */ +class StoreMicropayOrder extends BaseController +{ + /** + * @var StoreCartRepository + */ + private $StoreCartRepository; + + public function __construct(App $app, StoreCartRepository $StoreCartRepository) + { + parent::__construct($app); + $this->StoreCartRepository = $StoreCartRepository; + } + public function addCart(){ + $bar_code = $this->request->param('bar_code', 0); +// $mer_id = $this->request->param('mer_id', 0); + $user = $this->request->userInfo(); + $mer_id =Db::name('store_service')->where('uid',$user['uid'])->where('status',1)->value('mer_id'); + + if ($mer_id==0) return app('json')->fail('商户id不能为空'); + if (strlen($bar_code)==1) return app('json')->fail('条形码不能为空'); + $find=Db::name('store_product_attr_value')->where('mer_id',$mer_id)->where('bar_code', $bar_code)->find(); + if (!$find) return app('json')->fail('商品不存在,您没有将该商品添加到店铺中'); + $data = [ + 'product_type'=>0, + 'cart_num'=>1, + 'is_new'=>0, + 'product_attr_unique'=>$find['unique'], + 'product_id'=>$find['product_id'], + 'spread_id'=>'', + ]; + event('user.cart.before',compact('user','data')); + switch ($data['product_type']) + { + case 0: + $result = app()->make(ProductRepository::class)->cartCheck($data,$this->request->userInfo()); + [$source, $sourceId, $pid] = explode(':', $this->request->param('source', '0'), 3) + ['', '', '']; + $data['source'] = (in_array($source, [0, 1]) && $pid == $data['product_id']) ? $source : 0; + if ($data['source'] > 0) $data['source_id'] = intval($sourceId); + break; + } + $data['product_type'] =100; + unset($data['group_buying_id']); + if ($cart = $result['cart']) { + //更新购物车 + $cart_id = $cart['cart_id']; + $cart_num = ['cart_num' => ($cart['cart_num'] + $data['cart_num'])]; + $storeCart = $this->StoreCartRepository->update($cart_id,$cart_num); + } else { + //添加购物车 + $data['uid'] = $this->request->uid(); + $data['mer_id'] = $result['product']['mer_id']; + $cart = $storeCart = $this->StoreCartRepository->create($data); + } + $product=Db::name('store_product')->where('product_id',$find['product_id'])->find(); + event('user.cart', compact('user','storeCart')); + return app('json')->success(['product'=>$product,'attrValue' => $cart]); + } + + public function v2CreateOrder(StoreCartRepository $cartRepository, StoreOrderCreateRepository $orderCreateRepository) + { + $cartId = (array)$this->request->param('cart_id', []); +// $mer_id = $this->request->param('mer_id', 0); + $post=[]; + $couponIds=[]; + $takes=[]; + $useIntegral = false; + $receipt_data = []; + $extend = []; + $mark = []; + $payType = 'routine'; + $source = 2; // 默认来源为2 普通商品订单 + $product_type = 100;// + $uid = $this->request->uid(); + $mer_id =Db::name('store_service')->where('uid',$uid)->where('status',1)->value('mer_id'); + if (!$mer_id&&$mer_id!=0){ + return app('json')->fail('商户id不能为空'); + } + $addressId=Db::name('user_address')->where('uid',$uid)->find(); + $merchant=Db::name('merchant')->where('mer_id',$mer_id)->find(); + if (!$addressId){ + $merchant_address=Db::name('merchant_address')->where('mer_id',$mer_id)->find(); + if (!$merchant_address){ + return app('json')->fail('商户地址不存在'); + } + if ($merchant_address['area_id']==0||$merchant_address['street_id']==0||$merchant_address['village_id']==0){ + return app('json')->fail('商户地址不完整'); + } + $area_name=Db::name('geo_area')->where('area_code',$merchant_address['area_id'])->value('area_name'); + $street_name=Db::name('geo_street')->where('street_code',$merchant_address['street_id'])->value('street_name'); + $district_id=Db::name('city_area')->where('name',$area_name)->value('id'); + $street_id=Db::name('city_area')->where('name',$street_name)->value('id'); + $data=[ + 'province'=>'四川', + 'province_id'=>22, + 'city'=>'泸州市', + 'city_id'=>1954, + 'district'=>$area_name, + 'district_id'=>$district_id, + 'street'=>$street_name, + 'street_id'=>$street_id, + 'uid'=>$uid, + 'real_name'=>$merchant['mer_name'], + 'phone'=>$merchant['mer_phone'], + 'detail'=>'付款码订单默认地址', + 'create_time'=>date('Y-m-d H:i:s'), + ]; + $addressId=Db::name('user_address')->insertGetId($data); + }else{ + $addressId=$addressId['address_id']; + $post=[ + 'phone'=>$merchant['mer_phone'], + 'real_name'=>$merchant['mer_name'], + ]; + } + if (!in_array($payType, StoreOrderRepository::PAY_TYPE, true)) + return app('json')->fail('请选择正确的支付方式'); + if (!($count = count($cartId)) || $count != count($cartRepository->validIntersection($cartId, $uid))) + return app('json')->fail('数据无效'); + + $groupOrder = app()->make(LockService::class)->exec('order.create', function () use ($orderCreateRepository, $receipt_data, $mark, $extend, $cartId, $payType, $takes, $couponIds, $useIntegral, $addressId, $post,$source,$product_type) { + return $orderCreateRepository->v2CreateOrder(array_search($payType, StoreOrderRepository::PAY_TYPE), $this->request->userInfo(), $cartId, $extend, $mark, $receipt_data, $takes, $couponIds, $useIntegral, $addressId, $post,$source,$product_type); + }); + try { + $param['order_sn']=$groupOrder['group_order_sn']; + $param['pay_price']=$groupOrder['pay_price']; + $param['attach']='micro_pay'; + $param['body']='店内支付'; + $service = new PayService('weixinQr',$param); + $code = $service->pay(null); + + $endtime = time() + 1800 ; + $result = [ + 'config' => $code['config'], + 'endtime'=> date('Y-m-d H:i:s',$endtime), + 'price' => $param['pay_price'] + ]; + return app('json')->success($result); +// return WechatService::create()->paymentPrepare('',$groupOrder['group_order_sn'],$groupOrder['pay_price'],['type'=>1],'店内支付','','NATIVE'); +// return WechatService::create()->paymentMicropay($groupOrder['group_order_sn'],$groupOrder['pay_price'],'付款码支付','商户号'.$mer_id,md5(time()),$auth_code); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $groupOrder->group_order_id]); + } + } +} \ No newline at end of file diff --git a/app/controller/api/store/order/StoreOrder.php b/app/controller/api/store/order/StoreOrder.php new file mode 100644 index 00000000..52d8377b --- /dev/null +++ b/app/controller/api/store/order/StoreOrder.php @@ -0,0 +1,299 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\order; + + +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\store\order\StoreOrderCreateRepository; +use app\common\repositories\store\order\StoreOrderReceiptRepository; +use app\validate\api\UserReceiptValidate; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\services\ExpressService; +use crmeb\services\LockService; +use think\App; +use think\exception\ValidateException; +use think\facade\Log; + +/** + * Class StoreOrder + * @package app\controller\api\store\order + * @author xaboy + * @day 2020/6/10 + */ +class StoreOrder extends BaseController +{ + /** + * @var StoreOrderRepository + */ + protected $repository; + + /** + * StoreOrder constructor. + * @param App $app + * @param StoreOrderRepository $repository + */ + public function __construct(App $app, StoreOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function v2CheckOrder(StoreCartRepository $cartRepository, StoreOrderCreateRepository $orderCreateRepository) + { + $cartId = (array)$this->request->param('cart_id', []); + $addressId = (int)$this->request->param('address_id'); + $couponIds = (array)$this->request->param('use_coupon', []); + $takes = (array)$this->request->param('takes', []); + $useIntegral = (bool)$this->request->param('use_integral', false); + $user = $this->request->userInfo(); + $uid = $user->uid; + if (!($count = count($cartId)) || $count != count($cartRepository->validIntersection($cartId, $uid))) + return app('json')->fail('数据无效'); + $orderInfo = $orderCreateRepository->v2CartIdByOrderInfo($user, $cartId, $takes, $couponIds, $useIntegral, $addressId); + + return app('json')->success($orderInfo); + } + + public function v2CreateOrder(StoreCartRepository $cartRepository, StoreOrderCreateRepository $orderCreateRepository) + { + $cartId = (array)$this->request->param('cart_id', []); + $addressId = (int)$this->request->param('address_id'); + $couponIds = (array)$this->request->param('use_coupon', []); + $takes = (array)$this->request->param('takes', []); + $useIntegral = (bool)$this->request->param('use_integral', false); + $receipt_data = (array)$this->request->param('receipt_data', []); + $extend = (array)$this->request->param('extend', []); + $mark = (array)$this->request->param('mark', []); + $payType = $this->request->param('pay_type'); + $post = (array)$this->request->param('post'); + + $isPc = $payType === 'pc'; + if ($isPc) { + $payType = 'balance'; + } + + if (!in_array($payType, StoreOrderRepository::PAY_TYPE, true)) + return app('json')->fail('请选择正确的支付方式'); + + $validate = app()->make(UserReceiptValidate::class); + foreach ($receipt_data as $receipt) { + if (!is_array($receipt)) throw new ValidateException('发票信息有误'); + $validate->check($receipt); + } + + $uid = $this->request->uid(); + if (!($count = count($cartId)) || $count != count($cartRepository->validIntersection($cartId, $uid))) + return app('json')->fail('数据无效'); +// if (!$addressId) +// return app('json')->fail('请选择地址'); + + $groupOrder = app()->make(LockService::class)->exec('order.create', function () use ($orderCreateRepository, $receipt_data, $mark, $extend, $cartId, $payType, $takes, $couponIds, $useIntegral, $addressId, $post) { + return $orderCreateRepository->v2CreateOrder(array_search($payType, StoreOrderRepository::PAY_TYPE), $this->request->userInfo(), $cartId, $extend, $mark, $receipt_data, $takes, $couponIds, $useIntegral, $addressId, $post); + }); + + if ($groupOrder['pay_price'] == 0) { + $this->repository->paySuccess($groupOrder); + return app('json')->status('success', '支付成功', ['order_id' => $groupOrder['group_order_id']]); + } + if ($isPc) { + return app('json')->success(['order_id' => $groupOrder->group_order_id]); + } + try { + return $this->repository->pay($payType, $this->request->userInfo(), $groupOrder, $this->request->param('return_url'), $this->request->isApp()); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $groupOrder->group_order_id]); + } + } + + /** + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where['status'] = $this->request->param('status'); + $where['product_type'] = $this->request->param('product_type',0); + $where['search'] = $this->request->param('store_name'); + $where['uid'] = $this->request->uid(); + $where['paid'] = 1; + $where['is_user'] = 1; + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function detail($id) + { + $order = $this->repository->getDetail((int)$id, $this->request->uid()); + if (!$order) + return app('json')->fail('订单不存在'); + if ($order->order_type == 1) { + $order->append(['take', 'refund_status']); + } + return app('json')->success($order->toArray()); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function number() + { + return app('json')->success(['orderPrice' => $this->request->userInfo()->pay_price] + $this->repository->userOrderNumber($this->request->uid())); + } + + /** + * @param StoreGroupOrderRepository $groupOrderRepository + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function groupOrderList(StoreGroupOrderRepository $groupOrderRepository) + { + [$page, $limit] = $this->getPage(); + $list = $groupOrderRepository->getList(['uid' => $this->request->uid(), 'paid' => 0], $page, $limit); + return app('json')->success($list); + } + + /** + * @param $id + * @param StoreGroupOrderRepository $groupOrderRepository + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function groupOrderDetail($id, StoreGroupOrderRepository $groupOrderRepository) + { + $groupOrder = $groupOrderRepository->detail($this->request->uid(), (int)$id); + if (!$groupOrder) + return app('json')->fail('订单不存在'); + else + return app('json')->success($groupOrder->append(['cancel_time', 'cancel_unix'])->toArray()); + } + + public function groupOrderStatus($id, StoreGroupOrderRepository $groupOrderRepository) + { + $groupOrder = $groupOrderRepository->status($this->request->uid(), intval($id)); + if (!$groupOrder) + return app('json')->fail('订单不存在'); + if ($groupOrder->paid) $groupOrder->append(['give_coupon']); + $activity_type = 0; + $activity_id = 0; + foreach ($groupOrder->orderList as $order) { + $activity_type = max($order->activity_type, $activity_type); + if ($order->activity_type == 4 && $groupOrder->paid) { + $order->append(['orderProduct']); + $activity_id = $order->orderProduct[0]['activity_id']; + } + } + $groupOrder->activity_type = $activity_type; + $groupOrder->activity_id = $activity_id; + return app('json')->success($groupOrder->toArray()); + } + + /** + * @param $id + * @param StoreGroupOrderRepository $groupOrderRepository + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function cancelGroupOrder($id, StoreGroupOrderRepository $groupOrderRepository) + { + $groupOrderRepository->cancel((int)$id, $this->request->uid()); + return app('json')->success('取消成功'); + } + + public function groupOrderPay($id, StoreGroupOrderRepository $groupOrderRepository) + { + //TODO 佣金结算,佣金退回,物流查询 + $type = $this->request->param('type'); + if (!in_array($type, StoreOrderRepository::PAY_TYPE)) + return app('json')->fail('请选择正确的支付方式'); + $groupOrder = $groupOrderRepository->detail($this->request->uid(), (int)$id, false); + if (!$groupOrder) + return app('json')->fail('订单不存在或已支付'); + $this->repository->changePayType($groupOrder, array_search($type, StoreOrderRepository::PAY_TYPE)); + if ($groupOrder['pay_price'] == 0) { + $this->repository->paySuccess($groupOrder); + return app('json')->status('success', '支付成功', ['order_id' => $groupOrder['group_order_id']]); + } + + try { + return $this->repository->pay($type, $this->request->userInfo(), $groupOrder, $this->request->param('return_url'), $this->request->isApp()); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $groupOrder->group_order_id]); + } + } + + public function take($id) + { + $this->repository->takeOrder($id, $this->request->userInfo()); + return app('json')->success('确认收货成功'); + } + + public function express($id) + { + $order = $this->repository->getWhere(['order_id' => $id, 'is_del' => 0]); + if (!$order) + return app('json')->fail('订单不存在'); + if (!$order->delivery_type || !$order->delivery_id) + return app('json')->fail('订单未发货'); + $express = $this->repository->express($id,null); + $order->append(['orderProduct']); + return app('json')->success(compact('express', 'order')); + } + + public function verifyCode($id) + { + $order = $this->repository->getWhere(['order_id' => $id, 'uid' => $this->request->uid(), 'is_del' => 0, 'order_type' => 1]); + if (!$order) + return app('json')->fail('订单状态有误'); + return app('json')->success(['qrcode' => $this->repository->wxQrcode($id, $order->verify_code)]); + } + + public function del($id) + { + $this->repository->userDel($id, $this->request->uid()); + return app('json')->success('删除成功'); + } + + public function createReceipt($id) + { + $data = $this->request->params(['receipt_type' , 'receipt_title' , 'duty_paragraph', 'receipt_title_type', 'bank_name', 'bank_code', 'address','tel', 'email']); + $order = $this->repository->getWhere(['order_id' => $id, 'uid' => $this->request->uid(), 'is_del' => 0]); + if (!$order) return app('json')->fail('订单不属于您或不存在'); + app()->make(StoreOrderReceiptRepository::class)->add($data, $order); + return app('json')->success('操作成功'); + } + + public function getOrderDelivery($id, DeliveryOrderRepository $orderRepository) + { + $res = $orderRepository->show($id, $this->request->uid()); + return app('json')->success($res); + } +} diff --git a/app/controller/api/store/order/StoreOrder.php.bak b/app/controller/api/store/order/StoreOrder.php.bak new file mode 100644 index 00000000..daa788e1 --- /dev/null +++ b/app/controller/api/store/order/StoreOrder.php.bak @@ -0,0 +1,298 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\order; + + +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\store\order\StoreOrderCreateRepository; +use app\common\repositories\store\order\StoreOrderReceiptRepository; +use app\validate\api\UserReceiptValidate; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\services\ExpressService; +use crmeb\services\LockService; +use think\App; +use think\exception\ValidateException; +use think\facade\Log; + +/** + * Class StoreOrder + * @package app\controller\api\store\order + * @author xaboy + * @day 2020/6/10 + */ +class StoreOrder extends BaseController +{ + /** + * @var StoreOrderRepository + */ + protected $repository; + + /** + * StoreOrder constructor. + * @param App $app + * @param StoreOrderRepository $repository + */ + public function __construct(App $app, StoreOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function v2CheckOrder(StoreCartRepository $cartRepository, StoreOrderCreateRepository $orderCreateRepository) + { + $cartId = (array)$this->request->param('cart_id', []); + $addressId = (int)$this->request->param('address_id'); + $couponIds = (array)$this->request->param('use_coupon', []); + $takes = (array)$this->request->param('takes', []); + $useIntegral = (bool)$this->request->param('use_integral', false); + $user = $this->request->userInfo(); + $uid = $user->uid; + if (!($count = count($cartId)) || $count != count($cartRepository->validIntersection($cartId, $uid))) + return app('json')->fail('数据无效'); + $orderInfo = $orderCreateRepository->v2CartIdByOrderInfo($user, $cartId, $takes, $couponIds, $useIntegral, $addressId); + + return app('json')->success($orderInfo); + } + + public function v2CreateOrder(StoreCartRepository $cartRepository, StoreOrderCreateRepository $orderCreateRepository) + { + $cartId = (array)$this->request->param('cart_id', []); + $addressId = (int)$this->request->param('address_id'); + $couponIds = (array)$this->request->param('use_coupon', []); + $takes = (array)$this->request->param('takes', []); + $useIntegral = (bool)$this->request->param('use_integral', false); + $receipt_data = (array)$this->request->param('receipt_data', []); + $extend = (array)$this->request->param('extend', []); + $mark = (array)$this->request->param('mark', []); + $payType = $this->request->param('pay_type'); + $post = (array)$this->request->param('post'); + + $isPc = $payType === 'pc'; + if ($isPc) { + $payType = 'balance'; + } + + if (!in_array($payType, StoreOrderRepository::PAY_TYPE, true)) + return app('json')->fail('请选择正确的支付方式'); + + $validate = app()->make(UserReceiptValidate::class); + foreach ($receipt_data as $receipt) { + if (!is_array($receipt)) throw new ValidateException('发票信息有误'); + $validate->check($receipt); + } + + $uid = $this->request->uid(); + if (!($count = count($cartId)) || $count != count($cartRepository->validIntersection($cartId, $uid))) + return app('json')->fail('数据无效'); +// if (!$addressId) +// return app('json')->fail('请选择地址'); + + $groupOrder = app()->make(LockService::class)->exec('order.create', function () use ($orderCreateRepository, $receipt_data, $mark, $extend, $cartId, $payType, $takes, $couponIds, $useIntegral, $addressId, $post) { + return $orderCreateRepository->v2CreateOrder(array_search($payType, StoreOrderRepository::PAY_TYPE), $this->request->userInfo(), $cartId, $extend, $mark, $receipt_data, $takes, $couponIds, $useIntegral, $addressId, $post); + }); + + if ($groupOrder['pay_price'] == 0) { + $this->repository->paySuccess($groupOrder); + return app('json')->status('success', '支付成功', ['order_id' => $groupOrder['group_order_id']]); + } + if ($isPc) { + return app('json')->success(['order_id' => $groupOrder->group_order_id]); + } + try { + return $this->repository->pay($payType, $this->request->userInfo(), $groupOrder, $this->request->param('return_url'), $this->request->isApp()); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $groupOrder->group_order_id]); + } + } + + /** + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/10 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where['status'] = $this->request->param('status'); + $where['search'] = $this->request->param('store_name'); + $where['uid'] = $this->request->uid(); + $where['paid'] = 1; + $where['is_user'] = 1; + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param $id + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function detail($id) + { + $order = $this->repository->getDetail((int)$id, $this->request->uid()); + if (!$order) + return app('json')->fail('订单不存在'); + if ($order->order_type == 1) { + $order->append(['take', 'refund_status']); + } + return app('json')->success($order->toArray()); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function number() + { + return app('json')->success(['orderPrice' => $this->request->userInfo()->pay_price] + $this->repository->userOrderNumber($this->request->uid())); + } + + /** + * @param StoreGroupOrderRepository $groupOrderRepository + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function groupOrderList(StoreGroupOrderRepository $groupOrderRepository) + { + [$page, $limit] = $this->getPage(); + $list = $groupOrderRepository->getList(['uid' => $this->request->uid(), 'paid' => 0], $page, $limit); + return app('json')->success($list); + } + + /** + * @param $id + * @param StoreGroupOrderRepository $groupOrderRepository + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function groupOrderDetail($id, StoreGroupOrderRepository $groupOrderRepository) + { + $groupOrder = $groupOrderRepository->detail($this->request->uid(), (int)$id); + if (!$groupOrder) + return app('json')->fail('订单不存在'); + else + return app('json')->success($groupOrder->append(['cancel_time', 'cancel_unix'])->toArray()); + } + + public function groupOrderStatus($id, StoreGroupOrderRepository $groupOrderRepository) + { + $groupOrder = $groupOrderRepository->status($this->request->uid(), intval($id)); + if (!$groupOrder) + return app('json')->fail('订单不存在'); + if ($groupOrder->paid) $groupOrder->append(['give_coupon']); + $activity_type = 0; + $activity_id = 0; + foreach ($groupOrder->orderList as $order) { + $activity_type = max($order->activity_type, $activity_type); + if ($order->activity_type == 4 && $groupOrder->paid) { + $order->append(['orderProduct']); + $activity_id = $order->orderProduct[0]['activity_id']; + } + } + $groupOrder->activity_type = $activity_type; + $groupOrder->activity_id = $activity_id; + return app('json')->success($groupOrder->toArray()); + } + + /** + * @param $id + * @param StoreGroupOrderRepository $groupOrderRepository + * @return mixed + * @author xaboy + * @day 2020/6/10 + */ + public function cancelGroupOrder($id, StoreGroupOrderRepository $groupOrderRepository) + { + $groupOrderRepository->cancel((int)$id, $this->request->uid()); + return app('json')->success('取消成功'); + } + + public function groupOrderPay($id, StoreGroupOrderRepository $groupOrderRepository) + { + //TODO 佣金结算,佣金退回,物流查询 + $type = $this->request->param('type'); + if (!in_array($type, StoreOrderRepository::PAY_TYPE)) + return app('json')->fail('请选择正确的支付方式'); + $groupOrder = $groupOrderRepository->detail($this->request->uid(), (int)$id, false); + if (!$groupOrder) + return app('json')->fail('订单不存在或已支付'); + $this->repository->changePayType($groupOrder, array_search($type, StoreOrderRepository::PAY_TYPE)); + if ($groupOrder['pay_price'] == 0) { + $this->repository->paySuccess($groupOrder); + return app('json')->status('success', '支付成功', ['order_id' => $groupOrder['group_order_id']]); + } + + try { + return $this->repository->pay($type, $this->request->userInfo(), $groupOrder, $this->request->param('return_url'), $this->request->isApp()); + } catch (\Exception $e) { + return app('json')->status('error', $e->getMessage(), ['order_id' => $groupOrder->group_order_id]); + } + } + + public function take($id) + { + $this->repository->takeOrder($id, $this->request->userInfo()); + return app('json')->success('确认收货成功'); + } + + public function express($id) + { + $order = $this->repository->getWhere(['order_id' => $id, 'is_del' => 0]); + if (!$order) + return app('json')->fail('订单不存在'); + if (!$order->delivery_type || !$order->delivery_id) + return app('json')->fail('订单未发货'); + $express = $this->repository->express($id,null); + $order->append(['orderProduct']); + return app('json')->success(compact('express', 'order')); + } + + public function verifyCode($id) + { + $order = $this->repository->getWhere(['order_id' => $id, 'uid' => $this->request->uid(), 'is_del' => 0, 'order_type' => 1]); + if (!$order) + return app('json')->fail('订单状态有误'); + return app('json')->success(['qrcode' => $this->repository->wxQrcode($id, $order->verify_code)]); + } + + public function del($id) + { + $this->repository->userDel($id, $this->request->uid()); + return app('json')->success('删除成功'); + } + + public function createReceipt($id) + { + $data = $this->request->params(['receipt_type' , 'receipt_title' , 'duty_paragraph', 'receipt_title_type', 'bank_name', 'bank_code', 'address','tel', 'email']); + $order = $this->repository->getWhere(['order_id' => $id, 'uid' => $this->request->uid(), 'is_del' => 0]); + if (!$order) return app('json')->fail('订单不属于您或不存在'); + app()->make(StoreOrderReceiptRepository::class)->add($data, $order); + return app('json')->success('操作成功'); + } + + public function getOrderDelivery($id, DeliveryOrderRepository $orderRepository) + { + $res = $orderRepository->show($id, $this->request->uid()); + return app('json')->success($res); + } +} diff --git a/app/controller/api/store/order/StoreOrderVerify.php b/app/controller/api/store/order/StoreOrderVerify.php new file mode 100644 index 00000000..4b573fcb --- /dev/null +++ b/app/controller/api/store/order/StoreOrderVerify.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\order; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use crmeb\basic\BaseController; +use think\App; +use think\exception\HttpResponseException; + +class StoreOrderVerify extends BaseController +{ + protected $user; + + protected $service; + + public function __construct(App $app) + { + parent::__construct($app); + } + + public function detail($merId, $id, StoreOrderRepository $repository) + { + $order = $repository->codeByDetail($id); + if (!$order) return app('json')->fail('订单不存在'); + if ($order->mer_id != $merId) + return app('json')->fail('没有权限查询该订单'); + return app('json')->success($order); + } + + public function verify($merId, $id, StoreOrderRepository $repository) + { + $data = $this->request->params(['data','verify_code']); + $repository->verifyOrder($id, $merId, $data,$this->request->serviceInfo()->service_id); + return app('json')->success('订单核销成功'); + } +} diff --git a/app/controller/api/store/order/StoreRefundOrder.php b/app/controller/api/store/order/StoreRefundOrder.php new file mode 100644 index 00000000..5b3d8e94 --- /dev/null +++ b/app/controller/api/store/order/StoreRefundOrder.php @@ -0,0 +1,216 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\order; + + +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\shipping\ExpressRepository; +use app\validate\api\BackGoodsValidate; +use app\validate\api\StoreRefundOrderValidate; +use crmeb\basic\BaseController; +use think\App; + +/** + * Class StoreRefundOrder + * @package app\controller\api\store\order + * @author xaboy + * @day 2020/6/12 + */ +class StoreRefundOrder extends BaseController +{ + /** + * @var StoreRefundOrderRepository + */ + protected $repository; + + /** + * StoreRefundOrder constructor. + * @param App $app + * @param StoreRefundOrderRepository $repository + */ + public function __construct(App $app, StoreRefundOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @param $id + * @param StoreOrderRepository $orderRepository + * @return mixed + * @author xaboy + * @day 2020/6/12 + */ + public function batchProduct($id, StoreOrderRepository $orderRepository) + { + return app('json')->success($orderRepository->refundProduct($id, $this->request->uid())); + } + + /** + * @param $id + * @param StoreOrderProductRepository $orderProductRepository + * @param StoreOrderRepository $storeOrderRepository + * @return \think\response\Json + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/9/2 + */ + public function product($id, StoreOrderProductRepository $orderProductRepository, StoreOrderRepository $storeOrderRepository) + { + $_id = (string)$this->request->param('ids', ''); + $type = (string)$this->request->param('type', ''); + $ids = explode(',', $_id); + if (!$_id || !count($ids)) + return app('json')->fail('请选择退款商品'); + $uid = $this->request->uid(); + $order = $storeOrderRepository->userOrder(intval($id), $uid); + if (!$order) + return app('json')->fail('订单状态有误'); + if (!$order->refund_status) + return app('json')->fail('订单已过退款/退货期限'); + if ($order->status < 0) return app('json')->fail('订单已退款'); + if ($order->status == 10) return app('json')->fail('订单不支持退款'); + $product = $orderProductRepository->userRefundProducts($ids, $uid, intval($id)); + if (!$product) + return app('json')->fail('商品不存在或已退款'); + if (count($product) != count($ids)) + return app('json')->fail('请选择正确的退款商品'); + if ($type == 2) { + $total_refund_price = $this->repository->getRefundsTotalPrice($order, $product); + $postage_price = 0; + } else { + $data = $this->repository->getRefundTotalPrice($order, $product); + $total_refund_price = (float)$data['total_refund_price']; + $postage_price = (float)$data['postage_price']; + } + $status = (!$order->status || $order->status == 9) ? 0 : $order->status; + $activity_type = $order->activity_type; + return app('json')->success(compact('activity_type', 'total_refund_price', 'product', 'postage_price', 'status')); + } + + /** + * @param $id + * @param StoreRefundOrderValidate $validate + * @param StoreOrderRepository $orderRepository + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function refund($id, StoreRefundOrderValidate $validate, StoreOrderRepository $orderRepository) + { + $data = $this->request->params(['type', 'refund_type','refund_price', 'num', 'ids', 'refund_message', 'mark', 'pics']); + $validate->check($data); + $ids = explode(',', $data['ids']); + $type = $data['type']; + $num = $data['num']; + unset($data['num'], $data['ids'], $data['type']); + if ($type == 1 && count($ids) > 1) + return app('json')->fail('请选择正确的退款商品'); + $uid = $this->request->uid(); + $order = $orderRepository->userOrder($id, $uid); + if (!$order) return app('json')->fail('订单状态错误'); + if (!$order->refund_status) + return app('json')->fail('订单已过退款/退货期限'); + if ($order->status < 0) return app('json')->fail('订单已退款'); + if ($order->status == 10) return app('json')->fail('订单不支持退款'); + if($order->is_virtual && $data['refund_type'] == 2) return app('json')->fail('订单不支持退款退货'); + if ($type == 1) { + $refund = $this->repository->refund($order, (int)$ids[0], $num, $uid, $data); + } else { + $refund = $this->repository->refunds($order, $ids, $uid, $data); + } + return app('json')->success('申请退款成功', ['refund_order_id' => $refund->refund_order_id]); + } + + /** + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function lst() + { + $type = $this->request->param('type'); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->userList([ + 'type' => $type, + 'uid' => $this->request->uid(), + 'is_del' => 0, + ], $page, $limit)); + } + + /** + * @param $id + * @return mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author xaboy + * @day 2020/6/12 + */ + public function detail($id) + { + $refund = $this->repository->userDetail(intval($id), $this->request->uid()); + if (!$refund) + return app('json')->fail('退款单不存在'); + return app('json')->success($refund->toArray()); + } + + /** + * @param $id + * @return mixed + * @throws \think\db\exception\DbException + * @author xaboy + * @day 2020/6/12 + */ + public function del($id) + { + $this->repository->userDel(intval($id), $this->request->uid()); + return app('json')->success('删除成功'); + } + + public function back_goods($id, BackGoodsValidate $validate, ExpressRepository $expressRepository) + { + $data = $this->request->params(['delivery_type', 'delivery_id', 'delivery_phone', 'delivery_mark', 'delivery_pics']); + $validate->check($data); + if (!$expressRepository->merFieldExists('name', $data['delivery_type'], null, null, true)) + return app('json')->fail('不支持该快递公司'); + $this->repository->backGoods($this->request->uid(), $id, $data); + return app('json')->success('提交成功'); + } + + public function express($id) + { + if (!$refund = $this->repository->getWhere(['status' => 2, 'refund_order_id' => $id])) + return app('json')->fail('退款单不存在'); + $express = $this->repository->express($id); + return app('json')->success(compact('refund', 'express')); + } + + public function cancel($id) + { + $this->repository->cancel($id, $this->request->userInfo()); + return app('json')->success('取消成功'); + } + +} diff --git a/app/controller/api/store/product/Discounts.php b/app/controller/api/store/product/Discounts.php new file mode 100644 index 00000000..6fdcd347 --- /dev/null +++ b/app/controller/api/store/product/Discounts.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\store\product; + +use app\common\repositories\store\product\StoreDiscountProductRepository; +use app\common\repositories\store\product\StoreDiscountRepository; +use crmeb\basic\BaseController; +use think\App; + +class Discounts extends BaseController +{ + + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param StoreDiscountRepository $repository + */ + public function __construct(App $app ,StoreDiscountRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + $id = $this->request->param('product_id',0); + $where = [ + 'status' => 1, + 'is_show'=> 1, + 'end_time' => 1, + 'is_del' => 0, + ]; + + if ($id){ + $discount_id = app()->make(StoreDiscountProductRepository::class) + ->getSearch(['product_id' => $id]) + ->column('discount_id'); + $where['discount_id'] = $discount_id; + } + $data = $this->repository->getApilist($where); + return app('json')->success($data); + } + + +} diff --git a/app/controller/api/store/product/StoreBrand.php b/app/controller/api/store/product/StoreBrand.php new file mode 100644 index 00000000..8a5aae7e --- /dev/null +++ b/app/controller/api/store/product/StoreBrand.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\product; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreBrandRepository as repository; + +class StoreBrand extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * StoreBrand constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @return mixed + */ + public function lst() + { + $where = $this->request->params(['keyword', 'cate_id','mer_id','mer_cate_id','pid']); + return app('json')->success($this->repository->getCategorySearch($where)); + } + +} diff --git a/app/controller/api/store/product/StoreCategory.php b/app/controller/api/store/product/StoreCategory.php new file mode 100644 index 00000000..ff461403 --- /dev/null +++ b/app/controller/api/store/product/StoreCategory.php @@ -0,0 +1,74 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\product; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreCategoryRepository as repository; + +class StoreCategory extends BaseController +{ + protected $repository; + + /** + * ProductCategory constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/27 + * @return mixed + */ + public function lst() + { + $data = $this->repository->getHot(0); + $list = $this->repository->getApiFormatList(0,1); + $ret =[]; + foreach ($list as $key => $value) { + if (isset($value['children'])) { + $level = []; + foreach ($value['children'] as $child) { + if (isset($child['children'])) { + $level[] = $child; + } + } + if (isset($level) && !empty($level)) { + $value['children'] = $level; + $ret[] = $value; + } + } + } + $data['list'] = $ret; + return app('json')->success($data); + } + + public function children() + { + $pid = (int)$this->request->param('pid'); + + return app('json')->success($this->repository->children($pid)); + } + + public function cateHotRanking() + { + $data = $this->repository->getSearch(['level' => systemConfig('hot_ranking_lv') ?:0, 'mer_id' => 0,'is_show' => 1])->order('sort DESC,create_time DESC')->select(); + return app('json')->success($data); + } +} diff --git a/app/controller/api/store/product/StoreCoupon.php b/app/controller/api/store/product/StoreCoupon.php new file mode 100644 index 00000000..94c1b612 --- /dev/null +++ b/app/controller/api/store/product/StoreCoupon.php @@ -0,0 +1,153 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\product; + + +use app\common\repositories\store\coupon\StoreCouponProductRepository; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use crmeb\basic\BaseController; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class StoreCoupon + * @package app\controller\api\store\product + * @author xaboy + * @day 2020/6/1 + */ +class StoreCoupon extends BaseController +{ + /** + * @var + */ + protected $uid; + + /** + * StoreCoupon constructor. + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + if ($this->request->isLogin()) $this->uid = $this->request->uid(); + } + + /** + * @param StoreCouponUserRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/3 + */ + public function lst(StoreCouponUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['statusTag']); + $where['uid'] = $this->uid; + return app('json')->success($repository->userList($where, $page, $limit)); + } + + /** + * @param StoreCouponRepository $repository + * @param StoreCouponProductRepository $couponProductRepository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function coupon(StoreCouponRepository $repository, StoreCouponProductRepository $couponProductRepository) + { + $ids = array_filter(explode(',', $this->request->param('ids'))); + if (!count($ids)) + return app('json')->success([]); + $productCouponIds = $couponProductRepository->productByCouponId($ids); + $productCoupon = count($productCouponIds) ? $repository->validProductCoupon($productCouponIds, $this->uid)->toArray() : []; + return app('json')->success($productCoupon); + } + + /** + * @param $id + * @param StoreCouponRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/1 + */ + public function merCoupon($id, StoreCouponRepository $repository) + { + $all = (int)$this->request->param('all'); + $coupon = $repository->validMerCoupon($id, $this->uid, $all === 1 ? null : 0)->toArray(); + return app('json')->success($coupon); + } + + /** + * @param $id + * @param StoreCouponRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/1 + */ + public function receiveCoupon($id, StoreCouponRepository $repository) + { + if (!$repository->exists($id)) + return app('json')->fail('优惠券不存在'); + $repository->receiveCoupon($id, $this->uid); + return app('json')->success('领取成功'); + } + + /** + * TODO 可领取的优惠券列表 + * @author Qinii + * @day 3/14/22 + */ + public function getList(StoreCouponRepository $couponRepository) + { + $where = $this->request->params(['type','mer_id', 'product','is_pc',['send_type',0]]); + [$page, $limit] = $this->getPage(); + $data = $couponRepository->apiList($where, $page, $limit, $this->uid); + return app('json')->success($data); + } + + public function newPeople(StoreCouponRepository $couponRepository) + { + $coupons = $couponRepository->newPeopleCoupon(); + + foreach ($coupons as $coupon){ + if($coupon['coupon_type']){ + $coupon['use_end_time'] = explode(' ', $coupon['use_end_time'])[0] ?? ''; + $coupon['use_start_time'] = explode(' ', $coupon['use_start_time'])[0] ?? ''; + }else{ + $coupon['use_start_time'] = date('Y-m-d'); + $coupon['use_end_time'] = date('Y-m-d', strtotime('+ ' . $coupon['coupon_time'] . ' day')); + } + if($coupon['use_end_time']){ + $coupon['use_end_time'] = date('Y.m.d',strtotime($coupon['use_end_time'])); + } + if($coupon['use_start_time']){ + $coupon['use_start_time'] = date('Y.m.d',strtotime($coupon['use_start_time'])); + } + } + return app('json')->success($coupons); + } + +} diff --git a/app/controller/api/store/product/StoreMicro.php b/app/controller/api/store/product/StoreMicro.php new file mode 100644 index 00000000..aa5e034d --- /dev/null +++ b/app/controller/api/store/product/StoreMicro.php @@ -0,0 +1,57 @@ +request->userInfo(); + $mer_id =Db::name('store_service')->where('uid',$user['uid'])->where('status',1)->value('mer_id'); + $find=Db::name('store_product_attr_value')->where('mer_id',$mer_id)->where('bar_code',$code)->find(); + if (!$find){ + $store_product=Db::name('store_product')->where('product_type',98)->where('bar_code',$code)->find(); + if (!$store_product){ + return app('json')->fail('平台没有该条形码,请自行录入'); + } + $store_product['attr_value']=Db::name('store_product_attr_value')->where('product_id',$store_product['product_id'])->find(); + $store_product['is_mer_show']=0; + return app('json')->success(['data'=>$store_product]); + + }; + $store_product=Db::name('store_product')->where('product_id',$find['product_id'])->find(); + $store_product['attr_value']=$find; + $store_product['is_mer_show']=1; + return app('json')->success(['data'=>$store_product]); + } + + public function eadtProduct(){ + $product_id = $this->request->param('id', 0); + if ($product_id==0) return app('json')->fail('商品id不能为空'); + $price = $this->request->param('price', 0); + if ($price==0) return app('json')->fail('价格不能为空'); + $stock = $this->request->param('stock', 0); + if ($stock==0) return app('json')->fail('库存不能为空'); + $user = $this->request->userInfo(); + $mer_id =Db::name('store_service')->where('uid',$user['uid'])->where('status',1)->value('mer_id'); + if ($mer_id==0) return app('json')->fail('商户id不能为空'); + $data = [ + 'price'=>$price, + 'stock'=>$stock, + ]; + Db::startTrans(); + try { + Db::name('store_product')->where('mer_id',$mer_id)->where('product_id',$product_id)->update($data); + Db::name('store_product_attr_value')->where('mer_id',$mer_id)->where('product_id',$product_id)->update($data); + // 提交事务 + Db::commit(); + return app('json')->success(['data'=>'','msg'=>'更新成功']); + + } catch (\Exception $e) { + // 回滚事务 + Db::rollback(); + return app('json')->fail($e->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/controller/api/store/product/StoreProduct.php b/app/controller/api/store/product/StoreProduct.php new file mode 100644 index 00000000..3db98c39 --- /dev/null +++ b/app/controller/api/store/product/StoreProduct.php @@ -0,0 +1,197 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\product; + +use app\common\repositories\store\PriceRuleRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\user\UserMerchantRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductRepository as repository; +use think\facade\Cache; + +class StoreProduct extends BaseController +{ + /** + * @var repository + */ + protected $repository; + protected $userInfo = null; + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @return mixede + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'cate_id', 'order', 'price_on', 'price_off', 'brand_id', 'pid','star']); + $data = $this->repository->getApiSearch(null, $where, $page, $limit, $this->userInfo); + return app('json')->success($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @return mixed + */ + public function detail($id) + { + $param = $this->request->params(['type', ['product_type', 0]]); + $data = $this->repository->detail($id, $this->userInfo,$param['product_type']); + if (!$data){ + app()->make(SpuRepository::class)->changeStatus($id,0); + return app('json')->fail('商品已下架'); + } + + if ($this->request->isLogin()) { + app()->make(UserMerchantRepository::class)->updateLastTime($this->request->uid(), $data->mer_id); + } + + return app('json')->success($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @return mixed + */ + public function recommendList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->recommend($this->userInfo, null, $page, $limit)); + } + + public function qrcode($id) + { + $id = (int)$id; + $param = $this->request->params(['type', ['product_type', 0]]); + $param['product_type'] = (int)$param['product_type']; + if (!$id || !$product = $this->repository->existsProduct($id, $param['product_type'])) + return app('json')->fail('商品不存在'); + + if ($param['type'] == 'routine') { + $url = $this->repository->routineQrCode($id, $param['product_type'], $this->request->userInfo()); + }else{ + $url = $this->repository->wxQrCode($id, $param['product_type'], $this->request->userInfo()); + } + + if (!$url) return app('json')->fail('二维码生成失败'); + return app('json')->success(compact('url')); + } + + public function getBagList() + { + if(!systemConfig('extension_status')) return app('json')->fail('活动未开启'); + [$page, $limit] = $this->getPage(); + $where = $this->repository->bagShow(); + return app('json')->success($this->repository->getBagList($where, $page, $limit)); + } + + public function getBagrecomm() + { + $where = $this->repository->bagShow(); + $where['is_best'] = 1; + return app('json')->success($this->repository->selectWhere($where)->append(['merchant'])); + } + + public function getBagExplain() + { + if(!systemConfig('extension_status')) return app('json')->fail('活动未开启'); + $data = [ + 'explain' => systemConfig('promoter_explain'), + 'data' => app()->make(GroupDataRepository::class)->groupData('promoter_config', 0), + ]; + return app('json')->success($data); + } + + public function hot($type) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getApiSearch(null, ['hot_type' => $type, 'is_gift_bag' => 0, 'is_used' => 1], $page, $limit, $this->userInfo)); + } + + public function guaranteeTemplate($id) + { + $where = [ + 'guarantee_template_id' => $id, + 'status' => 1, + ]; + $data = $this->repository->GuaranteeTemplate($where); + return app('json')->success($data); + } + + public function setIncreaseTake() + { + $product_id = $this->request->param('product_id'); + $unique = $this->request->param('unique'); + $type = $this->request->param('type'); + if($type == 1 && !$this->userInfo['phone']) return app('json')->fail('请先绑定手机号'); + $this->repository->increaseTake($this->request->uid(),$unique,$type,$product_id); + return app('json')->success('订阅成功'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 6/15/21 + */ + public function preview() + { + $param = $this->request->params(['key','id',['product_type',0]]); + $data = []; + if($param['key']){ + $data = Cache::get($param['key']); + Cache::delete($param['key']); + }elseif($param['id']){ + $data = $this->repository->getPreview($param); + } + if(!$data) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function priceRule($id) + { + $path = app()->make(StoreCategoryRepository::class)->query(['store_category_id' => $id, 'mer_id' => 0])->value('path'); + if ($path && $path !== '/') { + $ids = explode('/', trim($path, '/')); + $ids[] = $id; + } else { + $ids[] = $id; + } + $rule = app()->make(PriceRuleRepository::class)->search(['cate_id' => $ids, 'is_show' => 1]) + ->order('sort DESC,rule_id DESC')->find(); + if ($rule) { + return app('json')->success($rule->toArray()); + } + return app('json')->fail('规则不存在'); + } +} diff --git a/app/controller/api/store/product/StoreProduct.php.bak b/app/controller/api/store/product/StoreProduct.php.bak new file mode 100644 index 00000000..b63ecf94 --- /dev/null +++ b/app/controller/api/store/product/StoreProduct.php.bak @@ -0,0 +1,196 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\product; + +use app\common\repositories\store\PriceRuleRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\user\UserMerchantRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductRepository as repository; +use think\facade\Cache; + +class StoreProduct extends BaseController +{ + /** + * @var repository + */ + protected $repository; + protected $userInfo = null; + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @return mixede + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'cate_id', 'order', 'price_on', 'price_off', 'brand_id', 'pid','star']); + $data = $this->repository->getApiSearch(null, $where, $page, $limit, $this->userInfo); + return app('json')->success($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @param $id + * @return mixed + */ + public function detail($id) + { + $data = $this->repository->detail($id, $this->userInfo); + if (!$data){ + app()->make(SpuRepository::class)->changeStatus($id,0); + return app('json')->fail('商品已下架'); + } + + if ($this->request->isLogin()) { + app()->make(UserMerchantRepository::class)->updateLastTime($this->request->uid(), $data->mer_id); + } + + return app('json')->success($data); + } + + /** + * @Author:Qinii + * @Date: 2020/5/30 + * @return mixed + */ + public function recommendList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->recommend($this->userInfo, null, $page, $limit)); + } + + public function qrcode($id) + { + $id = (int)$id; + $param = $this->request->params(['type', ['product_type', 0]]); + $param['product_type'] = (int)$param['product_type']; + if (!$id || !$product = $this->repository->existsProduct($id, $param['product_type'])) + return app('json')->fail('商品不存在'); + + if ($param['type'] == 'routine') { + $url = $this->repository->routineQrCode($id, $param['product_type'], $this->request->userInfo()); + }else{ + $url = $this->repository->wxQrCode($id, $param['product_type'], $this->request->userInfo()); + } + + if (!$url) return app('json')->fail('二维码生成失败'); + return app('json')->success(compact('url')); + } + + public function getBagList() + { + if(!systemConfig('extension_status')) return app('json')->fail('活动未开启'); + [$page, $limit] = $this->getPage(); + $where = $this->repository->bagShow(); + return app('json')->success($this->repository->getBagList($where, $page, $limit)); + } + + public function getBagrecomm() + { + $where = $this->repository->bagShow(); + $where['is_best'] = 1; + return app('json')->success($this->repository->selectWhere($where)->append(['merchant'])); + } + + public function getBagExplain() + { + if(!systemConfig('extension_status')) return app('json')->fail('活动未开启'); + $data = [ + 'explain' => systemConfig('promoter_explain'), + 'data' => app()->make(GroupDataRepository::class)->groupData('promoter_config', 0), + ]; + return app('json')->success($data); + } + + public function hot($type) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getApiSearch(null, ['hot_type' => $type, 'is_gift_bag' => 0, 'is_used' => 1], $page, $limit, $this->userInfo)); + } + + public function guaranteeTemplate($id) + { + $where = [ + 'guarantee_template_id' => $id, + 'status' => 1, + ]; + $data = $this->repository->GuaranteeTemplate($where); + return app('json')->success($data); + } + + public function setIncreaseTake() + { + $product_id = $this->request->param('product_id'); + $unique = $this->request->param('unique'); + $type = $this->request->param('type'); + if($type == 1 && !$this->userInfo['phone']) return app('json')->fail('请先绑定手机号'); + $this->repository->increaseTake($this->request->uid(),$unique,$type,$product_id); + return app('json')->success('订阅成功'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 6/15/21 + */ + public function preview() + { + $param = $this->request->params(['key','id','product_type']); + $data = []; + if($param['key']){ + $data = Cache::get($param['key']); + Cache::delete($param['key']); + }elseif($param['id']){ + $data = $this->repository->getPreview($param); + } + if(!$data) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function priceRule($id) + { + $path = app()->make(StoreCategoryRepository::class)->query(['store_category_id' => $id, 'mer_id' => 0])->value('path'); + if ($path && $path !== '/') { + $ids = explode('/', trim($path, '/')); + $ids[] = $id; + } else { + $ids[] = $id; + } + $rule = app()->make(PriceRuleRepository::class)->search(['cate_id' => $ids, 'is_show' => 1]) + ->order('sort DESC,rule_id DESC')->find(); + if ($rule) { + return app('json')->success($rule->toArray()); + } + return app('json')->fail('规则不存在'); + } +} diff --git a/app/controller/api/store/product/StoreProductAssist.php b/app/controller/api/store/product/StoreProductAssist.php new file mode 100644 index 00000000..48b024fd --- /dev/null +++ b/app/controller/api/store/product/StoreProductAssist.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\product; + +use app\common\model\store\product\ProductAssistUser; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductAssistUserRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductAssistRepository; + +class StoreProductAssist extends BaseController +{ + protected $repository; + protected $userInfo; + + /** + * StoreProductPresell constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, ProductAssistRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type','star','mer_id']); + return app('json')->success($this->repository->getApiList($where,$page, $limit)); + } + + public function userCount() + { + return app('json')->success($this->repository->getUserCount()); + } +} diff --git a/app/controller/api/store/product/StoreProductAssistSet.php b/app/controller/api/store/product/StoreProductAssistSet.php new file mode 100644 index 00000000..d3a21481 --- /dev/null +++ b/app/controller/api/store/product/StoreProductAssistSet.php @@ -0,0 +1,116 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\product; + +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductAssistUserRepository; +use think\App; +use crmeb\basic\BaseController; + +class StoreProductAssistSet extends BaseController +{ + protected $repository; + protected $userInfo; + + /** + * StoreProductPresell constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, ProductAssistSetRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + + /** + * TODO 个人助力列表 + * @return mixed + * @author Qinii + * @day 2020-11-25 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where['uid'] = $this->request->uid(); + return app('json')->success($this->repository->getApiList($where,$page, $limit)); + } + + public function detail($id) + { + $data = $this->repository->detail($id,$this->userInfo); + return app('json')->success($data); + } + + /** + * TODO 发起助力 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-28 + */ + public function create($id) + { +// if($this->userInfo->user_type == 'wechat' && !$this->userInfo->subscribe){ +// return app('json')->fail('请先关注公众号'); +// } + $data = $this->repository->create($id,$this->request->uid()); + return app('json')->success($data); + } + + /** + * TODO 帮好友助力 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-28 + */ + public function set($id) + { + $this->repository->set($id,$this->userInfo); + return app('json')->success('助力成功'); + } + + public function delete($id) + { + $res = $this->repository->getWhere(['product_assist_set_id' => $id,'uid' => $this->request->uid()]); + + if(!$res)return app('json')->fail('信息错误'); + $this->repository->update($id,['status' => -1]); + return app('json')->success('取消成功'); + } + + /** + * TODO 助力列表 + * @param $id + * @param ProductAssistUserRepository $repository + * @return mixed + * @author Qinii + * @day 2020-10-28 + */ + public function userList($id,ProductAssistUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where['product_assist_set_id'] = $id; + if(!$this->repository->get($id)) return app('json')->fail('数据丢失'); + return app('json')->success($repository->userList($where,$page, $limit)); + } + + public function shareNum($id) + { + $this->repository->incNum(1,$id); + return app('json')->success('oks'); + } +} diff --git a/app/controller/api/store/product/StoreProductGroup.php b/app/controller/api/store/product/StoreProductGroup.php new file mode 100644 index 00000000..72efc66a --- /dev/null +++ b/app/controller/api/store/product/StoreProductGroup.php @@ -0,0 +1,87 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\product; + +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupUserRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductGroupRepository; + +class StoreProductGroup extends BaseController +{ + protected $repository; + protected $userInfo; + + /** + * StoreProductPresell constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, ProductGroupRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([['active_type',1],'store_category_id','star','mer_id']); + return app('json')->success($this->repository->getApiList($where,$page, $limit)); + } + + public function detail($id) + { + $data = $this->repository->apiDetail($id, $this->userInfo); + return app('json')->success($data); + } + + public function groupBuying($id) + { + $make = app()->make(ProductGroupBuyingRepository::class); + $data = $make->detail($id,$this->userInfo); + if(!$data) return app('json')->fail('数据丢失'); + return app('json')->success($data); + } + + public function userCount() + { + [$page, $limit] = $this->getPage(); + $data = app()->make(ProductGroupUserRepository::class)->getApiList([],$page,$limit); + return app('json')->success($data); + } + + public function category() + { + return app('json')->success($this->repository->getCategory()); + } + + /** + * TODO 取消参团 + * @author Qinii + * @day 1/13/21 + */ + public function cancel() + { + $data = (int)$this->request->param('group_buying_id'); + + $make = app()->make(ProductGroupBuyingRepository::class); + + $make->cancelGroup($data,$this->userInfo); + + return app('json')->success('取消成功,订单金额将会原路退回'); + + } +} diff --git a/app/controller/api/store/product/StoreProductPresell.php b/app/controller/api/store/product/StoreProductPresell.php new file mode 100644 index 00000000..291cdc18 --- /dev/null +++ b/app/controller/api/store/product/StoreProductPresell.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\store\product; + +use app\common\repositories\system\CacheRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductPresellRepository; + +class StoreProductPresell extends BaseController +{ + protected $repository; + protected $userInfo; + + /** + * StoreProductPresell constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, ProductPresellRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([['type',4],'star','mer_id']); + return app('json')->success($this->repository->getApiList($where,$page, $limit)); + } + + + public function detail($id) + { + $data = $this->repository->apiDetail((int)$id,$this->userInfo); + return app('json')->success($data); + } + + public function getAgree() + { + $make = app()->make(CacheRepository::class); + return app('json')->success($make->getResult('sys_product_presell_agree')); + } + +} diff --git a/app/controller/api/store/product/StoreProductSeckill.php b/app/controller/api/store/product/StoreProductSeckill.php new file mode 100644 index 00000000..db4d931b --- /dev/null +++ b/app/controller/api/store/product/StoreProductSeckill.php @@ -0,0 +1,86 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\product; + +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\StoreSeckillTimeRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductRepository as repository; + +class StoreProductSeckill extends BaseController +{ + /** + * @var repository + */ + protected $repository; + protected $userInfo; + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + /** + * TODO 秒杀列表 + * @return mixed + * @author Qinii + * @day 2020-08-04 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where['mer_id'] = $this->request->param('mer_id',''); + $where['start_time'] = $this->request->param('start_time',''); + $where['end_time'] = $this->request->param('end_time',''); + return app('json')->success($this->repository->getApiSeckill($where,$page, $limit)); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-08-04 + */ + public function detail($id) + { + $data = $this->repository->seckillDetail($id,$this->userInfo); + if (!$data) { + app()->make(SpuRepository::class)->changeStatus($id, 1); + return app('json')->fail('商品不存在'); + } + return app('json')->success($data); + } + + /** + * TODO 秒杀时间段 + * @return mixed + * @author Qinii + * @day 2020-08-04 + */ + public function select() + { + return app('json')->success(app()->make(StoreSeckillTimeRepository::class)->selectTime()); + } + + +} diff --git a/app/controller/api/store/product/StoreReply.php b/app/controller/api/store/product/StoreReply.php new file mode 100644 index 00000000..98f186ee --- /dev/null +++ b/app/controller/api/store/product/StoreReply.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\product; + +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\validate\api\ProductReplyValidate; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductReplyRepository as repository; + +class StoreReply extends BaseController +{ + /** + * @var repository + */ + protected $repository; + protected $userInfo; + + /** + * StoreProduct constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @return mixed + */ + public function lst($id) + { + [$page, $limit] = $this->getPage(); + + $where['type'] = $this->request->param('type'); + $where['product_id'] = $id; + return app('json')->success($this->repository->getApiList($where,$page, $limit)); + } + + public function product($id, StoreOrderProductRepository $orderProductRepository) + { + $orderProduct = $orderProductRepository->userOrderProduct((int)$id, $this->request->uid()); + if (!$orderProduct || !$orderProduct->orderInfo) + return app('json')->fail('订单不存在'); + if ($orderProduct->is_reply) + return app('json')->fail('该商品已评价'); + return app('json')->success($orderProduct->toArray()); + } + + public function reply($id, ProductReplyValidate $validate) + { + $data = $this->request->params(['comment', 'product_score', 'service_score', 'postage_score', ['pics', []]]); + $validate->check($data); + $user = $this->request->userInfo(); + $data['uid'] = $this->request->uid(); + $data['order_product_id'] = (int)$id; + $data['nickname'] = $user['nickname']; + $data['avatar'] = $user['avatar']; + $this->repository->reply($data); + return app('json')->success('评价成功'); + } + +} diff --git a/app/controller/api/store/product/StoreSpu.php b/app/controller/api/store/product/StoreSpu.php new file mode 100644 index 00000000..f09807d6 --- /dev/null +++ b/app/controller/api/store/product/StoreSpu.php @@ -0,0 +1,288 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\store\product; + +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\StoreCategoryRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserHistoryRepository; +use crmeb\services\CopyCommand; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\SpuRepository; + +class StoreSpu extends BaseController +{ + protected $userInfo; + protected $repository; + + public function __construct(App $app, SpuRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->userInfo = $this->request->isLogin() ? $this->request->userInfo() : null; + } + + /** + * TODO 商品搜索列表 + * @return mixed + * @author Qinii + * @day 12/24/20 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([ + 'keyword', + 'cate_id', + 'cate_pid', + 'order', + 'price_on', + 'price_off', + 'brand_id', + 'pid', + 'mer_cate_id', + 'product_type', + 'action', + 'common', + 'is_trader', + 'product_ids', + 'mer_id' + ]); + $where['is_gift_bag'] = 0; + $where['product_type'] = 0; + $where['order'] = $where['order'] ?: 'star'; + if ($where['is_trader'] != 1) unset($where['is_trader']); + $data = $this->repository->getApiSearch($where, $page, $limit, $this->userInfo); + return app('json')->success($data); + } + + /** + * TODO 商户的商品搜索列表 + * @param $id + * @return mixed + * @author Qinii + * @day 12/24/20 + */ + public function merProductLst($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([ + 'keyword', 'cate_id', 'order', 'price_on', 'price_off', 'brand_id', 'pid', 'mer_cate_id', ['product_type', 0], 'action', 'common' + ]); + if ($where['action']) unset($where['product_type']); + $where['mer_id'] = $id; + $where['is_gift_bag'] = 0; + $where['order'] = $where['order'] ? $where['order'] : 'sort'; + $data = $this->repository->getApiSearch($where, $page, $limit, $this->userInfo); + return app('json')->success($data); + } + + /** + * TODO 推荐列表 + * @return mixed + * @author Qinii + * @day 12/24/20 + */ + public function recommend() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['common','mer_id']); + $where['is_gift_bag'] = 0; + //1:星级 + //2:用户收藏 + //3:创建时间 + switch (systemConfig('recommend_type')) { + case '1': + $where['order'] = 'star'; + break; + case '2': + $where['order'] = 'sales'; + if (!is_null($this->userInfo)) { + $cateId = app()->make(UserHistoryRepository::class)->getRecommend($this->userInfo->uid); + if ($cateId && count($cateId) > 5) + $where['cate_id'] = $cateId; + } + break; + case '3': + $where['order'] = 'create_time'; + break; + default: + $where['order'] = 'star'; + break; + } + $where['product_type'] = 0; + $where['is_stock'] = 1; + $data = $this->repository->getApiSearch($where, $page, $limit, $this->userInfo); + return app('json')->success($data); + } + + /** + * TODO 热门列表 + * @return mixed + * @author Qinii + * @day 12/24/20 + */ + public function hot($type) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['common','mer_id']); + $where['hot_type'] = $type; + $where['is_gift_bag'] = 0; + $where['order'] = 'star'; + $where['product_type'] = 0; + $data = $this->repository->getApiSearch($where, $page, $limit, null); + return app('json')->success($data); + } + + /** + * TODO 礼包列表 + * @return mixed + * @author Qinii + * @day 12/24/20 + */ + public function bag() + { + [$page, $limit] = $this->getPage(); + $where['is_gift_bag'] = 1; + $where['order'] = 'rank'; + $where['product_type'] = 0; + $data = $this->repository->getApiSearch($where, $page, $limit, null); + return app('json')->success($data); + } + + /** + * TODO 礼包推荐列表 + * @return mixed + * @author Qinii + * @day 12/24/20 + */ + public function bagRecommend() + { + [$page, $limit] = $this->getPage(); + $where['is_gift_bag'] = 1; + $where['hot_type'] = 'best'; + $where['product_type'] = 0; + $data = $this->repository->getApiSearch($where, $page, $limit, null); + return app('json')->success($data); + } + + /** + * TODO 活动分类 + * @param $type + * @return \think\response\Json + * @author Qinii + * @day 1/12/21 + */ + public function activeCategory($type) + { + $data = $this->repository->getActiveCategory($type); + return app('json')->success($data); + } + + /** + * TODO 根据标签获取数据 + * @return \think\response\Json + * @author Qinii + * @day 8/25/21 + */ + public function labelsLst() + { + [$page, $limit] = $this->getPage(); + $where['is_gift_bag'] = 0; + $merId = $this->request->param('mer_id', 0); + if ($merId) { + $where = ['mer_id' => $merId, 'mer_labels' => $this->request->param('labels')]; + } else { + $where = ['sys_labels' => $this->request->param('labels')]; + } + $data = $this->repository->getApiSearch($where, $page, $limit, null); + + return app('json')->success($data); + } + + public function local($id) + { + [$page, $limit] = $this->getPage(); + $merchant = app()->make(MerchantRepository::class)->get($id); + if (!in_array(1, $merchant['delivery_way'])) return app('json')->success(['count' => 0, 'list' => []]); + $where = [ + 'mer_id' => $id, + 'delivery_way' => 1, + 'is_gift_bag' => 0, + ]; + $data = $this->repository->getApiSearch($where, $page, $limit, $this->userInfo); + + return app('json')->success($data); + } + + /** + * TODO 获取复制口令 + * @return \think\response\Json + * @author Qinii + * @day 9/2/21 + */ + public function copy() + { + $id = $this->request->param('id'); + $type = $this->request->param('product_type'); + $str = app()->make(CopyCommand::class)->create($id, $type, $this->userInfo); + return app('json')->success(['str' => $str]); + } + + public function get($id) + { + return app('json')->success($this->repository->get($id)); + } + + public function getProductByCoupon() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params([ + 'keyword', + 'cate_id', + 'cate_pid', + 'order', + 'price_on', + 'price_off', + 'brand_id', + 'pid', + 'mer_cate_id', + 'coupon_id' + ]); + $where['is_gift_bag'] = 0; + $where['order'] = $where['order'] ? $where['order'] : 'star'; + $data = $this->repository->getApiSearchByCoupon($where, $page, $limit, $this->userInfo); + return app('json')->success($data); + } + + public function getHotRanking() + { + $cateId = $this->request->param('cate_pid',0); + $cateId = is_array($cateId) ?:explode(',',$cateId); + $data = []; + foreach ($cateId as $cate_id) { + $cate = app()->make(StoreCategoryRepository::class)->get($cate_id); + if ($cate) { + $list = $this->repository->getHotRanking($cate_id); + $data[] = [ + 'cate_id' => $cate['store_category_id'] ?? 0, + 'cate_name' => $cate['cate_name'] ?? '总榜', + 'list' => $list, + ]; + } + } + return app('json')->success($data); + } + + + +} diff --git a/app/controller/api/store/service/Service.php b/app/controller/api/store/service/Service.php new file mode 100644 index 00000000..1a6d1180 --- /dev/null +++ b/app/controller/api/store/service/Service.php @@ -0,0 +1,207 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\store\service; + + +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\store\service\StoreServiceUserRepository; +use app\common\repositories\system\ExtendRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\basic\BaseController; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Cache; + +/** + * Class Service + * @package app\controller\api\store\service + * @author xaboy + * @day 2020/5/29 + */ +class Service extends BaseController +{ + /** + * @var StoreServiceRepository + */ + protected $repository; + + /** + * Service constructor. + * @param App $app + * @param StoreServiceRepository $repository + */ + public function __construct(App $app, StoreServiceRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @param $id + * @param StoreServiceLogRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/15 + */ + public function chatHistory($id, StoreServiceLogRepository $repository) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->userList($id, $this->request->uid(), $page, $limit)); + } + + /** + * @param StoreServiceLogRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/16 + */ + public function getList(StoreServiceUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->userMerchantList($this->request->uid(), $page, $limit)); + } + + /** + * @param StoreServiceLogRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/16 + */ + public function serviceUserList($merId, StoreServiceUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->merUserList($merId, $this->request->uid(), $page, $limit)); + } + + /** + * @param $merId + * @param $id + * @param StoreServiceLogRepository $repository + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/15 + */ + public function serviceHistory($merId, $id, StoreServiceLogRepository $repository) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->merList($merId, $id, $this->request->uid(), $page, $limit)); + } + + public function user($merId, $uid, StoreServiceUserRepository $serviceUserRepository) + { + if (!$service = $this->repository->search([ + 'uid' => $this->request->uid(), + 'mer_id' => (int)$merId, + 'status' => 1 + ])->find()) { + return app('json')->fail('没有权限'); + } + $user = $serviceUserRepository->search(['uid' => $uid, 'service_user_id' => $service->service_user_id])->with(['user' => function ($query) use ($merId) { + $query->field('uid,avatar,nickname,is_promoter' . (!$merId ? ',phone' : '')); + }, 'mark' => function ($query) use ($merId) { + $query->where('mer_id', $merId)->bind(['mark' => 'extend_value']); + }])->find(); + if (!$user) { + return app('json')->fail('用户不存在'); + } + return app('json')->success($user->toArray()); + } + + public function mark($merId, $uid, StoreServiceUserRepository $serviceUserRepository, ExtendRepository $extendRepository) + { + $data = $this->request->params(['mark']); + if (!$service = $this->repository->search([ + 'uid' => $this->request->uid(), + 'mer_id' => (int)$merId, + 'status' => 1 + ])->find()) { + return app('json')->fail('没有权限'); + } + if ($service->mer_id && !$serviceUserRepository->existsWhere(['uid' => (int)$uid, 'mer_id' => $service->mer_id])) { + return app('json')->fail('用户不存在'); + } + $extendRepository->updateInfo(ExtendRepository::TYPE_SERVICE_USER_MARK, (int)$uid, $service->mer_id, (string)$data['mark']); + return app('json')->success('备注成功'); + } + + public function merchantInfo($id) + { + if ($id) { + $merchant = app()->make(MerchantRepository::class)->get((int)$id); + if (!$merchant) + return app('json')->fail('商户不存在'); + $data = [ + 'mer_id' => $merchant['mer_id'], + 'avatar' => $merchant['mer_avatar'], + 'name' => $merchant['mer_name'], + ]; + } else { + $config = systemConfig(['site_logo', 'site_name']); + $data = [ + 'mer_id' => 0, + 'avatar' => $config['site_logo'], + 'name' => $config['site_name'], + ]; + } + return app('json')->success($data); + } + + public function hasService($id){ + $uid = 0; + if ($this->request->isLogin()) { + $uid = $this->request->uid(); + } + $data = $this->repository->getChatService($id, $uid); + if (!$data) { + return app('json')->fail('暂无可用客服'); + } + return app('json')->success(200); + } + + public function scanLogin($key) + { + $serviceId = (int)$this->request->param('service_id'); + if (!$serviceId || !$service = $this->repository->search([ + 'uid' => $this->request->uid(), + 'service_id' => $serviceId, + ])->find()) { + return app('json')->fail('用户不存在'); + } + if (!$service['is_open'] || !$service['status']) { + return app('json')->fail('账号已被关闭'); + } + if (Cache::has('_scan_ser_login' . $key)) + Cache::set('_scan_ser_login' . $key, $serviceId); + else + return app('json')->fail('操作超时'); + + return app('json')->success('登录成功'); + } + +} diff --git a/app/controller/api/user/Admin.php b/app/controller/api/user/Admin.php new file mode 100644 index 00000000..95379923 --- /dev/null +++ b/app/controller/api/user/Admin.php @@ -0,0 +1,247 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\controller\merchant\Common; +use crmeb\basic\BaseController; +use think\App; +use think\exception\HttpResponseException; +use think\exception\ValidateException; +use think\facade\Db; +use think\response\Json; + +class Admin extends BaseController +{ + public function __construct(App $app) + { + parent::__construct($app); + } + + public function orderStatistics($merId, StoreOrderRepository $repository) + { + $order = $repository->OrderTitleNumber($merId, null); + $common = app()->make(Common::class); + $data = []; + $data['today'] = $common->mainGroup('today', $merId); + $data['yesterday'] = $common->mainGroup('yesterday', $merId); + $data['month'] = $common->mainGroup('month', $merId); + return app('json')->success(compact('order', 'data')); + } + + public function orderDetail($merId, StoreOrderRepository $repository) + { + [$page, $limit] = $this->getPage(); + list($start, $stop) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + ], true); + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $where = $this->request->has('start') ? ['dateRange' => compact('start', 'stop')] : []; + $list = $repository->orderGroupNumPage($where, $page, $limit, $merId); + return app('json')->success($list); + } + + public function orderList($merId, StoreOrderRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status']); + $where['mer_id'] = $merId; + $where['is_del'] = 0; + return app('json')->success($repository->merchantGetList($where, $page, $limit)); + } + + public function order($merId, $id, StoreOrderRepository $repository) + { + $detail = $repository->getDetail($id); + if (!$detail) + return app('json')->fail('订单不存在'); + if ($detail['mer_id'] != $merId) + return app('json')->fail('没有权限'); + return app('json')->success($detail->toArray()); + } + + + protected function checkOrderAuth($merId, $id) + { + if (!app()->make(StoreOrderRepository::class)->existsWhere(['mer_id' => $merId, 'order_id' => $id])) + throw new ValidateException('没有权限'); + } + + public function mark($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + $data = $this->request->params(['remark']); + $repository->update($id, $data); + return app('json')->success('备注成功'); + } + + public function price($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + + $data = $this->request->params(['total_price', 'pay_postage']); + + if ($data['total_price'] < 0 || $data['pay_postage'] < 0) + return app('json')->fail('金额不可未负数'); + if (!$repository->merStatusExists((int)$id, $merId)) + return app('json')->fail('订单信息或状态错误'); + $repository->eidt($id, $data, $this->request->serviceInfo()->service_id); + return app('json')->success('修改成功'); + } + + public function delivery($merId, $id, StoreOrderRepository $repository) + { + $this->checkOrderAuth($merId, $id); + if (!$repository->merDeliveryExists((int)$id, $merId,1)) + return app('json')->fail('订单信息或状态错误'); + $type = $this->request->param('delivery_type'); + if($type == 4){ + if(!systemConfig('crmeb_serve_dump')) return app('json')->fail('电子面单功能未开启'); + $params = $this->request->params([ + 'delivery_name', + 'from_name', + 'from_tel', + 'from_addr', + 'temp_id', + ]); + $repository->dump($id,$merId,$params); + } else { + $data = $this->request->params([ + 'delivery_type', + 'delivery_name', + 'delivery_id', + ]); + if(preg_match('/([\x81-\xfe][\x40-\xfe])/',$data['delivery_id'])) + return app('json')->fail('请输入正确的单号/电话'); + $repository->delivery($id, $merId, $data); + } + return app('json')->success('发货成功'); + } + + public function payPrice($merId, StoreOrderRepository $repository) + { + list($start, $stop, $month) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + 'month' + ], true); + + if ($month) { + $start = date('Y/m/d', strtotime(getStartModelTime('month'))); + $stop = date('Y/m/d H:i:s', strtotime('+ 1day')); + $front = date('Y/m/d', strtotime('first Day of this month', strtotime('-1 day', strtotime('first Day of this month')))); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } else { + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $space = bcsub($stop, $start, 0);//间隔时间段 + $front = bcsub($start, $space, 0);//第一个时间段 + + $front = date('Y/m/d H:i:s', $front); + $start = date('Y/m/d H:i:s', $start); + $stop = date('Y/m/d H:i:s', $stop); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } + $frontPrice = $repository->dateOrderPrice($front . '-' . $end, $merId); + $afterPrice = $repository->dateOrderPrice($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $chartInfo = $repository->chartTimePrice($start, date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $data['chart'] = $chartInfo;//营业额图表数据 + $data['time'] = $afterPrice;//时间区间营业额 + $increase = (float)bcsub((string)$afterPrice, (string)$frontPrice, 2); //同比上个时间区间增长营业额 + $growthRate = abs($increase); + if ($growthRate == 0) $data['growth_rate'] = 0; + else if ($frontPrice == 0) $data['growth_rate'] = bcmul($growthRate, 100, 0); + else $data['growth_rate'] = (int)bcmul((string)bcdiv((string)$growthRate, (string)$frontPrice, 2), '100', 0);//时间区间增长率 + $data['increase_time'] = abs($increase); //同比上个时间区间增长营业额 + $data['increase_time_status'] = $increase >= 0 ? 1 : 2; //同比上个时间区间增长营业额增长 1 减少 2 + + return app('json')->success($data); + } + + /** + * @param StoreOrderRepository $repository + * @return Json + * @author xaboy + * @day 2020/8/27 + */ + public function payNumber($merId, StoreOrderRepository $repository) + { + list($start, $stop, $month) = $this->request->params([ + ['start', strtotime(date('Y-m'))], + ['stop', time()], + 'month' + ], true); + + if ($month) { + $start = date('Y/m/d', strtotime(getStartModelTime('month'))); + $stop = date('Y/m/d H:i:s', strtotime('+ 1day')); + $front = date('Y/m/d', strtotime('first Day of this month', strtotime('-1 day', strtotime('first Day of this month')))); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } else { + if ($start == $stop) return app('json')->fail('参数有误'); + if ($start > $stop) { + $middle = $stop; + $stop = $start; + $start = $middle; + } + $space = bcsub($stop, $start, 0);//间隔时间段 + $front = bcsub($start, $space, 0);//第一个时间段 + + $front = date('Y/m/d H:i:s', $front); + $start = date('Y/m/d H:i:s', $start); + $stop = date('Y/m/d H:i:s', $stop); + $end = date('Y/m/d H:i:s', strtotime($start . ' -1 second')); + } + $frontNumber = $repository->dateOrderNum($front . '-' . $end, $merId); + $afterNumber = $repository->dateOrderNum($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $chartInfo = $repository->chartTimeNum($start . '-' . date('Y/m/d H:i:s', strtotime($stop . '-1 second')), $merId); + $data['chart'] = $chartInfo;//订单数图表数据 + $data['time'] = $afterNumber;//时间区间订单数 + $increase = $afterNumber - $frontNumber; //同比上个时间区间增长订单数 + $growthRate = abs($increase); + if ($growthRate == 0) $data['growth_rate'] = 0; + else if ($frontNumber == 0) $data['growth_rate'] = bcmul($growthRate, 100, 0); + else $data['growth_rate'] = (int)bcmul((string)bcdiv((string)$growthRate, (string)$frontNumber, 2), '100', 0);//时间区间增长率 + $data['increase_time'] = abs($increase); //同比上个时间区间增长营业额 + $data['increase_time_status'] = $increase >= 0 ? 1 : 2; //同比上个时间区间增长营业额增长 1 减少 2 + + return app('json')->success($data); + } + + public function getFormData($merId) + { + $config = [ + 'mer_from_com', + 'mer_from_name', + 'mer_from_tel', + 'mer_from_addr', + 'mer_config_siid', + 'mer_config_temp_id' + ]; + $data = merchantConfig($merId,$config); + return app('json')->success($data); + } +} diff --git a/app/controller/api/user/FeedBackCategory.php b/app/controller/api/user/FeedBackCategory.php new file mode 100644 index 00000000..35bdff62 --- /dev/null +++ b/app/controller/api/user/FeedBackCategory.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\user; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\user\FeedBackCategoryRepository as repository; + +class FeedBackCategory extends BaseController +{ + + protected $repository; + + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + return app('json')->success($this->repository->getFormatList(0,1)); + } +} diff --git a/app/controller/api/user/Feedback.php b/app/controller/api/user/Feedback.php new file mode 100644 index 00000000..3fba02f0 --- /dev/null +++ b/app/controller/api/user/Feedback.php @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + +use crmeb\basic\BaseController; +use app\common\repositories\user\FeedbackRepository; +use app\validate\api\FeedbackValidate; +use think\App; + +class Feedback extends BaseController +{ + protected $repository; + + public function __construct(App $app, FeedbackRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @param FeedbackValidate $validate + * @param FeedbackRepository $repository + * @return mixed + * @author xaboy + * @day 2020/5/28 + */ + public function feedback(FeedbackValidate $validate) + { + $data = $this->request->params(['type', 'content', ['images', []], 'realname', 'contact',['status',0]]); + $validate->check($data); + $data['uid'] = $this->request->uid(); + $FeedBack = $this->repository->create($data); + + event('user.feedback',compact('FeedBack')); + return app('json')->success('反馈成功'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/5/28 + */ + public function feedbackList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList(['uid' => $this->request->uid(),'is_del' => 0], $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->uidExists($id, $this->request->uid())) + return app('json')->fail('数据不存在'); + $feedback = $this->repository->get($id); + return app('json')->success($feedback); + } +} diff --git a/app/controller/api/user/Member.php b/app/controller/api/user/Member.php new file mode 100644 index 00000000..889c394c --- /dev/null +++ b/app/controller/api/user/Member.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + +use app\common\repositories\user\UserBillRepository; +use crmeb\basic\BaseController; +use app\common\repositories\user\FeedbackRepository; +use think\App; + +class Member extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBillRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getMemberValue() + { + $where = [ + 'uid' => $this->request->uid(), + 'category' => 'sys_members', + ]; + $data = $this->repository->month($where); + return app('json')->success($data); + } +} diff --git a/app/controller/api/user/Svip.php b/app/controller/api/user/Svip.php new file mode 100644 index 00000000..de6b339b --- /dev/null +++ b/app/controller/api/user/Svip.php @@ -0,0 +1,168 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + +use app\common\model\user\UserOrder; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\groupData\GroupRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\common\repositories\user\MemberinterestsRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserOrderRepository; +use app\common\repositories\user\UserRepository; +use crmeb\basic\BaseController; +use app\common\repositories\user\FeedbackRepository; +use think\App; +use think\exception\ValidateException; + +class Svip extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBillRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + if (!systemConfig('svip_switch_status')) throw new ValidateException('付费会员未开启'); + } + + /** + * TODO 会员卡类型列表 + * @param GroupRepository $groupRepository + * @param GroupDataRepository $groupDataRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/7 + */ + public function getTypeLst(GroupRepository $groupRepository,GroupDataRepository $groupDataRepository) + { + $group_id = $groupRepository->getSearch(['group_key' => 'svip_pay'])->value('group_id'); + $where['group_id'] = $group_id; + $where['status'] = 1; + $list = $groupDataRepository->getSearch($where)->field('group_data_id,value,sort,status')->order('sort DESC')->select(); + if ($this->request->isLogin() && $this->request->userInfo()->is_svip != -1) { + foreach ($list as $item) { + if ($item['value']['svip_type'] != 1) $res[] = $item; + } + } + $list = $res ?? $list; + $def = []; + if ($list && isset($list[0])) { + $def = $list[0] ? (['group_data_id' => $list[0]['group_data_id']] + $list[0]['value']) : []; + } + return app('json')->success(['def' => $def, 'list' => $list]); + } + + /** + * TODO 购买会员 + * @param $id + * @param GroupDataRepository $groupDataRepository + * @param ServeOrderRepository $serveOrderRepository + * @return \think\response\Json|void + * @author Qinii + * @day 2022/11/7 + */ + public function createOrder($id, GroupDataRepository $groupDataRepository, UserOrderRepository $userOrderRepository) + { + $params = $this->request->params(['pay_type','return_url']); + if (!in_array($params['pay_type'], ['weixin', 'routine', 'h5', 'alipay', 'alipayQr', 'weixinQr'], true)) + return app('json')->fail('请选择正确的支付方式'); + $res = $groupDataRepository->getWhere(['group_data_id' => $id, 'status' => 1]); + if (!$res) return app('json')->fail('参数有误~'); + if ($this->request->userInfo()->is_svip == 3) + return app('json')->fail('您已经是终身会员~'); + if ($this->request->userInfo()->is_svip !== -1 && $res['value']['svip_type'] == 1) + return app('json')->fail('请选择其他会员类型'); + $params['is_app'] = $this->request->isApp(); + return $userOrderRepository->add($res,$this->request->userInfo(),$params); + } + + /** + * TODO 会员中心个人信息 + * @return \think\response\Json + * @author Qinii + * @day 2022/11/9 + */ + public function svipUserInfo() + { + if ($this->request->isLogin()) { + $user = app()->make(UserRepository::class)->getSearch([])->field('uid,nickname,avatar,is_svip,svip_endtime,svip_save_money')->find($this->request->uid()); + if ($user && $user['is_svip'] == 3) $user['svip_endtime'] = date('Y-m-d H:i:s',strtotime("+100 year")); + } + $data['user'] = $user ?? new \stdClass(); + $data['interests'] = systemConfig('svip_switch_status') ? app()->make(MemberinterestsRepository::class)->getInterestsByLevel(MemberinterestsRepository::TYPE_SVIP) : []; + + return app('json')->success($data); + } + + /** + * TODO 获取会员优惠券列表 + * @param StoreCouponRepository $couponRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/17 + */ + public function svipCoupon(StoreCouponRepository $couponRepository) + { + $where['send_type'] = $couponRepository::GET_COUPON_TYPE_SVIP; + $uid = $this->request->isLogin() ? $this->request->uid() : null; + $data = $couponRepository->sviplist($where, $uid); + return app('json')->success($data); + } + + /** + * TODO 领取会员优惠券 + * @param $id + * @param StoreCouponRepository $couponRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/17 + */ + public function receiveCoupon($id, StoreCouponRepository $couponRepository) + { + if (!$this->request->userInfo()->is_svip) + return app('json')->fail('您还不是付费会员'); + if (!$couponRepository->exists($id)) + return app('json')->fail('优惠券不存在'); + try { + $couponRepository->receiveSvipCounpon($id, $this->request->uid()); + } catch (\Exception $e) { + return app('json')->fail('优惠券已被领完'); + } + return app('json')->success('领取成功'); + } + + /** + * TODO 会员专属商品 + * @param SpuRepository $spuRepository + * @return \think\response\Json + * @author Qinii + * @day 2022/11/17 + */ + public function svipProductList(SpuRepository $spuRepository) + { + [$page, $limit] = $this->getPage(); + $user = $this->request->isLogin() ? $this->request->userInfo() : null; + $where['is_gift_bag'] = 0; + $where['product_type'] = 0; + $where['order'] = 'star'; + $where['svip'] = 1; + $data = $spuRepository->getApiSearch($where, $page, $limit, $user); + return app('json')->success($data); + } +} diff --git a/app/controller/api/user/User.php b/app/controller/api/user/User.php new file mode 100644 index 00000000..1b0d602d --- /dev/null +++ b/app/controller/api/user/User.php @@ -0,0 +1,531 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + + +use app\common\repositories\store\IntegralRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\system\CacheRepository; +use app\common\repositories\user\MemberinterestsRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\user\UserVisitRepository; +use app\validate\api\UserBaseInfoValidate; +use crmeb\basic\BaseController; +use crmeb\services\MiniProgramService; +use crmeb\services\SmsService; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +class User extends BaseController +{ + protected $repository; + protected $user; + + public function __construct(App $app, UserRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->user = $this->request->userInfo(); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/6/22 + */ + public function spread_image() + { + $type = $this->request->param('type'); + $res = $type == 'routine' + ? $this->repository->routineSpreadImage($this->user) + : $this->repository->wxSpreadImage($this->user); + return app('json')->success($res); + } + + public function spread_image_v2() + { + $type = $this->request->param('type'); + $user = $this->user; + $siteName = systemConfig('site_name'); + $qrcode = $type == 'routine' + ? $this->repository->mpQrcode($user) + : $this->repository->wxQrcode($user); + $poster = systemGroupData('spread_banner'); + $nickname = $user['nickname']; + $mark = '邀请您加入' . $siteName; + return app('json')->success(compact('qrcode', 'poster', 'nickname', 'mark')); + } + + public function spread_info() + { + $user = $this->user; + $make = app()->make(UserBrokerageRepository::class); + $user->append(['one_level_count', 'lock_brokerage', 'two_level_count', 'spread_total', 'yesterday_brokerage', 'total_extract', 'total_brokerage', 'total_brokerage_price']); + $show_brokerage = (bool)$make->search(['type' => 0])->count(); + $data = [ + 'total_brokerage_price' => $user->total_brokerage_price, + 'lock_brokerage' => $user->lock_brokerage, + 'one_level_count' => $user->one_level_count, + 'two_level_count' => $user->two_level_count, + 'spread_total' => $user->spread_total, + 'yesterday_brokerage' => $user->yesterday_brokerage, + 'total_extract' => $user->total_extract, + 'total_brokerage' => $user->total_brokerage, + 'brokerage_price' => $user->brokerage_price, + 'show_brokerage' => $show_brokerage, + 'brokerage' => $show_brokerage ? ($user->brokerage ?: ['brokerage_level' => 0, 'brokerage_name' => '普通分销员']) : null, + 'now_money' => $user->now_money, + 'broken_day' => (int)systemConfig('lock_brokerage_timer'), + 'user_extract_min' => (int)systemConfig('user_extract_min'), + ]; + return app('json')->success($data); + } + + public function brokerage_all() + { + return app('json')->success(app()->make(UserBrokerageRepository::class)->all(0)); + } + + public function brokerage_info() + { + $make = app()->make(UserBrokerageRepository::class); + + $user = $this->user; + $brokerage = $user->brokerage; + $next_brokerage = $make->getNextLevel($user->brokerage_level) ?: $brokerage; + $brokerage_rate = null; + if ($next_brokerage || $brokerage) { + $brokerage_rate = $make->getLevelRate($user, $next_brokerage); + } + $down_brokerage = null; + if ($next_brokerage) { + $down_brokerage = $make->getNextLevel($next_brokerage->brokerage_level); + } + $brokerage = $brokerage ?: ['brokerage_level' => 0, 'brokerage_name' => '普通分销员']; + return app('json')->success(compact('brokerage', 'next_brokerage', 'brokerage_rate', 'down_brokerage')); + } + + public function brokerage_notice() + { + $user = $this->user; + if (!$user->brokerage_level) { + return app('json')->fail('无需通知'); + } + $make = app()->make(CacheRepository::class); + $key = 'notice_' . $user->uid . '_' . $user->brokerage_level; + if ($make->getResult($key)) { + return app('json')->fail('已通知'); + } + $make->create(['key' => $key, 'result' => 1, 'expire_time' => 0]); + $userBrokerageRepository = app()->make(UserBrokerageRepository::class); + return app('json')->success(['type' => $userBrokerageRepository->getNextLevel($user->brokerage_level) ? 'level' : 'top']); + } + + /** + * @param UserBillRepository $billRepository + * @return mixed + * @author xaboy + * @day 2020/6/22 + */ + public function bill(UserBillRepository $billRepository) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($billRepository->userList([ + 'now_money' => $this->request->param('type', 0), + 'status' => 1, + ], $this->request->uid(), $page, $limit)); + } + + /** + * @param UserBillRepository $billRepository + * @return mixed + * @author xaboy + * @day 2020/6/22 + */ + public function brokerage_list(UserBillRepository $billRepository) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($billRepository->userList([ + 'category' => 'brokerage', + ], $this->request->uid(), $page, $limit)); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function spread_order() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->subOrder($this->request->uid(), $page, $limit)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function binding() + { + $data = $this->request->params(['phone', 'sms_code']); + $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'binding'); + if (!$data['sms_code'] || !$sms_code) + return app('json')->fail('验证码不正确'); + $user = $this->repository->accountByUser($data['phone']); + if ($user) { + if (systemConfig('is_phone_login') === '1') { + return app('json')->fail('手机号已被绑定'); + } + $data = ['phone' => $data['phone']]; + } else { + $data = ['account' => $data['phone'], 'phone' => $data['phone']]; + } + $this->repository->update($this->request->uid(), $data); + return app('json')->success('绑定成功'); + } + + /** + * TODO 小程序获取手机号绑定 + * @author Qinii + * @day 10/11/21 + */ + public function mpPhone() + { + $code = $this->request->param('code'); + $iv = $this->request->param('iv'); + $encryptedData = $this->request->param('encryptedData'); + $miniProgramService = MiniProgramService::create(); + $userInfoCong = $miniProgramService->getUserInfo($code); + $session_key = $userInfoCong['session_key']; + + $data = $miniProgramService->encryptor($session_key, $iv, $encryptedData); + + $user = $this->repository->accountByUser($data['purePhoneNumber']); + if ($user) { + $data = ['phone' => $data['purePhoneNumber']]; + } else { + $data = ['account' => $data['purePhoneNumber'], 'phone' => $data['purePhoneNumber']]; + } + $this->repository->update($this->request->uid(), $data); + return app('json')->success('绑定成功'); + } + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/6/22 + */ + public function spread_list() + { + [$level, $sort, $nickname] = $this->request->params(['level', 'sort', 'keyword'], true); + $uid = $this->request->uid(); + [$page, $limit] = $this->getPage(); + return app('json')->success($level == 2 + ? $this->repository->getTwoLevelList($uid, $nickname, $sort, $page, $limit) + : $this->repository->getOneLevelList($uid, $nickname, $sort, $page, $limit)); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/6/22 + */ + public function spread_top() + { + [$page, $limit] = $this->getPage(); + $type = $this->request->param('type', 0); + $func = $type == 1 ? 'spreadMonthTop' : 'spreadWeekTop'; + $data = $this->repository->{$func}($page, $limit); + return app('json')->success($data); + } + + /** + * @return mixed + * @author xaboy + * @day 2020/6/22 + */ + public function brokerage_top() + { + [$page, $limit] = $this->getPage(); + $type = $this->request->param('type', 'week'); + $uid = $this->request->uid(); + $func = $type == 'month' ? 'brokerageMonthTop' : 'brokerageWeekTop'; + $data = $this->repository->{$func}($uid, $page, $limit); + return app('json')->success($data); + } + + public function history(UserVisitRepository $repository) + { + $uid = $this->request->uid(); + [$page, $limit] = $this->getPage(); + return app('json')->success($repository->getHistory($uid, $page, $limit)); + } + + public function deleteHistory($id, UserVisitRepository $repository) + { + $uid = $this->request->uid(); + + if (!$repository->getWhereCount(['user_visit_id' => $id, 'uid' => $uid])) + return app('json')->fail('数据不存在'); + $repository->delete($id); + return app('json')->success('删除成功'); + } + + public function deleteHistoryBatch(UserVisitRepository $repository) + { + $uid = $this->request->uid(); + $data = $this->request->param('ids'); + if (!empty($data) && is_array($data)) { + foreach ($data as $id) { + if (!$repository->getWhereCount(['user_visit_id' => $id, 'uid' => $uid])) + return app('json')->fail('数据不存在'); + } + $repository->batchDelete($data, null); + } + if ($data == 1) + $repository->batchDelete(null, $uid); + + return app('json')->success('删除成功'); + } + + public function account() + { + $user = $this->user; + if (!$user->phone) return app('json')->fail('请绑定手机号'); + return app('json')->success($this->repository->selfUserList($user->phone)); + } + + public function switchUser() + { + $uid = (int)$this->request->param('uid'); + if (!$uid) return app('json')->fail('用户不存在'); + $userInfo = $this->user; + if (!$userInfo->phone) return app('json')->fail('请绑定手机号'); + $user = $this->repository->switchUser($userInfo, $uid); + $tokenInfo = $this->repository->createToken($user); + $this->repository->loginAfter($user); + return app('json')->success($this->repository->returnToken($user, $tokenInfo)); + } + + public function edit() + { + $data = $this->request->params(['avatar', 'nickname']); + $uid = (int)$this->request->param('uid'); + if (!$uid) return app('json')->fail('用户不存在'); + + if (empty($data['avatar'])) unset($data['avatar']); + if (empty($data['nickname'])) unset($data['nickname']); + if (empty($data)) return app('json')->fail('参数丢失'); + $this->repository->update($this->request->uid(), $data); + + return app('json')->success('修改成功'); + } + + public function changePassword() + { + $data = $this->request->params(['repassword','password', 'sms_code']); + + if (!$this->user->phone) + return app('json')->fail('请先绑定手机号'); + if (empty($data['repassword']) || empty($data['password'])) + return app('json')->fail('请输入密码'); + if ($data['repassword'] !== $data['password']) + return app('json')->fail('两次密码不一致'); + + $sms_code = app()->make(SmsService::class)->checkSmsCode($this->user->phone, $data['sms_code'], 'change_pwd'); + if (!$data['sms_code'] || !$sms_code) + return app('json')->fail('验证码不正确'); + + $password = $this->repository->encodePassword($data['password']); + $this->repository->update($this->request->uid(), ['pwd' => $password]); + return app('json')->success('绑定成功'); + } + + public function changePhone() + { + $data = $this->request->params(['phone', 'sms_code']); + $sms_code = app()->make(SmsService::class)->checkSmsCode($data['phone'], $data['sms_code'], 'change_phone'); + if (!$data['sms_code'] || !$sms_code) + return app('json')->fail('验证码不正确'); + $user = $this->repository->accountByUser($data['phone']); + $data['main_uid'] = 0; + if ($user) { + if ($this->request->userInfo()->account !== $data['phone']) { + $data['account'] = $this->request->userInfo()->account.'_'.$this->request->uid(); + } + } else { + $data['account'] = $data['phone']; + } + unset($data['sms_code']); + $this->repository->update($this->request->uid(), $data); + return app('json')->success('修改成功'); + } + + + public function getAgree($key) + { + $make = app()->make(CacheRepository::class); + $data = $make->getResult($key); + return app('json')->success($data); + } + + public function integralInfo(UserBillRepository $make) + { + if (!systemConfig('integral_status')) { + return app('json')->fail('积分功能未开启'); + } + + $integral = $this->user->integral; + $lockIntegral = $make->lockIntegral($this->user->uid); + $deductionIntegral = $make->deductionIntegral($this->user->uid); + $totalGainIntegral = $make->totalGainIntegral($this->user->uid); + $make1 = app()->make(IntegralRepository::class); + $nextClearDay = $make1->getTimeoutDay(); + $status = $nextClearDay < strtotime('+20 day'); + $invalidDay = $make1->getInvalidDay(); + if ($status && $integral > 0 && $invalidDay) { + $validIntegral = $make->validIntegral($this->user->uid, date('Y-m-d H:i:s', $invalidDay), date('Y-m-d H:i:s', $nextClearDay)); + if ($integral > $validIntegral) { + $nextClearIntegral = (int)bcsub($integral, $validIntegral, 0); + } else { + $nextClearIntegral = 0; + } + } else { + $nextClearIntegral = 0; + } + $nextClearDay = date('m月d日', $nextClearDay); + $clear = compact('nextClearDay', 'status', 'nextClearIntegral'); + + return app('json')->success(compact('integral', 'lockIntegral', 'deductionIntegral', 'totalGainIntegral', 'clear')); + } + + public function integralList(UserBillRepository $repository) + { + if (!systemConfig('integral_status')) { + return app('json')->fail('积分功能未开启'); + } + [$page, $limit] = $this->getPage(); + $data = $repository->userList(['category' => 'integral'], $this->user->uid, $page, $limit); + return app('json')->success($data); + } + + public function services() + { + $uid = $this->user->uid; + $where = $this->request->params(['is_verify', 'customer', 'is_goods', ['is_open',1]]); + $is_sys = $this->request->param('is_sys'); + return app('json')->success(app()->make(StoreServiceRepository::class)->getServices($uid, $where,$is_sys)); + } + + public function memberInfo() + { + if (!systemConfig('member_status')) return app('json')->fail('未开启会员功能'); + $make = app()->make(UserBrokerageRepository::class); + $data['uid'] = $this->user->uid; + $data['avatar'] = $this->user->avatar; + $data['nickname'] = $this->user->nickname; + $data['member_value'] = $this->user->member_value; + $data['member'] = $this->user->member; + $next_level = $make->getNextLevel($this->user->member_level, 1); + if (!$next_level && $data['member']) { + $next_level = $this->user->member->toArray(); + $next_level['brokerage_rule']['value'] = 0; + } + $data['next_level'] = $next_level; + + $makeInteres = app()->make(MemberinterestsRepository::class); + $data['interests'] = systemConfig('member_interests_status') ? $makeInteres->getInterestsByLevel($makeInteres::TYPE_FREE,$this->user->member_level) : [] ; + + $data['today'] = app()->make(UserBillRepository::class)->search([ + 'category' => 'sys_members', + 'uid' => $this->user->uid, + 'day' => date('Y-m-d', time()) + ])->sum('number'); + + $config_key = ['member_pay_num', 'member_sign_num', 'member_reply_num', 'member_share_num']; + if (systemConfig('community_status')) $config_key[] = 'member_community_num'; + + $config= systemConfig($config_key); + if ($this->user->is_svip > 0) { + foreach ($config as $key => $item) { + $data['config'][$key] = $item .' x' . $makeInteres->getSvipInterestVal($makeInteres::HAS_TYPE_MEMBER).' '; + } + } else { + $data['config'] = $config; + } + + return app('json')->success($data); + } + + public function notice() + { + $type = $this->request->param('type',0); + $arr = [ + '0' => 'brokerage_level', + '1' => 'member_level', + ]; + $filed = $arr[$type]; + if (!$this->user->$filed) { + return app('json')->fail('无需通知'); + } + + $make = app()->make(CacheRepository::class); + $key = 'notice_' . $filed . '_' . $this->user->uid; + if ($ret = $make->getWhere(['key' => $key])) { + $userBrokerageRepository = app()->make(UserBrokerageRepository::class); + $level = app()->make(UserBrokerageRepository::class)->getWhere( + ['brokerage_level' => $ret->result, 'type' => $type], + 'brokerage_name,brokerage_icon,brokerage_rule' + ); + $next_level = $userBrokerageRepository->getNextLevel($this->user->$filed, $type); + $ret->delete(); + $type = $next_level ? 'level' : 'top'; + return app('json')->success(compact('type', 'level')); + } + return app('json')->fail('已通知'); + } + + public function updateBaseInfo(UserBaseInfoValidate $validate) + { + if (systemConfig('open_update_info') != '1') { + return app('json')->fail('不允许修改基本信息'); + } + $nickname = $this->request->param('nickname'); + $avatar = $this->request->param('avatar'); + if (!$nickname && !$avatar) + return app('json')->fail('未做任何修改'); + $user = $this->request->userInfo(); + if(!empty($nickname)) { + $validate->check(['nickname' => $nickname]); + $data['nickname'] = $nickname; + } + if(!empty($avatar)) { + $data['avatar'] = $avatar; + } + $this->repository->updateBaseInfo($data,$user); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/api/user/UserAddress.php b/app/controller/api/user/UserAddress.php new file mode 100644 index 00000000..386e5870 --- /dev/null +++ b/app/controller/api/user/UserAddress.php @@ -0,0 +1,155 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + +use app\common\repositories\store\CityAreaRepository; +use think\App; +use crmeb\basic\BaseController; +use app\validate\api\UserAddressValidate as validate; +use app\common\repositories\user\UserAddressRepository as repository; +use think\exception\ValidateException; + +class UserAddress extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * UserAddress constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst() + { + return app('json')->success($this->repository->getList($this->request->uid())); + } + + public function detail($id) + { + $uid = $this->request->uid(); + if (!$this->repository->existsWhere(['address_id' => $id, 'uid' => $uid])) { + return app('json')->fail('地址不存在'); + } + return app('json')->success($this->repository->get($id, $uid)); + } + + /** + * @param validate $validate + * @return mixed + * @author Qinii + */ + public function create(validate $validate) + { + $data = $this->checkParams($validate); + if ($data['is_default']) { + $this->repository->changeDefault($this->request->uid()); + } else { + if (!$this->repository->defaultExists($this->request->uid())) $data['is_default'] = 1; + } + if ($data['address_id']) { + if (!$this->repository->fieldExists($data['address_id'], $this->request->uid())) + return app('json')->fail('信息不存在'); + $this->repository->update($data['address_id'], $data); + return app('json')->success('编辑成功'); + }; + $data['uid'] = $this->request->uid(); + $address = $this->repository->create($data); + return app('json')->success('添加成功', $address->toArray()); + } + + /** + * @param $id + * @param validate $validate + * @return mixed + * @author Qinii + */ + public function update($id, validate $validate) + { + if (!$this->repository->fieldExists($id, $this->request->uid())) + return app('json')->fail('信息不存在'); + $data = $this->checkParams($validate); + if ($data['is_default']) $this->repository->changeDefault($this->request->uid()); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function delete($id) + { + if (!$this->repository->fieldExists($id, $this->request->uid())) + return app('json')->fail('信息不存在'); + if ($this->repository->checkDefault($id)) + return app('json')->fail('默认地址不能删除'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function editDefault($id) + { + if (!$this->repository->fieldExists($id, $this->request->uid())) + return app('json')->fail('信息不存在'); + $this->repository->changeDefault($this->request->uid()); + $this->repository->update($id, ['is_default' => 1]); + return app('json')->success('修改成功'); + } + + /** + * @param validate $validate + * @return array + * @author Qinii + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['address_id', 'real_name', 'phone', 'area', 'detail', 'post_code', 'is_default']); + $validate->check($data); + [$province, $city, $district, $street] = ((array)$data['area']) + [null, null, null, null]; + $last = $street ?? $district ?? $city ?? $province; + if (!$last) { + throw new ValidateException('请选择正确的收货地址'); + } + $make = app()->make(CityAreaRepository::class); + if (!$make->existsWhere(['id' => $last['id'], 'snum' => 0])) { + throw new ValidateException('请手动选择所在地区'); + } + if ($make->search([])->where('id', 'in', array_column($data['area'], 'id'))->count() !== count($data['area'])) { + throw new ValidateException('请选择正确的收货地址'); + } + + $data['province'] = $province['name']; + $data['province_id'] = $province['id']; + $data['city'] = $city['name']; + $data['city_id'] = $city['id']; + $data['district'] = $district['name']; + $data['district_id'] = $district['id']; + if (isset($street)) { + $data['street'] = $street['name']; + $data['street_id'] = $street['id']; + } + unset($data['area']); + return $data; + } +} diff --git a/app/controller/api/user/UserExtract.php b/app/controller/api/user/UserExtract.php new file mode 100644 index 00000000..b889ed17 --- /dev/null +++ b/app/controller/api/user/UserExtract.php @@ -0,0 +1,77 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\user; + +use crmeb\basic\BaseController; +use app\common\repositories\system\groupData\GroupDataRepository; +use think\App; +use app\validate\api\UserExtractValidate as validate; +use app\common\repositories\user\UserExtractRepository as repository; + +class UserExtract extends BaseController +{ + /** + * @var repository + */ + public $repository; + + /** + * UserExtract constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['status']); + $where['uid'] = $this->request->uid(); + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + + public function create(validate $validate) + { + $data = $this->checkParams($validate); + $user = $this->request->userInfo(); + if($data['extract_type'] == 3 && !systemConfig('sys_extension_type') ) return app('json')->fail('未开启付款到零钱'); + $this->repository->create($user,$data); + return app('json')->success('申请已提交'); + } + + public function checkParams(validate $validate) + { + $data = $this->request->params(['extract_type','bank_code','bank_address','alipay_code','wechat','extract_pic','extract_price','real_name','bank_name']); + $validate->check($data); + return $data; + } + + public function bankLst() + { + [$page,$limit] = $this->getPage(); + $data = app()->make(GroupDataRepository::class)->groupData('bank_list',0,$page,100); + return app('json')->success($data); + } + + public function historyBank() + { + $data = $this->repository->getHistoryBank($this->request->userInfo()->uid); + return app('json')->success($data ?? []); + } + + +} diff --git a/app/controller/api/user/UserHistory.php b/app/controller/api/user/UserHistory.php new file mode 100644 index 00000000..78cd0acd --- /dev/null +++ b/app/controller/api/user/UserHistory.php @@ -0,0 +1,70 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserHistoryRepository as repository; +use think\App; + +class UserHistory extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * UserHistory constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $type = $this->request->param('type',1); + $uid = $this->request->uid(); + $data = $this->repository->getApiList($page,$limit,$uid,$type); + return app('json')->success($data); + } + + /** + * @return mixed + * @author Qinii + */ + public function deleteHistory($id) + { + if(!$this->repository->getSearch(['uid' => $this->request->uid(),'history_id' => $id])) + return app('json')->fail('信息不存在'); + $this->repository->delete($id); + return app('json')->success('浏览记录已删除'); + } + + /** + * @return mixed + * @author Qinii + */ + public function deleteHistoryBatch() + { + $params = $this->request->param('history_id'); + if(!$params) return app('json')->fail('参数不能为空'); + $this->repository->deleteBatch($this->request->uid(),$params); + return app('json')->success('浏览记录已删除'); + } +} diff --git a/app/controller/api/user/UserReceipt.php b/app/controller/api/user/UserReceipt.php new file mode 100644 index 00000000..03deb9c1 --- /dev/null +++ b/app/controller/api/user/UserReceipt.php @@ -0,0 +1,123 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\user; + +use app\common\repositories\store\order\StoreOrderReceiptRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\user\UserReceiptRepository; +use app\validate\api\UserReceiptValidate; + +class UserReceipt extends BaseController +{ + /** + * @var UserReceiptRepository + */ + protected $repository; + + /** + * UserReceipt constructor. + * @param App $app + * @param UserReceiptRepository $repository + */ + public function __construct(App $app, UserReceiptRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function create(UserReceiptValidate $validate) + { + $data = $this->checkParams($validate); + $data['uid'] = $this->request->uid(); + if($data['is_default'] == 1) $this->repository->clearDefault($this->request->uid()); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function lst() + { + $where = $this->request->params(['receipt_title_type','receipt_type','is_default']); + $where['uid'] = $this->request->uid(); + return app('json')->success($this->repository->getList($where)); + } + + public function order(StoreOrderReceiptRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where['status'] = $this->request->param('status'); + $where['uid'] = $this->request->uid(); + $where['order_type'] = 8; + + $data = $repository->getList($where, $page, $limit); + $data['list']->append(['storeOrder.orderProduct']); + return app('json')->success($data); + } + + public function orderDetail($id, StoreOrderReceiptRepository $repository) + { + $receipt = $repository->getWhere(['order_receipt_id' => $id, 'uid' => $this->request->uid()],'*',[ + 'storeOrder.orderProduct', + 'merchant' => function($query) { + $query->field('mer_id,service_phone')->append(['services_type']); + } + ]); + if (!$receipt) return app('json')->fail('发票信息不存在'); + return app('json')->success($receipt); + } + + public function isDefault($id) + { + $res = $this->repository->uidExists($id,$this->request->uid()); + if(!$res) return app('json')->fail('信息丢失'); + $this->repository->isDefault($id,$this->request->uid()); + return app('json')->success('修改成功'); + } + + public function update($id,UserReceiptValidate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->uidExists($id,$this->request->uid())) return app('json')->fail('信息丢失'); + if($data['is_default'] == 1) $this->repository->clearDefault($this->request->uid()); + $this->repository->update($id,$data); + return app('json')->success('编辑成功'); + } + + public function detail($id) + { + $where = [ + 'uid' => $this->request->uid(), + 'user_receipt_id' => $id + ]; + return app('json')->success($this->repository->detail($where)); + + } + + public function delete($id) + { + if(!$this->repository->uidExists($id,$this->request->uid())) + return app('json')->fail('信息丢失'); + $res = $this->repository->getIsDefault($this->request->uid()); + if($res && $res['user_receipt_id'] == $id) + return app('json')->fail('默认项不可删除'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function checkParams(UserReceiptValidate $validate) + { + $data = $this->request->params(['receipt_type','receipt_title','receipt_title_type','duty_paragraph','email','bank_name','bank_code','address','tel','is_default']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/api/user/UserRecharge.php b/app/controller/api/user/UserRecharge.php new file mode 100644 index 00000000..271f3b48 --- /dev/null +++ b/app/controller/api/user/UserRecharge.php @@ -0,0 +1,87 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\api\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\user\UserRechargeRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\services\WechatService; +use think\App; + +class UserRecharge extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserRechargeRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function brokerage(UserRepository $userRepository) + { + $brokerage = (float)$this->request->param('brokerage'); + if ($brokerage <= 0) + return app('json')->fail('请输入正确的充值金额!'); + $user = $this->request->userInfo(); + if ($user->brokerage_price < $brokerage) + return app('json')->fail('剩余可用佣金不足' . $brokerage); + $config = systemConfig(['recharge_switch', 'balance_func_status']); + if (!$config['recharge_switch'] || !$config['balance_func_status']) + return app('json')->fail('余额充值功能已关闭'); + $userRepository->switchBrokerage($user, $brokerage); + return app('json')->success('转换成功'); + } + + public function recharge(GroupDataRepository $groupDataRepository) + { + [$type, $price, $rechargeId, $return_url] = $this->request->params(['type', 'price', 'recharge_id', 'return_url'], true); + if (!in_array($type, ['weixin', 'routine', 'h5', 'alipay', 'alipayQr', 'weixinQr'])) + return app('json')->fail('请选择正确的支付方式!'); + if($price > 1000000){ + return app('json')->fail('充值金额超出最大限制'); + } + $app = $this->request->isApp(); + $user = $this->request->userInfo(); + $wechatUserId = $user['wechat_user_id']; + if (!$wechatUserId && in_array($type, [$this->repository::TYPE_ROUTINE, $this->repository::TYPE_WECHAT]) && !$app) + return app('json')->fail('请关联微信' . ($type == 'weixin' ? '公众号' : '小程序') . '!'); + $config = systemConfig(['store_user_min_recharge', 'recharge_switch', 'balance_func_status']); + if (!$config['recharge_switch'] || !$config['balance_func_status']) + return app('json')->fail('余额充值功能已关闭'); + if ($rechargeId) { + if (!intval($rechargeId)) + return app('json')->fail('请选择充值金额!'); + $rule = $groupDataRepository->merGet(intval($rechargeId), 0); + if (!$rule || !isset($rule['price']) || !isset($rule['give'])) + return app('json')->fail('您选择的充值方式已下架!'); + $give = floatval($rule['give']); + $price = floatval($rule['price']); + if ($price <= 0) + return app('json')->fail('请选择正确的充值金额!'); + } else { + $price = floatval($price); + if ($price <= 0) + return app('json')->fail('请输入正确的充值金额!'); + if ($price < $config['store_user_min_recharge']) + return app('json')->fail('最低充值' . floatval($config['store_user_min_recharge'])); + $give = 0; + } + $recharge = $this->repository->create($this->request->uid(), $price, $give, $type); + return app('json')->success($this->repository->pay($type, $user, $recharge, $return_url, $app)); + } +} diff --git a/app/controller/api/user/UserRelation.php b/app/controller/api/user/UserRelation.php new file mode 100644 index 00000000..62195f97 --- /dev/null +++ b/app/controller/api/user/UserRelation.php @@ -0,0 +1,123 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\api\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserRelationRepository as repository; +use think\App; + +class UserRelation extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * UserRelation constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + */ + public function create() + { + $params = $this->request->params(['type_id', 'type']); + $params['uid'] = $this->request->uid(); + if (!$params['type_id']) + return app('json')->fail('请选择'. ($params['type'] == 1 ? '商品' : '商户')); + if (!in_array($params['type'], [0,1,2,3,4,10])) + return app('json')->fail('参数错误'); + if (!$this->repository->fieldExists($params)) + return app('json')->fail('数据不存在'); + if ($this->repository->getUserRelation($params,$this->request->uid())) + return app('json')->fail('您已经关注过了'); + $this->repository->create($params); + return app('json')->success('关注成功'); + } + + /** + * @return mixed + * @author Qinii + */ + public function productList() + { + [$page, $limit] = $this->getPage(); + $where = ['uid'=>$this->request->uid(),'type'=>1]; + return app('json')->success($this->repository->search($where, $page,$limit)); + } + + /** + * @return mixed + * @author Qinii + */ + public function merchantList() + { + [$page, $limit] = $this->getPage(); + $where = ['uid'=>$this->request->uid(),'type'=>10]; + return app('json')->success($this->repository->search($where, $page,$limit)); + } + + /** + * TODO 收藏列表的删除 + * @return \think\response\Json + * @author Qinii + * @day 7/12/21 + */ + public function batchDelete() + { + $ids = $this->request->param('type_id'); + $type = $this->request->param('type',1); + if(empty($ids)) return app('json')->fail('请选择'. ($type == 1 ? '商品' : '商户')); + $this->repository->batchDestory($ids,$this->request->uid(),$type); + return app('json')->success('已取消关注'); + } + + /** + * TODO 商品详情中的取消收藏 + * @return \think\response\Json + * @author Qinii + * @day 7/12/21 + */ + public function delete() + { + $params = $this->request->params(['type_id','type']); + if (!$this->repository->getUserRelation($params,$this->request->uid())) + return app('json')->fail('信息不存在'); + $rest = $this->repository->batchDestory([$params['type_id']],$this->request->uid(),$params['type']); + return app('json')->success('已取消关注'); + } + + /** + * @return mixed + * @author Qinii + */ + public function batchCreate() + { + $params = $this->request->params(['type_id','type']); + if(!count($params['type_id']) || !in_array($params['type'], [1,10])) + return app('json')->fail('请选择商品'); + $this->repository->batchCreate($this->request->uid(),$params); + return app('json')->success('收藏成功'); + } + +} diff --git a/app/controller/api/user/UserSign.php b/app/controller/api/user/UserSign.php new file mode 100644 index 00000000..f0295255 --- /dev/null +++ b/app/controller/api/user/UserSign.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\api\user; + + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserSignRepository; +use think\App; + +class UserSign extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * UserSign constructor. + * @param App $app + * @param UserSignRepository $repository + */ + public function __construct(App $app, UserSignRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page,$limit] = $this->getPage(); + $where = ['uid' => $this->request->uid()]; + $data = $this->repository->getList($where,$page,$limit); + return app('json')->success($data); + } + + public function create() + { + $uid = $this->request->uid(); + $day = date('Y-m-d',time()); + if($this->repository->getSign($uid,$day)) + return app('json')->fail('您今日已签到'); + $data = $this->repository->create($uid); + return app('json')->success($data); + } + + public function info() + { + $uid = $this->request->uid(); + $data = $this->repository->info($uid); + return app('json')->success($data); + } + + public function month() + { + $where = ['uid' => $this->request->uid()]; + return app('json')->success($this->repository->month($where)); + } +} diff --git a/app/controller/merchant/Common.php b/app/controller/merchant/Common.php new file mode 100644 index 00000000..e0fe41dc --- /dev/null +++ b/app/controller/merchant/Common.php @@ -0,0 +1,282 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant; + + +use app\common\repositories\user\UserRepository; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreOrderProductRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\user\UserRelationRepository; +use app\common\repositories\user\UserVisitRepository; +use crmeb\services\ImageWaterMarkService; +use crmeb\services\UploadService; +use Joypack\Tencent\Map\Bundle\Address; +use Joypack\Tencent\Map\Bundle\AddressOption; +use think\App; +use think\facade\Cache; +use think\facade\Db; + +/** + * Class Common + * @package app\controller\merchant + * @author xaboy + * @day 2020/6/25 + */ +class Common extends BaseController +{ + /** + * @var int|null + */ + protected $merId; + + /** + * Common constructor. + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + $this->merId = $this->request->merId() ?: null; + } + + /** + * @param null $merId + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function main($merId = null) + { + $today = $this->mainGroup('today', $merId ?? $this->merId); + $yesterday = $this->mainGroup('yesterday', $merId ?? $this->merId); + $lastWeek = $this->mainGroup(date('Y-m-d', strtotime('- 7day')), $merId ?? $this->merId); + $lastWeekRate = []; + foreach ($lastWeek as $k => $item) { + if ($item == $today[$k]) + $lastWeekRate[$k] = 0; + else if ($item == 0) + $lastWeekRate[$k] = $today[$k]; + else if ($today[$k] == 0) + $lastWeekRate[$k] = -$item; + else + $lastWeekRate[$k] = (float)bcdiv(bcsub($today[$k], $item, 4), $item, 4); + } + $day = date('Y-m-d'); + return $merId ? compact('today', 'yesterday', 'lastWeekRate', 'day') : app('json')->success(compact('today', 'yesterday', 'lastWeekRate', 'day')); + } + + /** + * @param $date + * @param $merId + * @return array + * @author xaboy + * @day 2020/6/25 + */ + public function mainGroup($date, $merId) + { + $userVisitRepository = app()->make(UserVisitRepository::class); + $repository = app()->make(StoreOrderRepository::class); + $relationRepository = app()->make(UserRelationRepository::class); + $orderNum = (float)$repository->dayOrderNum($date, $merId); + $payPrice = (float)$repository->dayOrderPrice($date, $merId); + $payUser = (float)$repository->dayOrderUserNum($date, $merId); + $visitNum = (float)$userVisitRepository->dateVisitUserNum($date, $merId); + $likeStore = (float)$relationRepository->dayLikeStore($date, $merId); + return compact('orderNum', 'payPrice', 'payUser', 'visitNum', 'likeStore'); + } + + /** + * @param StoreOrderRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function order(StoreOrderRepository $repository) + { + $date = $this->request->param('date') ?: 'lately7'; + $res = Cache::remember(self::class . '@order' . $this->merId . $date, function () use ($repository, $date) { + if ($date == 'year') { + $m = date('m',time()); + $time[] = $m; + do{ + $time[] = '0'. ($m - 1); + $m--; + }while($m > 1); + $time = array_reverse($time); + } else { + $time = getDatesBetweenTwoDays(getStartModelTime($date), date('Y-m-d')); + } + $list = $repository->orderGroupNum($date, $this->merId)->toArray(); + $list = array_combine(array_column($list, 'day'), $list); + $data = []; + foreach ($time as $item) { + $data[] = [ + 'day' => $item, + 'total' => $list[$item]['total'] ?? 0, + 'user' => $list[$item]['user'] ?? 0, + 'pay_price' => $list[$item]['pay_price'] ?? 0 + ]; + } + return $data; + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + /** + * @param UserRelationRepository $repository + * @param StoreOrderRepository $orderRepository + * @param UserVisitRepository $userVisitRepository + * @return \think\response\Json + * @author xaboy + * @day 2020/9/24 + */ + public function user(StoreOrderRepository $orderRepository, UserVisitRepository $userVisitRepository) + { + $date = $this->request->param('date', 'today') ?: 'today'; + $res = Cache::store('file')->remember(self::class . '@user' . $this->merId . $date, function () use ($orderRepository, $userVisitRepository, $date) { + $visitUser = $userVisitRepository->dateVisitUserNum($date, $this->merId); + $orderUser = $orderRepository->orderUserNum($date, null, $this->merId); + $orderPrice = $orderRepository->orderPrice($date, null, $this->merId); + $payOrderUser = $orderRepository->orderUserNum($date, 1, $this->merId); + $payOrderPrice = $orderRepository->orderPrice($date, 1, $this->merId); + $userRate = $payOrderUser ? bcdiv($payOrderPrice, $payOrderUser, 2) : 0; + $orderRate = $visitUser ? bcdiv($orderUser, $visitUser, 2) : 0; + $payOrderRate = $orderUser ? bcdiv($payOrderUser, $orderUser, 2) : 0; + + return compact('visitUser', 'orderUser', 'orderPrice', 'payOrderUser', 'payOrderPrice', 'payOrderRate', 'userRate', 'orderRate'); + }, 2000 + random_int(600, 1200)); + + return app('json')->success($res); + } + + /** + * @param StoreOrderRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function userRate(StoreOrderRepository $repository, UserRepository $userRepository) + { + $date = $this->request->param('date') ?: 'today'; + + $res = Cache::store('file')->remember(self::class . '@userRate' . $this->merId . $date, function () use ($userRepository, $repository, $date) { + $uids = $repository->orderUserGroup($date, 1, $this->merId)->toArray(); + $userPayCount = $userRepository->idsByPayCount(array_column($uids, 'uid')); + $user = count($uids); + $oldUser = 0; + $totalPrice = 0; + $oldTotalPrice = 0; + foreach ($uids as $uid) { + $totalPrice = bcadd($uid['pay_price'], $totalPrice, 2); + if (($userPayCount[$uid['uid']] ?? 0) > $uid['total']) { + $oldUser++; + $oldTotalPrice = bcadd($uid['pay_price'], $oldTotalPrice, 2); + } + } + $newTotalPrice = bcsub($totalPrice, $oldTotalPrice, 2); + $newUser = $user - $oldUser; + return compact('newTotalPrice', 'newUser', 'oldTotalPrice', 'oldUser', 'totalPrice', 'user'); + }, 2000 + random_int(600, 1200)); + + return app('json')->success($res); + } + + /** + * @param StoreOrderProductRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function product(StoreOrderProductRepository $repository) + { + $date = $this->request->param('date', 'today') ?: 'today'; + + $res = Cache::store('file')->remember(self::class . '@product' . $this->merId . $date, function () use ($repository, $date) { + return $repository->orderProductGroup($date, $this->merId)->toArray(); + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + public function productVisit(UserVisitRepository $repository) + { + $date = $this->request->param('date', 'today') ?: 'today'; + + $res = Cache::store('file')->remember(self::class . '@productVisit' . $this->merId . $date, function () use ($repository, $date) { + return $repository->dateVisitProductNum($date, $this->merId); + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + /** + * @param ProductRepository $repository + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function productCart(ProductRepository $repository) + { + $date = $this->request->param('date', 'today') ?: 'today'; + + $res = Cache::store('file')->remember(self::class . '@productCart' . $this->merId . $date, function () use ($repository, $date) { + return $repository->cartProductGroup($date, $this->merId); + }, 2000 + random_int(600, 1200)); + return app('json')->success($res); + } + + public function uploadCertificate() + { + $file = $this->request->file('file'); + if (!$file) + return app('json')->fail('请上传证书'); + validate(["file|图片" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'jpg,jpeg,png,bmp', + 'fileMime' => 'image/jpeg,image/png', + ]])->check(['file' => $file]); + $upload = UploadService::create(1); + $data = $upload->to('attach')->move('file'); + if ($data === false) { + return app('json')->fail($upload->getError()); + } + app()->make(ImageWaterMarkService::class)->run(public_path() . $upload->getFileInfo()->filePath); + return app('json')->success(['src' => tidy_url($upload->getFileInfo()->filePath)]); + } + + public function uploadVideo() + { + $file = $this->request->file('file'); + if (!$file) + return app('json')->fail('请上传视频'); + validate(["file|视频" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'mp4,mov', + 'fileMime' => 'video/mp4,video/quicktime', + ]])->check(['file' => $file]); + $upload = UploadService::create(); + $data = $upload->to('media')->validate([])->move('file'); + if ($data === false) { + return app('json')->fail($upload->getError()); + } + return app('json')->success(['src' => tidy_url($upload->getFileInfo()->filePath)]); + } + + public function config() + { + $data = systemConfig(['tx_map_key','delivery_status','delivery_type']); + $data['mer_id'] = $this->request->merId(); + return app('json')->success($data); + } +} diff --git a/app/controller/merchant/store/Excel.php b/app/controller/merchant/store/Excel.php new file mode 100644 index 00000000..e808a511 --- /dev/null +++ b/app/controller/merchant/store/Excel.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store; + +use app\common\repositories\store\ExcelRepository; +use crmeb\exceptions\UploadException; +use crmeb\services\ExcelService; +use think\App; +use crmeb\basic\BaseController; + +class Excel extends BaseController +{ + + protected $repository; + + public function __construct(App $app, ExcelRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-08-15 + */ + public function lst() + { + $admin = $this->request->adminInfo(); + if($admin['level']) $where['admin_id'] = $this->request->adminId(); + [$page, $limit] = $this->getPage(); + $where['type'] = $this->request->param('type',''); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getList($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO 下载文件 + * @param $id + * @return \think\response\File + * @author Qinii + * @day 2020-07-30 + */ + public function downloadExpress() + { + try{ + $file['name'] = 'express'; + $path = app()->getRootPath().'extend/express.xlsx'; + if(!$file || !file_exists($path)) return app('json')->fail('文件不存在'); + return download($path,$file['name']); + }catch (UploadException $e){ + return app('json')->fail('下载失败'); + } + } + + /** + * TODO 所有类型 + * @return \think\response\Json + * @author Qinii + * @day 7/2/21 + */ + public function type() + { + $data = $this->repository->getTypeData(); + return app('json')->success($data); + } + +} diff --git a/app/controller/merchant/store/StoreAttrTemplate.php b/app/controller/merchant/store/StoreAttrTemplate.php new file mode 100644 index 00000000..923bb4d4 --- /dev/null +++ b/app/controller/merchant/store/StoreAttrTemplate.php @@ -0,0 +1,134 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store; + + +use crmeb\basic\BaseController; +use app\common\repositories\store\StoreAttrTemplateRepository; +use app\validate\merchant\StoreAttrTemplateValidate; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class StoreAttrTemplate + * @package app\controller\merchant\store + * @author xaboy + * @day 2020-05-06 + */ +class StoreAttrTemplate extends BaseController +{ + /** + * @var StoreAttrTemplateRepository + */ + protected $repository; + + /** + * StoreAttrTemplate constructor. + * @param App $app + * @param StoreAttrTemplateRepository $repository + */ + public function __construct(App $app, StoreAttrTemplateRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $data = $this->repository->getList($this->request->merId(), [], $page, $limit); + + return app('json')->success($data); + } + + public function getlist() + { + return app('json')->success($this->repository->list($this->request->merId())); + } + /** + * @param StoreAttrTemplateValidate $validate + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function create(StoreAttrTemplateValidate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + /** + * @param $id + * @param StoreAttrTemplateValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function update($id, StoreAttrTemplateValidate $validate) + { + $merId = $this->request->merId(); + + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $data = $this->checkParams($validate); + $data['mer_id'] = $merId; + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-06 + */ + public function delete($id) + { + $merId = $this->request->merId(); + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id, $merId); + + return app('json')->success('删除成功'); + } + + /** + * @param StoreAttrTemplateValidate $validate + * @return array + * @author xaboy + * @day 2020-05-06 + */ + public function checkParams(StoreAttrTemplateValidate $validate) + { + $data = $this->request->params(['template_name', ['template_value', []]]); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/merchant/store/StoreImport.php b/app/controller/merchant/store/StoreImport.php new file mode 100644 index 00000000..509331b4 --- /dev/null +++ b/app/controller/merchant/store/StoreImport.php @@ -0,0 +1,141 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\order\StoreImportDeliveryRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\jobs\ImportSpreadsheetExcelJob; +use crmeb\services\ExcelService; +use crmeb\services\SpreadsheetExcelService; +use crmeb\services\UploadService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreImportRepository; + +use think\facade\Queue; + +class StoreImport extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param StoreImportRepository $repository + */ + public function __construct(App $app, StoreImportRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status','date',['import_type','delivery'],'type']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getList($where,$page,$limit); + return app('json')->success($data); + } + + public function detail($id) + { + $where = [ + 'import_id' => $id, + 'mer_id' => $this->request->merId() + ]; + [$page, $limit] = $this->getPage(); + $data = app()->make(StoreImportDeliveryRepository::class)->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function export($id) + { + $where = [ + 'import_id' => $id, + 'mer_id' => $this->request->merId() + ]; + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->importDelivery($where, $page, $limit); + return app('json')->success($data); + } + + /** + * TODO 导入excel信息 + * @return \think\response\Json + * @author Qinii + * @day 3/16/21 + */ + public function Import($type) + { + $file = $this->request->file('file'); + if (!$file) return app('json')->fail('请上传EXCEL文件'); + $file = is_array($file) ? $file[0] : $file; + validate(["file|文件" => ['fileExt' => 'xlsx,xls',]])->check(['file' => $file]); + $upload = UploadService::create(1); + $ret = $upload->to('excel')->move('file'); + if ($ret === false) return app('json')->fail($upload->getError()); + $res = $upload->getUploadInfo(); + $path = rtrim(public_path(),'/').$res['dir']; + $data = []; + switch ($type){ + case 'product': + $check =[ + 'A1'=>'商品名称', + 'B1'=>'商品简介', + 'C1'=>'关键字', + 'D1'=>'商品条码', + 'E1'=>'分类', + 'F1'=>'单位名', + 'G1'=>'出售价', + 'H1'=>'总库存', + 'I1'=>'规格', + ]; + SpreadsheetExcelService::instance()->checkImport($path,$check); + $data = [ + 'mer_id' => $this->request->merId(), + 'data' => [ + 'path' => $path, + 'sql' => ['store_name' => 'A', 'store_info' => 'B', 'keyword' => 'C', 'bar_code' => 'D', 'cate_id' => 'E', 'unit_name' => 'F', 'price' => 'G', 'stock' => 'H', 'specifications' => 'I'], + 'where' => ['bar_code' => 'D'], + ] + ]; + app()->make(StoreOrderRepository::class)->setProduct($data['data'],$data['mer_id']); + return app('json')->success('开始导入数据,请稍后在列表中查看!'); + break; + case 'delivery' : + SpreadsheetExcelService::instance()->checkImport($path,['E3' => '物流单号']); + $data = [ + 'mer_id' => $this->request->merId(), + 'data' => [ + 'path' => $path, + 'sql' => ['delivery_name' => 'D', 'delivery_id' => 'E',], + 'where' => ['order_sn' => 'B',], + ] + ]; + break; + default: + $data = SpreadsheetExcelService::instance()->_import($path,[],[],0); + break; + } + if(!empty($data)){ + $res = $this->repository->create($this->request->merId(),'delivery'); + $data['data']['import_id'] = $res->import_id; + app()->make(StoreOrderRepository::class)->setWhereDeliveryStatus($data['data'],$data['mer_id']); + Queue::push(ImportSpreadsheetExcelJob::class,$data); + return app('json')->success('开始导入数据,请稍后在批量发货记录中查看!'); + } + return app('json')->fail('数据类型错误'); + } +} + diff --git a/app/controller/merchant/store/StoreImport.php.bak b/app/controller/merchant/store/StoreImport.php.bak new file mode 100644 index 00000000..225ee328 --- /dev/null +++ b/app/controller/merchant/store/StoreImport.php.bak @@ -0,0 +1,120 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\order\StoreImportDeliveryRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\jobs\ImportSpreadsheetExcelJob; +use crmeb\services\ExcelService; +use crmeb\services\SpreadsheetExcelService; +use crmeb\services\UploadService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreImportRepository; + +use think\facade\Queue; + +class StoreImport extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param StoreImportRepository $repository + */ + public function __construct(App $app, StoreImportRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status','date',['import_type','delivery'],'type']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getList($where,$page,$limit); + return app('json')->success($data); + } + + public function detail($id) + { + $where = [ + 'import_id' => $id, + 'mer_id' => $this->request->merId() + ]; + [$page, $limit] = $this->getPage(); + $data = app()->make(StoreImportDeliveryRepository::class)->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function export($id) + { + $where = [ + 'import_id' => $id, + 'mer_id' => $this->request->merId() + ]; + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->importDelivery($where, $page, $limit); + return app('json')->success($data); + } + + /** + * TODO 导入excel信息 + * @return \think\response\Json + * @author Qinii + * @day 3/16/21 + */ + public function Import($type) + { + $file = $this->request->file('file'); + if (!$file) return app('json')->fail('请上传EXCEL文件'); + $file = is_array($file) ? $file[0] : $file; + validate(["file|文件" => ['fileExt' => 'xlsx,xls',]])->check(['file' => $file]); + + $upload = UploadService::create(1); + $ret = $upload->to('excel')->move('file'); + if ($ret === false) return app('json')->fail($upload->getError()); + $res = $upload->getUploadInfo(); + $path = rtrim(public_path(),'/').$res['dir']; + $data = []; + switch ($type){ + case 'delivery' : + SpreadsheetExcelService::instance()->checkImport($path,['E3' => '物流单号']); + $data = [ + 'mer_id' => $this->request->merId(), + 'data' => [ + 'path' => $path, + 'sql' => ['delivery_name' => 'D', 'delivery_id' => 'E',], + 'where' => ['order_sn' => 'B',], + ] + ]; + break; + default: + $data = SpreadsheetExcelService::instance()->_import($path,[],[],0); + break; + } + if(!empty($data)){ + $res = $this->repository->create($this->request->merId(),'delivery'); + $data['data']['import_id'] = $res->import_id; + +// app()->make(StoreOrderRepository::class)->setWhereDeliveryStatus($data['data'],$data['mer_id']); + + Queue::push(ImportSpreadsheetExcelJob::class,$data); + return app('json')->success('开始导入数据,请稍后在批量发货记录中查看!'); + } + return app('json')->fail('数据类型错误'); + } +} + diff --git a/app/controller/merchant/store/StorePrinter.php b/app/controller/merchant/store/StorePrinter.php new file mode 100644 index 00000000..edaaefd7 --- /dev/null +++ b/app/controller/merchant/store/StorePrinter.php @@ -0,0 +1,122 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\StorePrinterRepository; +use crmeb\exceptions\UploadException; +use crmeb\services\ExcelService; +use think\App; +use crmeb\basic\BaseController; + +class StorePrinter extends BaseController +{ + + protected $repository; + + public function __construct(App $app, StorePrinterRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-08-15 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status','keyword']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->merList($where,$page,$limit); + return app('json')->success($data); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null))); + } + + public function create() + { + $params = $this->request->params([ + 'printer_name', + 'printer_appkey', + 'printer_appid', + 'printer_secret', + 'printer_terminal', + 'status', + ]); + + if (!$params['printer_name'] || + !$params['printer_appkey'] || + !$params['printer_appid'] || + !$params['printer_secret'] || + !$params['printer_terminal'] + ) { + return app('json')->fail('信息不完整'); + } + $params['mer_id'] = $this->request->merId(); + $this->repository->create($params); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->form($id))); + } + + public function update($id) + { + $params = $this->request->params([ + 'printer_name', + 'printer_appkey', + 'printer_appid', + 'printer_secret', + 'printer_terminal', + 'status', + ]); + + if (!$params['printer_name'] || + !$params['printer_appkey'] || + !$params['printer_appid'] || + !$params['printer_secret'] || + !$params['printer_terminal'] + ) { + return app('json')->fail('信息不完整'); + } + $res = $this->repository->getWhere(['printer_id' => $id, 'mer_id' => $this->request->merId()]); + if (!$res) return app('json')->fail('打印机信息不存在'); + $this->repository->update($id, $params); + return app('json')->success('添加成功'); + } + + public function delete($id) + { + $res = $this->repository->getWhere(['printer_id' => $id, 'mer_id' => $this->request->merId()]); + if (!$res) return app('json')->fail('打印机信息不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function switchWithStatus($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/merchant/store/StoreProductReply.php b/app/controller/merchant/store/StoreProductReply.php new file mode 100644 index 00000000..438cae95 --- /dev/null +++ b/app/controller/merchant/store/StoreProductReply.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store; + + +use app\common\repositories\store\product\ProductReplyRepository; +use crmeb\basic\BaseController; +use think\App; + +class StoreProductReply extends BaseController +{ + protected $repository; + + public function __construct(App $app, ProductReplyRepository $replyRepository) + { + parent::__construct($app); + $this->repository = $replyRepository; + } + + public function changeSort($id) + { + $merId = $this->request->merId(); + if (!$this->repository->merExists($merId, $id)) + return app('json')->fail('数据不存在'); + + $sort = (int)$this->request->param('sort'); + + $this->repository->update($id, compact('sort')); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/merchant/store/broadcast/BroadcastAssistant.php b/app/controller/merchant/store/broadcast/BroadcastAssistant.php new file mode 100644 index 00000000..9c993f4d --- /dev/null +++ b/app/controller/merchant/store/broadcast/BroadcastAssistant.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store\broadcast; + + +use app\common\repositories\store\broadcast\BroadcastAssistantRepository; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class BroadcastAssistant extends BaseController +{ + protected $repository; + + public function __construct(App $app, BroadcastAssistantRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['username', 'nickname']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null))); + } + + public function updateForm($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->form(intval($id)))); + } + + public function create() + { + $data = $this->checkParams(); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function update($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $this->checkParams()); + return app('json')->success('修改成功'); + } + + public function checkParams() + { + $data = $this->request->params(['username', 'nickname', 'mark']); + if (!$data['username'] || !$data['nickname']) { + throw new ValidateException('微信号或昵称不可为空'); + } + return $data; + } + + public function delete($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->delete((int)$id); + return app('json')->success('删除成功'); + } +} diff --git a/app/controller/merchant/store/broadcast/BroadcastGoods.php b/app/controller/merchant/store/broadcast/BroadcastGoods.php new file mode 100644 index 00000000..056ca557 --- /dev/null +++ b/app/controller/merchant/store/broadcast/BroadcastGoods.php @@ -0,0 +1,118 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store\broadcast; + + +use app\common\repositories\store\broadcast\BroadcastGoodsRepository; +use app\validate\merchant\BroadcastGoodsValidate; +use crmeb\basic\BaseController; +use think\App; + +class BroadcastGoods extends BaseController +{ + protected $repository; + + public function __construct(App $app, BroadcastGoodsRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status_tag', 'keyword', 'mer_valid','broadcast_goods_id']); + return app('json')->success($this->repository->getList($this->request->merId(), $where, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)->append(['product'])->toArray()); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->createForm())); + } + + protected function checkParams(BroadcastGoodsValidate $validate) + { + $data = $this->request->params(['name', 'cover_img', 'product_id', 'price']); + $validate->check($data); + $data['product_id'] = $data['product_id']['id']; + return $data; + } + + public function create(BroadcastGoodsValidate $validate) + { + $this->repository->create($this->request->merId(), $this->checkParams($validate)); + return app('json')->success('创建成功'); + } + + public function batchCreate(BroadcastGoodsValidate $validate) + { + $goods = $this->request->param('goods', []); + if (!count($goods)) return app('json')->fail('请选中商品'); + $validate->isBatch(); + foreach ($goods as $item) { + $validate->check((array)$item); + } + $this->repository->batchCreate($this->request->merId(), $goods); + return app('json')->success('创建成功'); + } + + public function updateForm($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + public function update($id, BroadcastGoodsValidate $validate) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $this->checkParams($validate)); + return app('json')->success('编辑成功'); + } + + public function mark($id) + { + $mark = (string)$this->request->param('mark'); + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->mark($id, $mark); + return app('json')->success('修改成功'); + } + + public function changeStatus($id) + { + $isShow = $this->request->param('is_show') == 1 ? 1 : 0; + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->isShow($id, $isShow); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->delete((int)$id); + return app('json')->success('删除成功'); + } + +} diff --git a/app/controller/merchant/store/broadcast/BroadcastRoom.php b/app/controller/merchant/store/broadcast/BroadcastRoom.php new file mode 100644 index 00000000..ec06df76 --- /dev/null +++ b/app/controller/merchant/store/broadcast/BroadcastRoom.php @@ -0,0 +1,196 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store\broadcast; + + +use app\common\repositories\store\broadcast\BroadcastAssistantRepository; +use app\common\repositories\store\broadcast\BroadcastRoomGoodsRepository; +use app\common\repositories\store\broadcast\BroadcastRoomRepository; +use app\validate\merchant\BroadcastRoomValidate; +use crmeb\basic\BaseController; +use think\App; + +class BroadcastRoom extends BaseController +{ + protected $repository; + + public function __construct(App $app, BroadcastRoomRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'status_tag', 'show_tag', 'show_type','live_status','broadcast_room_id']); + return app('json')->success($this->repository->getList($this->request->merId(), $where, $page, $limit)); + } + + /** + * @param BroadcastRoomGoodsRepository $repository + * @param $id + * @return \think\response\Json + * @author xaboy + * @day 2020/8/31 + */ + public function goodsList(BroadcastRoomGoodsRepository $repository, $id) + { + [$page, $limit] = $this->getPage(); + if (!$this->repository->merExists((int)$id, $this->request->merId())) + return app('json')->fail('直播间不存在'); + return app('json')->success($repository->getGoodsList($id, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->get($id)->toArray()); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->createForm())); + } + + public function updateForm($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + if (!$this->repository->existsWhere(['broadcast_room_id' => $id, 'status' => [-1, 0]])) + return app('json')->fail('当前直播间不能修改'); + return app('json')->success(formToData($this->repository->updateForm(intval($id)))); + } + + public function create() + { + $this->repository->create($this->request->merId(), $this->checkParams()); + return app('json')->success('创建成功'); + } + + public function update($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + if (!$this->repository->existsWhere(['broadcast_room_id' => $id, 'status' => [-1, 0]])) + return app('json')->fail('当前直播间不能修改'); + $this->repository->updateRoom($this->request->merId(), $id, $this->checkParams()); + return app('json')->success('修改成功'); + } + + public function checkParams() + { + $validate = app()->make(BroadcastRoomValidate::class); + $data = $this->request->params(['name', 'cover_img', 'share_img', 'anchor_name', 'anchor_wechat', 'phone', 'start_time', 'type', 'screen_type', 'close_like', 'close_goods', 'close_comment', 'replay_status', 'close_share', 'close_kf','feeds_img','is_feeds_public']); + $validate->check($data); + [$data['start_time'], $data['end_time']] = $data['start_time']; + return $data; + } + + public function changeStatus($id) + { + $isShow = $this->request->param('is_show') == 1 ? 1 : 0; + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->isShow($id, $isShow); + return app('json')->success('修改成功'); + } + + public function mark($id) + { + $mark = (string)$this->request->param('mark'); + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->mark($id, $mark); + return app('json')->success('修改成功'); + } + + public function exportGoods() + { + [$ids, $roomId] = $this->request->params(['ids', 'room_id'], true); + if (!count($ids)) return app('json')->fail('请选择直播商品'); + $this->repository->exportGoods($this->request->merId(), (array)$ids, $roomId); + return app('json')->success('导入成功'); + } + + public function rmExportGoods() + { + [$id, $roomId] = $this->request->params(['id', 'room_id'], true); + $this->repository->rmExportGoods($this->request->merId(), intval($roomId), intval($id)); + return app('json')->success('删除成功'); + } + + public function delete($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->merDelete((int)$id); + return app('json')->success('删除成功'); + } + + public function addAssistantForm($id) + { + return app('json')->success(formToData($this->repository->assistantForm($id, $this->request->merId()))); + } + + public function addAssistant($id) + { + $data = $this->request->param('assistant_id'); + $make = app()->make(BroadcastAssistantRepository::class); + foreach ($data as $datum) { + $has = $make->exists($datum); + if (!$has) return app('json')->fail('助手信息不存在,ID:'.$datum); + } + $this->repository->editAssistant($id, $this->request->merId(), $data); + return app('json')->success('修改成功'); + } + + public function pushMessage($id) + { + if (!$this->repository->merExists($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $this->repository->pushMessage($id); + return app('json')->success('消息已发送'); + } + + public function closeKf($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->closeInfo($id,'close_kf', $status); + return app('json')->success('修改成功'); + } + + public function banComment($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->closeInfo($id,'close_comment', $status); + return app('json')->success('修改成功'); + } + + public function isFeedsPublic($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->closeInfo($id,'is_feeds_public', $status); + return app('json')->success('修改成功'); + } + + public function onSale($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $data['goods_id'] =$this->request->param('goods_id'); + $this->repository->closeInfo($id,'on_sale', $status,false,$data); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/coupon/Coupon.php b/app/controller/merchant/store/coupon/Coupon.php new file mode 100644 index 00000000..fa1c96af --- /dev/null +++ b/app/controller/merchant/store/coupon/Coupon.php @@ -0,0 +1,239 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store\coupon; + + +use app\common\repositories\store\coupon\StoreCouponSendRepository; +use app\validate\merchant\StoreCouponSendValidate; +use crmeb\basic\BaseController; +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\user\UserRepository; +use app\validate\merchant\StoreCouponValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; + +/** + * Class CouponIssue + * @package app\controller\merchant\store\coupon + * @author xaboy + * @day 2020-05-13 + */ +class Coupon extends BaseController +{ + /** + * @var StoreCouponRepository + */ + protected $repository; + + /** + * CouponIssue constructor. + * @param App $app + * @param StoreCouponRepository $repository + */ + public function __construct(App $app, StoreCouponRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws DbException + * @throws DataNotFoundException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-14 + */ + public function lst() + { + $where = $this->request->params(['is_full_give', 'status', 'is_give_subscribe', 'coupon_name', 'send_type', 'type']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($this->request->merId(), $where, $page, $limit)); + } + + public function detail($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $coupon = $this->repository->get($id)->append(['used_num', 'send_num']); + return app('json')->success($coupon->toArray()); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-13 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form())); + } + + /** + * @param StoreCouponValidate $validate + * @return mixed + * @author xaboy + * @day 2020/5/30 + */ + public function create(StoreCouponValidate $validate) + { + $merId = $this->request->merId(); + $data = $this->checkParams($validate); + $data['mer_id'] = $merId; + $this->repository->create($data); + return app('json')->success('发布成功'); + } + + /** + * @param StoreCouponValidate $validate + * @return array + * @author xaboy + * @day 2020/5/20 + */ + public function checkParams(StoreCouponValidate $validate) + { + $data = $this->request->params(['use_type', 'title', 'coupon_price', 'use_min_price', 'coupon_type', 'coupon_time', ['use_start_time', []], 'sort', ['status', 0], 'type', ['product_id', []], ['range_date', ''], ['send_type', 0], ['full_reduction', 0], ['is_limited', 0], ['is_timeout', 0], ['total_count', ''], ['status', 0]]); + $validate->check($data); + if ($data['is_timeout']) { + [$data['start_time'], $data['end_time']] = $data['range_date']; + if (strtotime($data['end_time']) <= time()) + throw new ValidateException('优惠券领取结束时间不能小于当前'); + } + if (!$data['use_type']) $data['use_min_price'] = 0; + unset($data['use_type']); + if ($data['coupon_type']) { + if (count(array_filter($data['use_start_time'])) != 2) + throw new ValidateException('请选择有效期限'); + [$data['use_start_time'], $data['use_end_time']] = $data['use_start_time']; + } else unset($data['use_start_time']); + unset($data['range_date']); + if ($data['is_limited'] == 0) $data['total_count'] = 0; + if (!in_array($data['type'], [0, 1])) { + throw new ValidateException('请选择有效的优惠券类型'); + } + return $data; + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-13 + */ + public function changeStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, compact('status')); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/26 + */ + public function cloneForm($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->cloneCouponForm($id))); + } + + + + /** + * @param StoreCouponUserRepository $repository + * @author xaboy + * @day 2020/6/2 + */ + public function issue(StoreCouponUserRepository $repository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['username', 'coupon', 'status', 'coupon_id', 'type', 'send_id']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($repository->getList($where, $page, $limit)); + } + + + /** + * @return mixed + * @author Qinii + */ + public function select() + { + $where = $this->request->params(['coupon_name']); + $where['status'] = 1; + $where['send_type'] = 3; + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($this->request->merId(), $where, $page, $limit)); + } + + + + public function send(StoreCouponSendValidate $validate, StoreCouponSendRepository $repository) + { + $data = $this->request->params(['coupon_id', 'mark', 'is_all', 'search', 'uid']); + $validate->check($data); + if (!$data['is_all'] && !count($data['uid'])) { + return app('json')->fail('请选择发送用户'); + } + $repository->create($data, $this->request->merId()); + return app('json')->success('创建成功,正在发送中'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/7/7 + */ + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm($this->request->merId(), $id))); + } + + public function update($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['title']); + $this->repository->update($id, $data); + + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/merchant/store/coupon/CouponSend.php b/app/controller/merchant/store/coupon/CouponSend.php new file mode 100644 index 00000000..22d2dc8d --- /dev/null +++ b/app/controller/merchant/store/coupon/CouponSend.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store\coupon; + + +use app\common\repositories\store\coupon\StoreCouponSendRepository; +use crmeb\basic\BaseController; +use think\App; + +class CouponSend extends BaseController +{ + protected $repository; + + public function __construct(App $app, StoreCouponSendRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date', 'coupon_type', 'coupon_name', 'status']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } +} diff --git a/app/controller/merchant/store/delivery/DeliveryOrder.php b/app/controller/merchant/store/delivery/DeliveryOrder.php new file mode 100644 index 00000000..63bc6946 --- /dev/null +++ b/app/controller/merchant/store/delivery/DeliveryOrder.php @@ -0,0 +1,75 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\delivery; + +use app\common\repositories\delivery\DeliveryOrderRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use think\App; +use crmeb\basic\BaseController; +use think\exception\ValidateException; + +class DeliveryOrder extends BaseController +{ + protected $repository; + + public function __construct(App $app, DeliveryOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','station_id','status','date','order_sn','station_type']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->merList($where, $page, $limit); + return app('json')->success($data); + } + + public function detail($id) + { + $data = $this->repository->detail($id,$this->request->merId()); + return app('json')->success($data); + } + + public function cancelForm($id) + { + return app('json')->success(formToData($this->repository->cancelForm($id))); + } + + public function cancel($id) + { + $reason = $this->request->params(['reason','cancel_reason']); + if (empty($reason['reason'])) + return app('json')->fail('取消理由不能为空'); + $this->repository->cancel($id, $this->request->merId(), $reason); + return app('json')->success('取消成功'); + } + + public function delete($id) + { + $this->repository->destory($id, $this->request->merId()); + return app('json')->success('删除成功'); + } + + public function switchWithStatus($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + + +} diff --git a/app/controller/merchant/store/delivery/DeliveryStation.php b/app/controller/merchant/store/delivery/DeliveryStation.php new file mode 100644 index 00000000..9263388f --- /dev/null +++ b/app/controller/merchant/store/delivery/DeliveryStation.php @@ -0,0 +1,193 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\delivery; + +use app\common\repositories\system\serve\ServeOrderRepository; +use crmeb\services\DeliverySevices; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\delivery\DeliveryStationRepository; +use app\validate\merchant\DeliveryStationValidate; +use think\exception\ValidateException; + +class DeliveryStation extends BaseController +{ + protected $repository; + + public function __construct(App $app, DeliveryStationRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','station_name','status','type','date']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->merList($where, $page, $limit); + return app('json')->success($data); + } + + public function getTypeList() + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','station_name']); + $where['mer_id'] = $this->request->merId(); + $where['type'] = systemConfig('delivery_type'); + $where['status'] = 1; + $data = $this->repository->merList($where, $page, $limit); + return app('json')->success($data); + } + + public function detail($id) + { + $data = $this->repository->detail($id,$this->request->merId()); + return app('json')->success($data); + } + + public function create() + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $data = $this->checkParams(); + $data['mer_id'] = $this->request->merId(); + $this->repository->save($data); + return app('json')->success('添加成功'); + } + + public function update($id) + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $data = $this->checkParams(); + $this->repository->edit($id, $this->request->merId(), $data); + return app('json')->success('编辑成功'); + } + + public function delete($id) + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $this->repository->destory($id, $this->request->merId()); + return app('json')->success('删除成功'); + } + + public function switchWithStatus($id) + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + + public function markForm($id) + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + return app('json')->success(formToData($this->repository->markForm($id, $this->request->merId()))); + } + + public function mark($id) + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $data = $this->request->params(['mark']); + $this->repository->update($id, $data); + return app('json')->success('备注成功'); + } + + public function checkParams() + { + $data = $this->request->params([ + 'station_name', + 'business', + 'station_address', + 'lng', + 'lat', + 'contact_name', + 'phone', + 'username', + 'password', + ['status',1], + 'city_name', + ]); + $make = app()->make(DeliveryStationValidate::class); + $data['type'] = systemConfig('delivery_type'); + if ($data['type'] == DeliverySevices::DELIVERY_TYPE_DADA) { + $make->scene('dada')->check($data); + } else { + $make->check($data); + [$data['lng'],$data['lat']] = gcj02ToBd09($data['lng'],$data['lat']); + } + return $data; + } + + public function getBusiness() + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $data = $this->repository->getBusiness(); + return app('json')->success($data); + } + + public function options() + { + $where = [ + 'status' => 1, + 'mer_id' => $this->request->merId(), + 'type' => systemConfig('delivery_type'), + ]; + return app('json')->success($this->repository->getOptions($where)); + } + + public function select() + { + $where = [ + 'mer_id' => $this->request->merId(), + ]; + return app('json')->success($this->repository->getOptions($where)); + } + + public function getCityLst() + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + return app('json')->success($this->repository->getCityLst()); + } + + /** + * TODO 充值记录 + * @author Qinii + * @day 2/18/22 + */ + public function payLst() + { + + [$page, $limit] = $this->getPage(); + $where = [ + 'type' => 20, + 'mer_id' => $this->request->merId(), + 'date' => $this->request->param('date'), + ]; + $data = app()->make(ServeOrderRepository::class)->getList($where, $page, $limit); + $data['delivery_balance'] = $this->request->merchant()->delivery_balance; + return app('json')->success($data); + } + + public function getQrcode() + { + if (systemConfig('delivery_status') != 1) throw new ValidateException('未开启同城配送'); + $data['pay_type'] = $this->request->param('pay_type',1); + $data['price'] = $this->request->param('price',10); + if (!is_numeric($data['price']) || $data['price'] <= 0 ) + return app('json')->fail('支付金额不正确'); + $res = app()->make(ServeOrderRepository::class)->QrCode($this->request->merId(), 'delivery', $data); + $res['delivery_balance'] = $this->request->merchant()->delivery_balance; + return app('json')->success($res); + } +} diff --git a/app/controller/merchant/store/guarantee/GuaranteeTemplate.php b/app/controller/merchant/store/guarantee/GuaranteeTemplate.php new file mode 100644 index 00000000..8a6f75f8 --- /dev/null +++ b/app/controller/merchant/store/guarantee/GuaranteeTemplate.php @@ -0,0 +1,134 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\merchant\store\guarantee; + +use app\common\repositories\store\GuaranteeRepository; +use app\common\repositories\store\GuaranteeTemplateRepository; +use app\validate\admin\GuaranteeTemplateValidate; +use think\App; +use crmeb\basic\BaseController; + +class GuaranteeTemplate extends BaseController +{ + /** + * @var GuaranteeTemplateRepository + */ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param GuaranteeTemplateRepository $repository + */ + public function __construct(App $app, GuaranteeTemplateRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','keyword']); + $where['is_del'] = 0; + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function create(GuaranteeTemplateValidate $validate) + { + $data = $this->request->params(['template_name','template_value',['status',1],'sort']); + $validate->check($data); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function detail($id) + { + $ret = $this->repository->detail($id,$this->request->merId()); + return app('json')->success($ret); + } + + public function update($id,GuaranteeTemplateValidate $validate) + { + $data = $this->request->params(['template_name','template_value',['status',1],'sort']); + $validate->check($data); + $this->repository->detail($id,$this->request->merId()); + + $data['mer_id'] = $this->request->merId(); + $this->repository->edit($id,$data); + + return app('json')->success('编辑成功'); + } + + public function delete($id) + { + $this->repository->detail($id,$this->request->merId()); + + $this->repository->delete($id); + + return app('json')->success('删除成功'); + } + + /** + * TODO 添加模板筛选的条款数据 + * @return \think\response\Json + * @author Qinii + * @day 5/25/21 + */ + public function select() + { + $where['keyword'] = $this->request->param('keyword'); + $where['is_del'] = 0; + $where['status'] = 1; + $data = app()->make(GuaranteeRepository::class)->select($where); + + return app('json')->success($data); + } + + public function sort($id) + { + $ret = $this->repository->detail($id,$this->request->merId()); + if(!$ret) return app('json')->fail('数据不存在'); + $data = [ + 'sort' => $this->request->param('sort'), + ]; + $this->repository->update($id,$data); + + return app('json')->success('修改成功'); + } + + /** + * TODO 商品选择模板的下拉数据 + * @return \think\response\Json + * @author Qinii + * @day 5/25/21 + */ + public function list() + { + $data = $this->repository->list($this->request->merId()); + return app('json')->success($data); + } + + public function switchStatus($id) + { + $ret = $this->repository->detail($id,$this->request->merId()); + if(!$ret) return app('json')->fail('数据不存在'); + $data = [ + 'status' => $this->request->param('status') == 1 ?: 0, + ]; + $this->repository->update($id,$data); + + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/order/Order.php b/app/controller/merchant/store/order/Order.php new file mode 100644 index 00000000..c4e6ecfc --- /dev/null +++ b/app/controller/merchant/store/order/Order.php @@ -0,0 +1,458 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\order; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\order\MerchantReconciliationRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\exceptions\UploadException; +use crmeb\jobs\BatchDeliveryJob; +use crmeb\services\ExcelService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreOrderRepository as repository; +use think\facade\Queue; + +class Order extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function title() + { + $where = $this->request->params(['status', 'date', 'order_sn', 'username', 'order_type', 'keywords', 'order_id', 'activity_type']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getStat($where, $where['status'])); + } + /** + * 订单列表 + * @return mixed + * @author Qinii + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status', 'date', 'order_sn', 'username', 'order_type', 'keywords', 'order_id', 'activity_type', 'group_order_sn', 'store_name']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->merchantGetList($where, $page, $limit)); + } + + public function takeTitle() + { + $where = $this->request->params(['date', 'order_sn', 'username', 'keywords']); + $where['take_order'] = 1; + $where['status'] = -1; + $where['verify_date'] = $where['date']; + unset($where['date']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getStat($where, '')); + } + + /** + * TODO 自提订单列表 + * @return mixed + * @author Qinii + * @day 2020-08-17 + */ + public function takeLst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date', 'order_sn', 'username', 'keywords']); + $where['take_order'] = 1; + $where['status'] = -1; + $where['verify_date'] = $where['date']; + unset($where['date']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->merchantGetList($where, $page, $limit)); + } + + /** + * 订单头部统计 + * @return mixed + * @author Qinii + */ + public function chart() + { + return app('json')->success($this->repository->OrderTitleNumber($this->request->merId(), null)); + } + + /** + * TODO 自提订单头部统计 + * @return mixed + * @author Qinii + * @day 2020-08-17 + */ + public function takeChart() + { + return app('json')->success($this->repository->OrderTitleNumber($this->request->merId(), 1)); + } + + + /** + * TODO 订单类型 + * @return mixed + * @author Qinii + * @day 2020-08-15 + */ + public function orderType() + { + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->orderType($where)); + } + + /** + * @param $id + * @return mixed + * @author Qinii + */ + public function deliveryForm($id) + { + $data = $this->repository->getWhere(['order_id' => $id, 'mer_id' => $this->request->merId(), 'is_del' => 0]); + if (!$data) return app('json')->fail('数据不存在'); + if (!$data['paid']) return app('json')->fail('订单未支付'); + if (!in_array($data['status'], [0, 1])) return app('json')->fail('订单状态错误'); + return app('json')->success(formToData($this->repository->sendProductForm($id, $data))); + } + + /** + * TODO 发货 + * @param $id + * @return mixed + * @author Qinii + */ + public function delivery($id) + { + $type = $this->request->param('delivery_type'); + $split = $this->request->params(['is_split',['split',[]]]); + if (!$this->repository->merDeliveryExists($id, $this->request->merId())) + return app('json')->fail('订单信息或状态错误'); + switch ($type) + { + case 3: //虚拟发货 + $data = $this->request->params([ + 'delivery_type', + 'remark', + ]); + $data['delivery_name'] = ''; + $data['delivery_id'] = ''; + $method = 'delivery'; + break; + case 4: //电子面单 + if (!systemConfig('crmeb_serve_dump')) + return app('json')->fail('电子面单功能未开启'); + $data = $this->request->params([ + 'delivery_type', + 'delivery_name', + 'from_name', + 'from_tel', + 'from_addr', + 'temp_id', + 'remark', + ]); + if (!$data['from_name'] || + !$data['delivery_name'] || + !$data['from_tel'] || + !$data['from_addr'] || + !$data['temp_id'] + ) + return app('json')->fail('填写配送信息'); + $method = 'dump'; + break; + case 5: //同城配送 + if (systemConfig('delivery_status') != 1) + return app('json')->fail('未开启同城配送'); + $data = $this->request->params([ + 'delivery_type', + 'station_id', + 'mark', + ['cargo_weight',0], + 'remark', + ]); + if ($data['cargo_weight'] < 0) return app('json')->fail('包裹重量能为负数'); + if (!$data['station_id']) return app('json')->fail('请选择门店'); + $method = 'cityDelivery'; + break; + default: //快递 + $data = $this->request->params([ + 'delivery_type', + 'delivery_name', + 'delivery_id', + 'remark', + ]); + if (!$data['delivery_type'] || !$data['delivery_name'] || !$data['delivery_id']) + return app('json')->fail('填写配送信息'); + + $method = 'delivery'; + break; + } + $this->repository->runDelivery($id,$this->request->merId(), $data, $split, $method); + return app('json')->success('发货成功'); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 7/26/21 + */ + public function batchDelivery() + { + $params = $this->request->params([ + 'temp_id', + 'order_id', + 'from_tel', + 'from_addr', + 'from_name', + 'delivery_id', + 'delivery_type', + 'delivery_name', + 'remark', + ]); + if (!in_array($params['delivery_type'], [2, 3, 4])) return app('json')->fail('发货类型错误'); + if (!$params['order_id']) return app('json')->fail('需要订单ID'); + $data = [ + 'mer_id' => $this->request->merId(), + 'data' => $params + ]; + if ($params['delivery_type'] == 4 && !systemConfig('crmeb_serve_dump')) + return app('json')->fail('电子面单功能未开启'); + Queue::push(BatchDeliveryJob::class, $data); + return app('json')->success('开始批量发货'); + } + + /** + * TODO 改价form + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function updateForm($id) + { + if (!$this->repository->merStatusExists($id, $this->request->merId())) + return app('json')->fail('订单信息或状态错误'); + return app('json')->success(formToData($this->repository->form($id))); + } + + /** + * TODO 改价 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function update($id) + { + $data = $this->request->params(['total_price', 'pay_postage']); + if ($data['total_price'] < 0 || $data['pay_postage'] < 0) + return app('json')->fail('金额不可未负数'); + if (!$this->repository->merStatusExists($id, $this->request->merId())) + return app('json')->fail('订单信息或状态错误'); + $this->repository->eidt($id, $data); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function detail($id) + { + $data = $this->repository->getOne($id, $this->request->merId()); + if (!$data) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function status($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','user_type']); + $where['id'] = $id; + if (!$this->repository->getOne($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getOrderStatus($where, $page, $limit)); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function remarkForm($id) + { + return app('json')->success(formToData($this->repository->remarkForm($id))); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function remark($id) + { + if (!$this->repository->getOne($id, $this->request->merId())) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['remark']); + $this->repository->update($id, $data); + + return app('json')->success('备注成功'); + } + + /** + * 核销 + * @param $code + * @author xaboy + * @day 2020/8/15 + */ + public function verify($id) + { + $data = $this->request->params(['data','verify_code']); + $this->repository->verifyOrder($id, $this->request->merId(), $data); + return app('json')->success('订单核销成功'); + } + + public function verifyDetail($code) + { + $order = $this->repository->codeByDetail($code); + if (!$order) return app('json')->fail('订单不存在'); + return app('json')->success($order); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-11 + */ + public function delete($id) + { + if (!$this->repository->userDelExists($id, $this->request->merId())) + return app('json')->fail('订单信息或状态错误'); + $this->repository->merDelete($id); + return app('json')->success('删除成功'); + } + + + /** + * TODO 快递查询 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-25 + */ + public function express($id) + { + return app('json')->success($this->repository->express($id, $this->request->merId())); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-30 + */ + public function reList($id) + { + [$page, $limit] = $this->getPage(); + $make = app()->make(MerchantReconciliationRepository::class); + if (!$make->getWhereCount(['mer_id' => $this->request->merId(), 'reconciliation_id' => $id])) + return app('json')->fail('数据不存在'); + $where = ['reconciliation_id' => $id, 'type' => 0]; + return app('json')->success($this->repository->reconList($where, $page, $limit)); + } + + /** + * TODO 导出文件 + * @author Qinii + * @day 2020-07-30 + */ + public function excel() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status', 'date', 'order_sn', 'order_type', 'username', 'keywords', 'take_order']); + if ($where['take_order']) { + $where['status'] = -1; + $where['verify_date'] = $where['date']; + unset($where['date']); + unset($where['order_type']); + } + $where['mer_id'] = $this->request->merId(); + $data = app()->make(ExcelService::class)->order($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO 打印小票 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-30 + */ + public function printer($id) + { + $merId = $this->request->merId(); + if (!$this->repository->getWhere(['order_id' => $id, 'mer_id' => $merId])) + return app('json')->fail('数据不存在'); + $this->repository->batchPrinter($id, $merId); + return app('json')->success('打印成功'); + } + + /** + * TODO 导出发货单 + * @return \think\response\Json + * @author Qinii + * @day 3/13/21 + */ + public function deliveryExport() + { + $where = $this->request->params(['username', 'date', 'activity_type', 'order_type', 'username', 'keywords', 'id']); + $where['mer_id'] = $this->request->merId(); + $where['status'] = 0; + $where['paid'] = 1; + $make = app()->make(StoreOrderRepository::class); + if (is_array($where['id'])) $where['order_ids'] = $where['id']; + $count = $make->search($where)->count(); + if (!$count) return app('json')->fail('没有可导出数据'); + + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->delivery($where,$page,$limit); + return app('json')->success($data); + } + + public function childrenList($id) + { + $data = $this->repository->childrenList($id, $this->request->merId()); + return app('json')->success($data); + } +} diff --git a/app/controller/merchant/store/order/OrderReceipt.php b/app/controller/merchant/store/order/OrderReceipt.php new file mode 100644 index 00000000..b3471ceb --- /dev/null +++ b/app/controller/merchant/store/order/OrderReceipt.php @@ -0,0 +1,139 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\order; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreOrderReceiptRepository; +use app\common\repositories\user\UserReceiptRepository; +use app\common\repositories\store\order\StoreOrderRepository; + +class OrderReceipt extends BaseController +{ + protected $repository; + + public function __construct(App $app, StoreOrderReceiptRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-17 + */ + public function Lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status', 'date', 'receipt_sn','username','order_type','keyword']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO 平台列表 + * @return mixed + * @author Qinii + * @day 2020-10-17 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status', 'date', 'receipt_sn','username','order_type','keyword','mer_id']); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + + public function setRecipt() + { + $ids = $this->request->param('ids'); + if(!$ids) return app('json')->fail('请选择需要合并的发票'); + $this->repository->merExists($ids,$this->request->merId()); + return app('json')->success($this->repository->setRecipt($ids,$this->request->merId())); + } + + /** + * TODO 开票 + * @return mixed + * @author Qinii + * @day 2020-10-17 + */ + public function saveRecipt() + { + $data = $this->request->param(['ids','receipt_sn','receipt_price','receipt_no','mer_mark']); + $this->repository->merExists($data['ids'],$this->request->merId()); + if(!is_numeric($data['receipt_price']) || $data['receipt_price'] < 0) + return app('json')->fail('发票信息金额格式错误'); + //if(!$data['receipt_no'])return app('json')->fail('请填写发票号'); + $this->repository->save($data); + return app('json')->success('开票成功'); + } + + /** + * TODO 备注form + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-17 + */ + public function markForm($id) + { + return app('json')->success(formToData($this->repository->markForm($id))); + } + + /** + * TODO 备注 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-17 + */ + public function mark($id) + { + if(!$this->repository->getWhereCount(['order_receipt_id' => $id,'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['mer_mark']); + $this->repository->update($id,$data); + return app('json')->success('备注成功'); + } + + + public function detail($id) + { + $mer_id = $this->request->merId(); + $where = [$this->repository->getPk() => $id]; + if($mer_id) $where['mer_id'] = $mer_id; + $data = $this->repository->getSearch($where)->find(); + if(!$data) return app('json')->fail('数据不存在'); + if($data['receipt_info']->receipt_type == 1 ){ + $title = $data['receipt_info']->receipt_title_type == 1 ? '个人电子普通发票' : '企业电子普通发票'; + }else{ + $title = '企业专用纸质发票'; + } + $data['title'] = $title; + return app('json')->success($data); + } + + public function update($id) + { + $data = $this->request->params(['receipt_no','mer_mark']); + if(!empty($data['receipt_no'])) $data['status'] = 1; + $where = [$this->repository->getPk() => $id,'mer_id' => $this->request->merId()]; + $res = $this->repository->getSearch($where)->find(); + if(!$res) return app('json')->fail('数据不存在'); + $this->repository->updateBySn($res['receipt_sn'],$data); + return app('json')->success('编辑成功'); + } +} diff --git a/app/controller/merchant/store/order/Reconciliation.php b/app/controller/merchant/store/order/Reconciliation.php new file mode 100644 index 00000000..a844507e --- /dev/null +++ b/app/controller/merchant/store/order/Reconciliation.php @@ -0,0 +1,74 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\order; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\store\order\MerchantReconciliationRepository as repository; + +class Reconciliation extends BaseController +{ + protected $repository; + + public function __construct(App $app,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + public function lst() + { + [$page,$limit] = $this->getPage(); + $where = $this->request->params(['date','status','is_accounts','reconciliation_id','keyword']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + + + /** + * TODO 确认订单 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-15 + */ + public function switchStatus($id) + { + if(!$this->repository->merWhereCountById($id,$this->request->merId())) + return app('json')->fail('数据不存在或状态错误'); + $status = ($this->request->param('status') == 1) ? 1 : 2; + $data['status'] = $status; + $data['mer_admin_id'] = $this->request->merId(); + $this->repository->switchStatus($id,$data); + return app('json')->success('修改成功'); + } + + + public function markForm($id) + { + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id,'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->markForm($id))); + } + + public function mark($id) + { + if(!$this->repository->getWhereCount([$this->repository->getPk() => $id,'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $data = $this->request->params(['mark']); + $this->repository->update($id,$data); + return app('json')->success('备注成功'); + } +} diff --git a/app/controller/merchant/store/order/RefundOrder.php b/app/controller/merchant/store/order/RefundOrder.php new file mode 100644 index 00000000..62d1276b --- /dev/null +++ b/app/controller/merchant/store/order/RefundOrder.php @@ -0,0 +1,212 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\order; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\order\MerchantReconciliationRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\store\order\StoreRefundStatusRepository; +use crmeb\services\ExcelService; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\order\StoreRefundOrderRepository as repository; + +class RefundOrder extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + + /** + * Order constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @author Qinii + * @day 2020-06-12 + */ + public function lst() + { + list($page,$limit) = $this->getPage(); + $where = $this->request->params(['refund_order_sn','status','refund_type','date','order_sn','id','delivery_id']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where,$page,$limit)); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-12 + */ + public function detail($id) + { + if(!$this->repository->getExistsById($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getOne($id)); + } + + /** + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-12 + */ + public function switchStatus($id) + { + if(!$this->repository->getStatusExists($this->request->merId(),$id)) + return app('json')->fail('信息或状态错误'); + $status = ($this->request->param('status') == 1) ? 1 : -1; + event('refund.status',compact('id','status')); + if($status == 1){ + $data = $this->request->params(['mer_delivery_user','mer_delivery_address','phone']); + if ($data['phone'] && isPhone($data['phone'])) + return app('json')->fail('请输入正确的手机号'); + $data['status'] = $status; + $this->repository->agree($id,$data); + }else{ + $fail_message = $this->request->param('fail_message',''); + if($status == -1 && empty($fail_message)) + return app('json')->fail('未通过必须填写'); + $data['status'] = $status; + $data['fail_message'] = $fail_message; + $this->repository->refuse($id,$data); + } + return app('json')->success('审核成功'); + } + + /** + * TODO 收货后确定退款 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-12 + */ + public function refundPrice($id) + { + if(!$this->repository->getRefundPriceExists($this->request->merId(),$id)) + return app('json')->fail('信息或状态错误'); + $this->repository->adminRefund($id,0); + return app('json')->success('退款成功'); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-12 + */ + public function switchStatusForm($id) + { + if(!$this->repository->getStatusExists($this->request->merId(),$id)) + return app('json')->fail('信息或状态错误'); + return app('json')->success(formToData($this->repository->statusForm($id))); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function delete($id) + { + if(!$this->repository->getUserDelExists($this->request->merId(),$id)) + return app('json')->fail('信息或状态错误'); + $this->repository->update($id,['is_system_del' => 1]); + return app('json')->success('删除成功'); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function markForm($id) + { + if(!$this->repository->getExistsById($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->markForm($id))); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function mark($id) + { + if(!$this->repository->getExistsById($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['mer_mark' => $this->request->param('mer_mark','')]); + + return app('json')->success('备注成功'); + } + + public function log($id) + { + list($page,$limit) = $this->getPage(); + $where = $this->request->params(['date','user_type']); + $where['id'] = $id; + $where['type'] = StoreOrderStatusRepository::TYPE_REFUND; + $data = app()->make(StoreOrderStatusRepository::class)->search($where,$page,$limit); + return app('json')->success($data); + } + + public function reList($id) + { + [$page,$limit] = $this->getPage(); + $make = app()->make(MerchantReconciliationRepository::class); + if(!$make->getWhereCount(['mer_id' => $this->request->merId(),'reconciliation_id' => $id])) + return app('json')->fail('数据不存在'); + $where = ['reconciliation_id' => $id,'type' => 1]; + return app('json')->success($this->repository->reconList($where,$page,$limit)); + } + + /** + * TODO 快递查询 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-25 + */ + public function express($id) + { + return app('json')->success($this->repository->express($id)); + } + + public function createExcel() + { + $where = $this->request->params(['refund_order_sn','status','refund_type','date','order_sn','id']); + $where['mer_id'] = $this->request->merId(); + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->refundOrder($where, $page, $limit); + return app('json')->success($data); + } +} diff --git a/app/controller/merchant/store/product/Discounts.php b/app/controller/merchant/store/product/Discounts.php new file mode 100644 index 00000000..9542f620 --- /dev/null +++ b/app/controller/merchant/store/product/Discounts.php @@ -0,0 +1,133 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\StoreDiscountRepository; +use app\validate\merchant\StoreDiscountsValidate; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class Discounts extends BaseController +{ + + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param StoreDiscountRepository $repository + */ + public function __construct(App $app ,StoreDiscountRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $status = $this->request->param('status'); + $where = $this->request->params(['keyword','store_name','title','type']); + $where['is_show'] = $status; + + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getMerlist($where, $page, $limit); + return app('json')->success($data); + } + + public function create() + { + $data = $this->checkParams(); + $this->repository->save($data); + return app('json')->success('添加成功'); + } + + public function update($id) + { + $data = $this->checkParams(); + if (!$this->repository->getWhere(['mer_id' => $data['mer_id'], $this->repository->getPk() => $id])) + return app('json')->fail('数据不存在'); + $data['discount_id'] = $id; + $this->repository->save($data); + return app('json')->success('编辑成功'); + } + + public function detail($id) + { + $data = $this->repository->detail($id, $this->request->merId()); + if (!$data ) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + public function switchStatus($id) + { + $status = $this->request->param('status') == 1 ?: 0; + + if (!$this->repository->getWhere([$this->repository->getPk() => $id,'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_show' => $status]); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->getWhere([$this->repository->getPk() => $id,'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_del' => 1]); + return app('json')->success('删除成功'); + } + + public function checkParams() + { + $params = [ + ['title', ''], + ['image', ''], + ['type', 0], + ['is_limit', 0], + ['limit_num', 0], + ['is_time', 0], + ['time', []], + ['sort', 0], + ['free_shipping', 0], + ['status', 0], + ['is_show', 1], + ['products', []], + ['temp_id',0], + ]; + $data = $this->request->params($params); + app()->make(StoreDiscountsValidate::class)->check($data); + + if ($data['is_time'] && is_array($data['time'])) { + if (empty($data['time'])) throw new ValidateException('开始时间必须填写'); + [$start, $end] = $data['time']; + $start = strtotime($start); + $end = strtotime($end); + if($start > $end){ + throw new ValidateException('开始时间必须小于结束时间'); + } + if($start < time() || $end < time()){ + throw new ValidateException('套餐时间不能小于当前时间'); + } + } + foreach ($data['products'] as $item) { + if (!isset($item['items'])) + throw new ValidateException('请选择' . $item['store_name'] . '的规格'); + foreach ($item['attr'] as $attr) { + if($attr['active_price'] > $attr['price']) throw new ValidateException('套餐价格高于原价'); + } + } + $data['mer_id'] = $this->request->merId(); + return $data; + } + + +} diff --git a/app/controller/merchant/store/product/Product.php b/app/controller/merchant/store/product/Product.php new file mode 100644 index 00000000..789bd641 --- /dev/null +++ b/app/controller/merchant/store/product/Product.php @@ -0,0 +1,395 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; +use app\common\repositories\store\StoreCategoryRepository; +use crmeb\services\UploadService; +use think\App; +use crmeb\basic\BaseController; +use app\validate\merchant\StoreProductValidate as validate; +use app\common\repositories\store\product\ProductRepository as repository; +use think\exception\ValidateException; + +class Product extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['temp_id','cate_id','keyword',['type',1],'mer_cate_id','is_gift_bag','status','us_status','product_id','mer_labels',['order','sort'],'is_ficti','svip_price_type']); + $where = array_merge($where,$this->repository->switchType($where['type'],$this->request->merId(),0)); + $type=$this->request->merchant()['type_id']; + if ($type==12){ + $where['product_type']=98;//供应链 + } + return app('json')->success($this->repository->getList($this->request->merId(),$where, $page, $limit)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function detail($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id,null)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param validate $validate + * @return mixed + */ + public function create() + { + $params = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($params,$this->request->merId()); + $data['mer_id'] = $this->request->merId(); + if ($data['is_gift_bag'] && !$this->repository->checkMerchantBagNumber($data['mer_id'])) + return app('json')->fail('礼包数量超过数量限制'); + $data['status'] = $this->request->merchant()->is_audit ? 0 : 1; + $data['mer_status'] = ($this->request->merchant()->is_del || !$this->request->merchant()->mer_state || !$this->request->merchant()->status) ? 0 : 1; + $data['rate'] = 3; + if ($this->request->merchant()->type_id==12){ + $product_type=98;//供应链 + }else{ + $product_type=0;//普通商品 + } + $this->repository->create($data,$product_type); + return app('json')->success('添加成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id) + { + $params = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($params,$this->request->merId(), $id); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $pro = $this->repository->getWhere(['product_id' => $id]); + if ($pro->status == -2) { + $data['status'] = 0; + } else { + $data['status'] = $this->request->merchant()->is_audit ? 0 : 1; + } + $data['mer_status'] = ($this->request->merchant()->is_del || !$this->request->merchant()->mer_state || !$this->request->merchant()->status) ? 0 : 1; + $data['mer_id'] = $this->request->merId(); + $this->repository->edit($id, $data, $this->request->merId(), 0); + return app('json')->success('编辑成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + if($this->repository->getWhereCount(['product_id' => $id,'is_show' => 1,'status' => 1])) + return app('json')->fail('商品上架中'); + $this->repository->delete($id); + //queue(ChangeSpuStatusJob::class,['product_type' => 0,'id' => $id]); + return app('json')->success('转入回收站'); + } + + + public function destory($id) + { + if(!$this->repository->merDeleteExists($this->request->merId(),$id)) + return app('json')->fail('只能删除回收站的商品'); + if(app()->make(StoreCartRepository::class)->getProductById($id)) + return app('json')->fail('商品有被加入购物车不可删除'); + $this->repository->destory($id); + return app('json')->success('删除成功'); + } + + + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getStatusFilter() + { + $type=$this->request->merchant()['type_id']; + $product_type=0; + if ($type==12){ + $product_type=98;//供应链 + } + return app('json')->success($this->repository->getFilter($this->request->merId(),'商品',$product_type)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-24 + */ + public function config() + { + $data = systemConfig(['extension_status','svip_switch_status','integral_status']); + $merData= merchantConfig($this->request->merId(),['mer_integral_status','mer_integral_rate','mer_svip_status','svip_store_rate']); + $svip_store_rate = $merData['svip_store_rate'] > 0 ? bcdiv($merData['svip_store_rate'],100,2) : 0; + $data['mer_svip_status'] = ($data['svip_switch_status'] && $merData['mer_svip_status'] != 0 ) ? 1 : 0; + $data['svip_store_rate'] = $svip_store_rate; + $data['integral_status'] = $data['integral_status'] && $merData['mer_integral_status'] ? 1 : 0; + $data['integral_rate'] = $merData['mer_integral_rate'] ?: 0; + $data['delivery_way'] = $this->request->merchant()->delivery_way ? $this->request->merchant()->delivery_way : [2]; + $data['is_audit'] = $this->request->merchant()->is_audit; + return app('json')->success($data); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-03 + */ + public function restore($id) + { + if(!$this->repository->merDeleteExists($this->request->merId(),$id)) + return app('json')->fail('只能恢复回收站的商品'); + $this->repository->restore($id); + return app('json')->success('商品已恢复'); + } + + /** + * @return \think\response\Json + * @throws \think\Exception + * @author xaboy + * @day 2020/11/16 + */ + public function temp_key() + { + $upload = UploadService::create(); + $re = $upload->getTempKeys(); + return app('json')->success($re); + } + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id,$this->request->merId(),['sort' => $sort]); + return app('json')->success('修改成功'); + } + + public function preview() + { + $data = $this->request->param(); + $data['merchant'] = [ + 'mer_name' => $this->request->merchant()->mer_name, + 'is_trader' => $this->request->merchant()->is_trader, + 'mer_avatar' => $this->request->merchant()->mer_avatar, + 'product_score' => $this->request->merchant()->product_score, + 'service_score' => $this->request->merchant()->service_score, + 'postage_score' => $this->request->merchant()->postage_score, + 'service_phone' => $this->request->merchant()->service_phone, + 'care_count' => $this->request->merchant()->care_count, + 'type_name' => $this->request->merchant()->type_name->type_name ?? '', + 'care' => true, + 'recommend' => $this->request->merchant()->recommend, + ]; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 1; + $data['mer_status'] = 1; + $data['rate'] = 3; + return app('json')->success($this->repository->preview($data)); + } + + public function setLabels($id) + { + $data = $this->request->params(['mer_labels']); + app()->make(SpuRepository::class)->setLabels($id,0,$data,$this->request->merId()); + return app('json')->success('修改成功'); + } + + public function getAttrValue($id) + { + $data = $this->repository->getAttrValue($id, $this->request->merId()); + return app('json')->success($data); + } + + public function freeTrial($id) + { + $params = [ + "mer_cate_id", + "sort" , + "is_show", + "is_good", + "attr", + "attrValue", + 'spec_type' + ]; + $data = $this->request->params($params); + $count = app()->make(StoreCategoryRepository::class)->getWhereCount(['store_category_id' => $data['mer_cate_id'],'is_show' => 1,'mer_id' => $this->request->merId()]); + if (!$count) throw new ValidateException('商户分类不存在或不可用'); + $data['status'] = 1; + $this->repository->freeTrial($id, $data,$this->request->merId()); + return app('json')->success('编辑成功'); + } + + /** + * TODO 上下架 + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @return mixed + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + $this->repository->switchShow($id, $status,'is_show',$this->request->merId()); + return app('json')->success('修改成功'); + } + + + /** + * TODO 批量上下架 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchShow() + { + $ids = $this->request->param('ids'); + if (empty($ids)) return app('json')->fail('请选择商品'); + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->batchSwitchShow($ids,$status,'is_show',$this->request->merId()); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置模板 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchTemplate() + { + $ids = $this->request->param('ids'); + $ids = is_array($ids) ? $ids : explode(',',$ids); + $data = $this->request->params(['temp_id']); + if (empty($ids)) return app('json')->fail('请选择商品'); + if (empty($data['temp_id'])) return app('json')->fail('请选择运费模板'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) return app('json')->fail('请选择您自己商品'); + $make = app()->make(ShippingTemplateRepository::class); + if (!$make->merInExists($this->request->merId(), [$data['temp_id']])) + return app('json')->fail('请选择您自己的运费模板'); + $data['delivery_free'] = 0; + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量标签 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchLabels() + { + $ids = $this->request->param('ids'); + $data = $this->request->params(['mer_labels']); + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + app()->make(SpuRepository::class)->batchLabels($ids, $data,$this->request->merId()); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置推荐类型 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchHot() + { + $ids = $this->request->param('ids'); + $data['is_good'] = 1; + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置佣金 + * @param ProductAttrValueRepository $repository + * @return \think\response\Json + * @author Qinii + * @day 2022/12/26 + */ + public function batchExtension(ProductAttrValueRepository $repository) + { + $ids = $this->request->param('ids'); + $data = $this->request->params(['extension_one','extension_two']); + if ($data['extension_one'] > 1 || $data['extension_one'] < 0 || $data['extension_two'] < 0 || $data['extension_two'] > 1) { + return app('json')->fail('比例0~1之间'); + } + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + $repository->updatesExtension($ids,$data); + return app('json')->success('修改成功'); + } + + public function batchSvipType() + { + $ids = $this->request->param('ids'); + $data = $this->request->params([['svip_price_type',0]]); + + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/product/Product.php.bak b/app/controller/merchant/store/product/Product.php.bak new file mode 100644 index 00000000..efa05be0 --- /dev/null +++ b/app/controller/merchant/store/product/Product.php.bak @@ -0,0 +1,381 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\order\StoreCartRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\shipping\ShippingTemplateRepository; +use app\common\repositories\store\StoreCategoryRepository; +use crmeb\services\UploadService; +use think\App; +use crmeb\basic\BaseController; +use app\validate\merchant\StoreProductValidate as validate; +use app\common\repositories\store\product\ProductRepository as repository; +use think\exception\ValidateException; + +class Product extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['temp_id','cate_id','keyword',['type',1],'mer_cate_id','is_gift_bag','status','us_status','product_id','mer_labels',['order','sort'],'is_ficti','svip_price_type']); + $where = array_merge($where,$this->repository->switchType($where['type'],$this->request->merId(),0)); + return app('json')->success($this->repository->getList($this->request->merId(),$where, $page, $limit)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function detail($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id,null)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param validate $validate + * @return mixed + */ + public function create() + { + $params = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($params,$this->request->merId()); + $data['mer_id'] = $this->request->merId(); + if ($data['is_gift_bag'] && !$this->repository->checkMerchantBagNumber($data['mer_id'])) + return app('json')->fail('礼包数量超过数量限制'); + $data['status'] = $this->request->merchant()->is_audit ? 0 : 1; + $data['mer_status'] = ($this->request->merchant()->is_del || !$this->request->merchant()->mer_state || !$this->request->merchant()->status) ? 0 : 1; + $data['rate'] = 3; + $this->repository->create($data,0); + return app('json')->success('添加成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id) + { + $params = $this->request->params($this->repository::CREATE_PARAMS); + $data = $this->repository->checkParams($params,$this->request->merId(), $id); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $pro = $this->repository->getWhere(['product_id' => $id]); + if ($pro->status == -2) { + $data['status'] = 0; + } else { + $data['status'] = $this->request->merchant()->is_audit ? 0 : 1; + } + $data['mer_status'] = ($this->request->merchant()->is_del || !$this->request->merchant()->mer_state || !$this->request->merchant()->status) ? 0 : 1; + $data['mer_id'] = $this->request->merId(); + $this->repository->edit($id, $data, $this->request->merId(), 0); + return app('json')->success('编辑成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + if($this->repository->getWhereCount(['product_id' => $id,'is_show' => 1,'status' => 1])) + return app('json')->fail('商品上架中'); + $this->repository->delete($id); + //queue(ChangeSpuStatusJob::class,['product_type' => 0,'id' => $id]); + return app('json')->success('转入回收站'); + } + + + public function destory($id) + { + if(!$this->repository->merDeleteExists($this->request->merId(),$id)) + return app('json')->fail('只能删除回收站的商品'); + if(app()->make(StoreCartRepository::class)->getProductById($id)) + return app('json')->fail('商品有被加入购物车不可删除'); + $this->repository->destory($id); + return app('json')->success('删除成功'); + } + + + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getStatusFilter() + { + return app('json')->success($this->repository->getFilter($this->request->merId(),'商品',0)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-06-24 + */ + public function config() + { + $data = systemConfig(['extension_status','svip_switch_status','integral_status']); + $merData= merchantConfig($this->request->merId(),['mer_integral_status','mer_integral_rate','mer_svip_status','svip_store_rate']); + $svip_store_rate = $merData['svip_store_rate'] > 0 ? bcdiv($merData['svip_store_rate'],100,2) : 0; + $data['mer_svip_status'] = ($data['svip_switch_status'] && $merData['mer_svip_status'] != 0 ) ? 1 : 0; + $data['svip_store_rate'] = $svip_store_rate; + $data['integral_status'] = $data['integral_status'] && $merData['mer_integral_status'] ? 1 : 0; + $data['integral_rate'] = $merData['mer_integral_rate'] ?: 0; + $data['delivery_way'] = $this->request->merchant()->delivery_way ? $this->request->merchant()->delivery_way : [2]; + $data['is_audit'] = $this->request->merchant()->is_audit; + return app('json')->success($data); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-03 + */ + public function restore($id) + { + if(!$this->repository->merDeleteExists($this->request->merId(),$id)) + return app('json')->fail('只能恢复回收站的商品'); + $this->repository->restore($id); + return app('json')->success('商品已恢复'); + } + + /** + * @return \think\response\Json + * @throws \think\Exception + * @author xaboy + * @day 2020/11/16 + */ + public function temp_key() + { + $upload = UploadService::create(); + $re = $upload->getTempKeys(); + return app('json')->success($re); + } + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id,$this->request->merId(),['sort' => $sort]); + return app('json')->success('修改成功'); + } + + public function preview() + { + $data = $this->request->param(); + $data['merchant'] = [ + 'mer_name' => $this->request->merchant()->mer_name, + 'is_trader' => $this->request->merchant()->is_trader, + 'mer_avatar' => $this->request->merchant()->mer_avatar, + 'product_score' => $this->request->merchant()->product_score, + 'service_score' => $this->request->merchant()->service_score, + 'postage_score' => $this->request->merchant()->postage_score, + 'service_phone' => $this->request->merchant()->service_phone, + 'care_count' => $this->request->merchant()->care_count, + 'type_name' => $this->request->merchant()->type_name->type_name ?? '', + 'care' => true, + 'recommend' => $this->request->merchant()->recommend, + ]; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 1; + $data['mer_status'] = 1; + $data['rate'] = 3; + return app('json')->success($this->repository->preview($data)); + } + + public function setLabels($id) + { + $data = $this->request->params(['mer_labels']); + app()->make(SpuRepository::class)->setLabels($id,0,$data,$this->request->merId()); + return app('json')->success('修改成功'); + } + + public function getAttrValue($id) + { + $data = $this->repository->getAttrValue($id, $this->request->merId()); + return app('json')->success($data); + } + + public function freeTrial($id) + { + $params = [ + "mer_cate_id", + "sort" , + "is_show", + "is_good", + "attr", + "attrValue", + 'spec_type' + ]; + $data = $this->request->params($params); + $count = app()->make(StoreCategoryRepository::class)->getWhereCount(['store_category_id' => $data['mer_cate_id'],'is_show' => 1,'mer_id' => $this->request->merId()]); + if (!$count) throw new ValidateException('商户分类不存在或不可用'); + $data['status'] = 1; + $this->repository->freeTrial($id, $data,$this->request->merId()); + return app('json')->success('编辑成功'); + } + + /** + * TODO 上下架 + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @return mixed + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + $this->repository->switchShow($id, $status,'is_show',$this->request->merId()); + return app('json')->success('修改成功'); + } + + + /** + * TODO 批量上下架 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchShow() + { + $ids = $this->request->param('ids'); + if (empty($ids)) return app('json')->fail('请选择商品'); + $status = $this->request->param('status') == 1 ? 1 : 0; + $this->repository->batchSwitchShow($ids,$status,'is_show',$this->request->merId()); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置模板 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchTemplate() + { + $ids = $this->request->param('ids'); + $ids = is_array($ids) ? $ids : explode(',',$ids); + $data = $this->request->params(['temp_id']); + if (empty($ids)) return app('json')->fail('请选择商品'); + if (empty($data['temp_id'])) return app('json')->fail('请选择运费模板'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) return app('json')->fail('请选择您自己商品'); + $make = app()->make(ShippingTemplateRepository::class); + if (!$make->merInExists($this->request->merId(), [$data['temp_id']])) + return app('json')->fail('请选择您自己的运费模板'); + $data['delivery_free'] = 0; + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量标签 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchLabels() + { + $ids = $this->request->param('ids'); + $data = $this->request->params(['mer_labels']); + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + app()->make(SpuRepository::class)->batchLabels($ids, $data,$this->request->merId()); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置推荐类型 + * @return \think\response\Json + * @author Qinii + * @day 2022/9/6 + */ + public function batchHot() + { + $ids = $this->request->param('ids'); + $data['is_good'] = 1; + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } + + /** + * TODO 批量设置佣金 + * @param ProductAttrValueRepository $repository + * @return \think\response\Json + * @author Qinii + * @day 2022/12/26 + */ + public function batchExtension(ProductAttrValueRepository $repository) + { + $ids = $this->request->param('ids'); + $data = $this->request->params(['extension_one','extension_two']); + if ($data['extension_one'] > 1 || $data['extension_one'] < 0 || $data['extension_two'] < 0 || $data['extension_two'] > 1) { + return app('json')->fail('比例0~1之间'); + } + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + $repository->updatesExtension($ids,$data); + return app('json')->success('修改成功'); + } + + public function batchSvipType() + { + $ids = $this->request->param('ids'); + $data = $this->request->params([['svip_price_type',0]]); + + if (empty($ids)) return app('json')->fail('请选择商品'); + if (!$this->repository->merInExists($this->request->merId(), $ids)) + return app('json')->fail('请选择您自己商品'); + $this->repository->updates($ids,$data); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/product/ProductAssist.php b/app/controller/merchant/store/product/ProductAssist.php new file mode 100644 index 00000000..df9f401f --- /dev/null +++ b/app/controller/merchant/store/product/ProductAssist.php @@ -0,0 +1,167 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductAssistRepository as repository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use crmeb\basic\BaseController; +use think\App; +use app\validate\merchant\StoreProductAssistValidate; + +class ProductAssist extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['product_status','keyword','is_show','type','presell_type','us_status','product_assist_id','mer_labels']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getMerchantList($where,$page,$limit)); + } + + /** + * TODO 添加 + * @param StoreProductAssistValidate $validate + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function create(StoreProductAssistValidate $validate) + { + $data = $this->checkParams($validate); + $this->repository->create($this->request->merId(),$data); + return app('json')->success('添加成功'); + } + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + $data = $this->repository->detail($this->request->merId(),$id); + return app('json')->success($data); + } + + /** + * TODO + * @param $id + * @param StoreProductAssistValidate $validate + * @return mixed + * @author Qinii + * @day 2020-10-13 + */ + public function update($id,StoreProductAssistValidate $validate) + { + $data = $this->checkParams($validate->isUpdate()); + $this->repository->edit($id,$data); + return app('json')->success('编辑成功'); + } + + + public function delete($id) + { + $where = [ + $this->repository->getPk() => $id, + 'mer_id' => $this->request->merId() + ]; + $this->repository->delete($where); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if(!$this->repository->detail($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_show' => $status]); + app()->make(SpuRepository::class)->changeStatus($id,3); + return app('json')->success('修改成功'); + } + + + public function checkParams(StoreProductAssistValidate $validate) + { + $params = [ + "image", "slider_image", "store_name", "store_info", "product_id","is_show","temp_id","attrValue","guarantee_template_id", + "start_time", "end_time", "assist_user_count", "assist_count", "status","pay_count","product_status","sort",'mer_labels','delivery_way','delivery_free', + ]; + $data = $this->request->params($params); + + $validate->check($data); + return $data; + } + + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id,$this->request->merId(),['sort' => $sort]); + return app('json')->success('修改成功'); + } + + public function preview(ProductRepository $repository) + { + $data = $this->request->param(); + $data['merchant'] = [ + 'mer_name' => $this->request->merchant()->mer_name, + 'is_trader' => $this->request->merchant()->is_trader, + 'mer_avatar' => $this->request->merchant()->mer_avatar, + 'product_score' => $this->request->merchant()->product_score, + 'service_score' => $this->request->merchant()->service_score, + 'postage_score' => $this->request->merchant()->postage_score, + 'service_phone' => $this->request->merchant()->service_phone, + 'care_count' => $this->request->merchant()->care_count, + 'type_name' => $this->request->merchant()->type_name->type_name ?? '', + 'care' => true, + 'recommend' => $this->request->merchant()->recommend, + ]; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 1; + $data['mer_status'] = 1; + $data['rate'] = 3; + return app('json')->success($repository->preview($data)); + } + + public function setLabels($id) + { + $data = $this->request->params(['mer_labels']); +// if (empty($data['mer_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id,3,$data,$this->request->merId()); + return app('json')->success('修改成功'); + } + +} diff --git a/app/controller/merchant/store/product/ProductAssistSet.php b/app/controller/merchant/store/product/ProductAssistSet.php new file mode 100644 index 00000000..b7353d69 --- /dev/null +++ b/app/controller/merchant/store/product/ProductAssistSet.php @@ -0,0 +1,70 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductAssistSetRepository as repository; +use app\common\repositories\store\product\ProductAssistUserRepository; +use crmeb\basic\BaseController; +use think\App; +use app\validate\merchant\StoreProductAssistValidate; + +class ProductAssistSet extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','status','type','date','user_name']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getMerchantList($where,$page,$limit)); + } + + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + [$page, $limit] = $this->getPage(); + $where['product_assist_set_id'] = $id; + if(!$this->repository->getWhere(['product_assist_set_id' => $id,'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $make = app()->make(ProductAssistUserRepository::class); + return app('json')->success($make->userList($where,$page,$limit)); + } + + + +} diff --git a/app/controller/merchant/store/product/ProductCopy.php b/app/controller/merchant/store/product/ProductCopy.php new file mode 100644 index 00000000..6e7193fc --- /dev/null +++ b/app/controller/merchant/store/product/ProductCopy.php @@ -0,0 +1,90 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\merchant\StoreProductValidate as validate; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductCopyRepository as repository; + +class ProductCopy extends BaseController +{ + /** + * @var repository + */ + protected $repository; + + /** + * ProductCopy constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + $this->repository = $repository; + parent::__construct($app); + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-08-14 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + + $where['mer_id'] = $this->request->param('mer_id'); + $mer_id = $this->request->merId(); + if ($mer_id){ + $where['mer_id'] = $this->request->merId(); + } + $where['type'] = $this->request->param('type','copy'); + + return app('json')->success($this->repository->getList($where,$page, $limit)); + } + + /** + * TODO + * @return mixed + * @author Qinii + * @day 2020-08-07 + */ + public function count() + { + $count = $this->request->merchant()->copy_product_num; + return app('json')->success(['count' => $count]); + } + + /** + * TODO 复制商品 + * @return mixed + * @author Qinii + * @day 2020-08-06 + */ + public function get() + { + $status = systemConfig('copy_product_status'); + if($status == 0) return app('json')->fail('请前往平台后台-设置-第三方接口-开启采集'); + $num = app()->make(MerchantRepository::class)->getCopyNum($this->request->merId()); + if($num <= 0) return app('json')->fail('复制商品次数已用完'); + $url = $this->request->param('url'); + if (!$url) return app('json')->fail('请输入采集链接'); + $res = $this->repository->getProduct($url,$this->request->merId()); + return app('json')->success($res); + } + +} diff --git a/app/controller/merchant/store/product/ProductGroup.php b/app/controller/merchant/store/product/ProductGroup.php new file mode 100644 index 00000000..2b918532 --- /dev/null +++ b/app/controller/merchant/store/product/ProductGroup.php @@ -0,0 +1,155 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductGroupRepository; +use app\validate\merchant\StoreProductGroupValidate; +use think\exception\ValidateException; + +class ProductGroup extends BaseController +{ + protected $repository ; + + /** + * ProductGroup constructor. + * @param App $app + * @param ProductGroupRepository $repository + */ + public function __construct(App $app ,ProductGroupRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['product_status','keyword','active_type','status','us_status','product_group_id','mer_labels']); + $where['is_show'] = $where['status']; + unset($where['status']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getMerchantList($where,$page,$limit)); + } + + public function create(StoreProductGroupValidate $validate) + { + $data = $this->checkParams($validate); + $this->repository->create($this->request->merId(),$data); + return app('json')->success('添加成功'); + } + + public function detail($id) + { + $where = [ + $this->repository->getPk() => $id, + 'mer_id' => $this->request->merId() + ]; + if(!$this->repository->getWhere($where)) + return app('json')->fail('数据不存在'); + $data = $this->repository->detail($this->request->merId(),$id); + return app('json')->success($data); + } + + public function delete($id) + { + $where = [ + $this->repository->getPk() => $id, + 'mer_id' => $this->request->merId() + ]; + if(!$this->repository->getWhere($where)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,['is_del' => 1]); + event('product.groupDelete',compact('id')); + app()->make(SpuRepository::class)->changeStatus($id,4); + return app('json')->success('删除成功'); + } + + public function update($id,StoreProductGroupValidate $validate) + { + $data = $this->checkParams($validate); + $where = [ + $this->repository->getPk() => $id, + 'mer_id' => $this->request->merId() + ]; + if(!$this->repository->getWhere($where)) + return app('json')->fail('数据不存在'); + + $this->repository->edit($id,$data); + return app('json')->success('编辑成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if(!$this->repository->detail($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_show' => $status]); + app()->make(SpuRepository::class)->changeStatus($id,4); + return app('json')->success('修改成功'); + } + + public function checkParams(StoreProductGroupValidate $validate) + { + $params = [ + "image", "slider_image", "store_name", "store_info", "product_id","is_show","temp_id","once_pay_count","guarantee_template_id", + "start_time", "end_time", "buying_num", "buying_count_num", "status","pay_count","time","ficti_status","ficti_num","attrValue", + 'unit_name','content','sort','mer_labels','delivery_way','delivery_free' + ]; + $data = $this->request->params($params); + if($data['buying_count_num'] < 2) throw new ValidateException('开团人数不得少于2人'); + if($data['end_time'] < $data['start_time']) throw new ValidateException('活动开始时间必须大于结束时间'); + $validate->check($data); + return $data; + } + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id,$this->request->merId(),['sort' => $sort]); + return app('json')->success('修改成功'); + } + + public function preview(ProductRepository $repository) + { + $data = $this->request->param(); + $data['merchant'] = [ + 'mer_name' => $this->request->merchant()->mer_name, + 'is_trader' => $this->request->merchant()->is_trader, + 'mer_avatar' => $this->request->merchant()->mer_avatar, + 'product_score' => $this->request->merchant()->product_score, + 'service_score' => $this->request->merchant()->service_score, + 'postage_score' => $this->request->merchant()->postage_score, + 'service_phone' => $this->request->merchant()->service_phone, + 'care_count' => $this->request->merchant()->care_count, + 'type_name' => $this->request->merchant()->type_name->type_name ?? '', + 'care' => true, + 'recommend' => $this->request->merchant()->recommend, + ]; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 1; + $data['mer_status'] = 1; + $data['rate'] = 3; + return app('json')->success($repository->preview($data)); + } + + public function setLabels($id) + { + $data = $this->request->params(['mer_labels']); +// if (empty($data['mer_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id,4,$data,$this->request->merId()); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/product/ProductGroupBuying.php b/app/controller/merchant/store/product/ProductGroupBuying.php new file mode 100644 index 00000000..1f88d18b --- /dev/null +++ b/app/controller/merchant/store/product/ProductGroupBuying.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductGroupUserRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\product\ProductGroupBuyingRepository; + +class ProductGroupBuying extends BaseController +{ + protected $repository ; + + /** + * ProductGroup constructor. + * @param App $app + * @param ProductGroupBuyingRepository $repository + */ + public function __construct(App $app ,ProductGroupBuyingRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * TODO 团列表 + * @return \think\response\Json + * @author Qinii + * @day 1/12/21 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword','status','date','user_name']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getMerchantList($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO 团成员列表 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 1/12/21 + */ + public function detail($id) + { + [$page, $limit] = $this->getPage(); + if(!$this->repository->get($id)) + return app('json')->fail('数据不存在'); + $where = ['group_buying_id' => $id]; + $list = app()->make(ProductGroupUserRepository::class)->getAdminList($where,$page,$limit); + return app('json')->success($list); + } + +} diff --git a/app/controller/merchant/store/product/ProductLabel.php b/app/controller/merchant/store/product/ProductLabel.php new file mode 100644 index 00000000..56dca928 --- /dev/null +++ b/app/controller/merchant/store/product/ProductLabel.php @@ -0,0 +1,109 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductLabelRepository; +use app\validate\admin\ProductLabelValidate; +use think\App; +use crmeb\basic\BaseController; + +class ProductLabel extends BaseController +{ + + protected $repository; + + public function __construct(App $app, ProductLabelRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['name', 'type', 'status']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getList($where,$page, $limit); + return app('json')->success($data); + } + + public function createForm() + { + return app('json')->success(formToData($this->repository->form(null, 'merchantStoreProductLabelCreate'))); + } + + public function create(ProductLabelValidate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->check($data['label_name'], $this->request->merId())) + return app('json')->fail('名称重复'); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function updateForm($id) + { + return app('json')->success(formToData($this->repository->updateForm($id, 'merchantStoreProductLabelUpdate', $this->request->merId()))); + } + + public function update($id, ProductLabelValidate $validate) + { + $data = $this->checkParams($validate); + if (!$this->repository->check($data['label_name'], $this->request->merId(),$id)) + return app('json')->fail('名称重复'); + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => $this->request->merId()]); + if (!$getOne) return app('json')->fail('数据不存在'); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + public function detail($id) + { + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => $this->request->merId(), 'is_del' => 0]); + if (!$getOne) return app('json')->fail('数据不存在'); + return app('json')->success($getOne); + } + + public function delete($id) + { + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => $this->request->merId()]); + if (!$getOne) return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + public function switchWithStatus($id) + { + $status = $this->request->param('status') == 1 ? 1 : 0; + $getOne = $this->repository->getWhere(['product_label_id' => $id,'mer_id' => $this->request->merId()]); + if (!$getOne) return app('json')->fail('数据不存在'); + $this->repository->update($id,['status' => $status]); + return app('json')->success('修改成功'); + } + + public function getOptions() + { + $data = $this->repository->getOptions($this->request->merId()); + return app('json')->success($data); + } + + public function checkParams(ProductLabelValidate $validate) + { + $params = ['label_name', 'status', 'sort', 'info']; + $data = $this->request->params($params); + $validate->check($data); + return $data; + } + + + +} diff --git a/app/controller/merchant/store/product/ProductPresell.php b/app/controller/merchant/store/product/ProductPresell.php new file mode 100644 index 00000000..a627d364 --- /dev/null +++ b/app/controller/merchant/store/product/ProductPresell.php @@ -0,0 +1,177 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductPresellRepository as repository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use crmeb\basic\BaseController; +use think\App; +use app\validate\merchant\StoreProductPresellValidate; + +class ProductPresell extends BaseController +{ + protected $repository; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 列表 + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['product_status', 'keyword', 'type', 'presell_type', 'is_show', 'us_status','product_presell_id','mer_labels']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getMerchantList($where, $page, $limit)); + } + + /** + * TODO 添加 + * @param StoreProductPresellValidate $validate + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function create(StoreProductPresellValidate $validate) + { + $data = $this->checkParams($validate); + $this->repository->create($this->request->merId(), $data); + return app('json')->success('添加成功'); + } + + /** + * TODO 详情 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-10-12 + */ + public function detail($id) + { + $data = $this->repository->detail($this->request->merId(), $id); + return app('json')->success($data); + } + + /** + * TODO + * @param $id + * @param StoreProductPresellValidate $validate + * @return mixed + * @author Qinii + * @day 2020-10-13 + */ + public function update($id, StoreProductPresellValidate $validate) + { + $data = $this->checkParams($validate); + $where = [ + $this->repository->getPk() => $id, + 'mer_id' => $this->request->merId() + ]; + if (!$this->repository->getWhere($where)) + return app('json')->fail('数据不存在'); + $data['mer_id'] = $this->request->merId(); + $this->repository->edit($id, $data); + return app('json')->success('编辑成功'); + } + + + public function delete($id) + { + $where = [ + $this->repository->getPk() => $id, + 'mer_id' => $this->request->merId() + ]; + $this->repository->delete($where); + return app('json')->success('删除成功'); + } + + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if (!$this->repository->detail($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_show' => $status]); + app()->make(SpuRepository::class)->changeStatus($id,2); + return app('json')->success('修改成功'); + } + + public function number() + { + return app('json')->success($this->repository->stat($this->request->merId())); + } + + public function checkParams(StoreProductPresellValidate $validate) + { + $params = [ + "image", "slider_image", "store_name", "store_info", "product_id", "is_show", "temp_id", "attrValue","sort","guarantee_template_id", + "start_time", "end_time", "final_start_time", "final_end_time", "status", "presell_type", 'pay_count', "delivery_type", "delivery_day", + "product_status",'mer_labels','delivery_way','delivery_free' + ]; + $data = $this->request->params($params); + $validate->check($data); + return $data; + } + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + $this->repository->updateSort($id, $this->request->merId(), ['sort' => $sort]); + return app('json')->success('修改成功'); + } + + + public function preview(ProductRepository $repository) + { + $data = $this->request->param(); + $data['merchant'] = [ + 'mer_name' => $this->request->merchant()->mer_name, + 'is_trader' => $this->request->merchant()->is_trader, + 'mer_avatar' => $this->request->merchant()->mer_avatar, + 'product_score' => $this->request->merchant()->product_score, + 'service_score' => $this->request->merchant()->service_score, + 'postage_score' => $this->request->merchant()->postage_score, + 'service_phone' => $this->request->merchant()->service_phone, + 'care_count' => $this->request->merchant()->care_count, + 'type_name' => $this->request->merchant()->type_name->type_name ?? '', + 'care' => true, + 'recommend' => $this->request->merchant()->recommend, + ]; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 1; + $data['mer_status'] = 1; + $data['rate'] = 3; + return app('json')->success($repository->preview($data)); + } + + public function setLabels($id) + { + $data = $this->request->params(['mer_labels']); +// if (empty($data['mer_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id,2,$data,$this->request->merId()); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/product/ProductSeckill.php b/app/controller/merchant/store/product/ProductSeckill.php new file mode 100644 index 00000000..57e95992 --- /dev/null +++ b/app/controller/merchant/store/product/ProductSeckill.php @@ -0,0 +1,266 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\product; + +use app\common\repositories\store\product\ProductLabelRepository; +use app\common\repositories\store\product\SpuRepository; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\store\StoreSeckillTimeRepository; +use think\App; +use crmeb\basic\BaseController; +use app\validate\merchant\StoreSeckillProductValidate as validate; +use app\common\repositories\store\product\ProductRepository as repository; +use think\exception\ValidateException; + +class ProductSeckill extends BaseController +{ + protected $repository ; + + /** + * Product constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app ,repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['cate_id','keyword',['type',1],'mer_cate_id','seckill_status','us_status','product_id','mer_labels']); + $where = array_merge($where,$this->repository->switchType($where['type'],$this->request->merId(),1)); + return app('json')->success($this->repository->getSeckillList($this->request->merId(),$where, $page, $limit)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @return mixed + */ + public function detail($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getAdminOneProduct($id,null)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param validate $validate + * @return mixed + */ + public function create(validate $validate) + { + $data = $this->checkParams($validate); + $data['start_time'] = (int)substr($data['start_time'],0,2); + $data['end_time'] = (int)substr($data['end_time'],0,2); + $merchant = $this->request->merchant(); + $data['product_type'] = 1; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 0; + $data['is_gift_bag'] = 0; + $data['mer_status'] = ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1; + $this->repository->create($data,1); + return app('json')->success('添加成功'); + } + + + /** + * TODO 商品验证 + * @param $data + * @author Qinii + * @day 2020-08-01 + */ + public function check($data) + { + if($data['brand_id'] != 0 && !$this->repository->merBrandExists($data['brand_id'])) + throw new ValidateException('品牌不存在'); + if(!$this->repository->CatExists($data['cate_id'])) + throw new ValidateException('平台分类不存在'); + if(isset($data['mer_cate_id']) && !$this->repository->merCatExists($data['mer_cate_id'],$this->request->merId())) + throw new ValidateException('不存在的商户分类'); + + if($data['delivery_way'] == 2 && !$this->repository->merShippingExists($this->request->merId(),$data['temp_id'])) + throw new ValidateException('运费模板不存在'); + $make = app()->make(StoreSeckillTimeRepository::class); + $_count = $make->getWhereCount(['start_time' => $data['start_time'],'end_time' => $data['end_time']]); + if(!$_count) throw new ValidateException('时间段未开放活动'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + $merchant = $this->request->merchant(); + if(!$this->repository->merExists($this->request->merId(),$id)) return app('json')->fail('数据不存在'); + $this->check($data); + $data['status'] = 0; + $data['mer_status'] = ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1; + unset($data['old_product_id']); + $data['is_gift_bag'] = 0; + $this->repository->edit($id,$data,$this->request->merId(),1); + return app('json')->success('编辑成功'); + } + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-08-07 + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + if($this->repository->getWhereCount(['product_id' => $id,'is_show' => 1,'status' => 1])) + return app('json')->fail('商品上架中'); + $this->repository->delete($id); + return app('json')->success('转入回收站'); + } + + + public function destory($id) + { + if(!$this->repository->merDeleteExists($this->request->merId(),$id)) + return app('json')->fail('只能删除回收站的商品'); + $this->repository->destory($id); + return app('json')->success('删除成功'); + } + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @param int $id + * @return mixed + */ + public function switchStatus($id) + { + $status = $this->request->param('status', 0) == 1 ? 1 : 0; + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->switchShow($id, $status,'is_show',$this->request->merId()); + return app('json')->success('修改成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getStatusFilter() + { + return app('json')->success($this->repository->getFilter($this->request->merId(),'秒杀商品',1)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param validate $validate + * @return array + */ + public function checkParams(validate $validate) + { + $params = array_merge($this->repository::CREATE_PARAMS,["start_day","end_day", "start_time","end_time","once_count","all_pay_count", "once_pay_count","old_product_id"]); + $data = $this->request->params($params); + app()->make(ProductLabelRepository::class)->checkHas($this->request->merId(),$data['mer_labels']); + $validate->check($data); + $data['start_time'] = (int)substr($data['start_time'],0,2); + $data['end_time'] = (int)substr($data['end_time'],0,2); + return $data; + } + + + /** + * TODO + * @param $id + * @return mixed + * @author Qinii + * @day 2020-07-03 + */ + public function restore($id) + { + if(!$this->repository->merDeleteExists($this->request->merId(),$id)) + return app('json')->fail('只能删除回收站的商品'); + $this->repository->restore($id); + return app('json')->success('商品已恢复'); + } + + + /** + * TODO 获取可用时间段 + * @return mixed + * @author Qinii + * @day 2020-08-03 + */ + public function lst_time() + { + return app('json')->success(app()->make(StoreSeckillTimeRepository::class)->select()); + } + + public function updateSort($id) + { + $sort = $this->request->param('sort'); + app()->make(StoreSeckillActiveRepository::class); + $this->repository->updateSort($id,$this->request->merId(),['sort' => $sort]); + return app('json')->success('修改成功'); + } + + public function preview() + { + $data = $this->request->param(); + $data['merchant'] = [ + 'mer_name' => $this->request->merchant()->mer_name, + 'is_trader' => $this->request->merchant()->is_trader, + 'mer_avatar' => $this->request->merchant()->mer_avatar, + 'product_score' => $this->request->merchant()->product_score, + 'service_score' => $this->request->merchant()->service_score, + 'postage_score' => $this->request->merchant()->postage_score, + 'service_phone' => $this->request->merchant()->service_phone, + 'care_count' => $this->request->merchant()->care_count, + 'type_name' => $this->request->merchant()->type_name->type_name ?? '', + 'care' => true, + 'recommend' => $this->request->merchant()->recommend, + ]; + $data['mer_id'] = $this->request->merId(); + $data['status'] = 1; + $data['mer_status'] = 1; + $data['rate'] = 3; + return app('json')->success($this->repository->preview($data)); + } + + public function setLabels($id) + { + $data = $this->request->params(['mer_labels']); +// if (empty($data['mer_labels'])) return app('json')->fail('标签为空'); + + app()->make(SpuRepository::class)->setLabels($id,1,$data,$this->request->merId()); + return app('json')->success('修改成功'); + } +} diff --git a/app/controller/merchant/store/service/StoreService.php b/app/controller/merchant/store/service/StoreService.php new file mode 100644 index 00000000..50579be6 --- /dev/null +++ b/app/controller/merchant/store/service/StoreService.php @@ -0,0 +1,292 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\store\service; + + +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\user\UserRepository; +use app\validate\merchant\StoreServiceValidate; +use crmeb\basic\BaseController; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; + +/** + * Class StoreService + * @package app\controller\merchant\store\service + * @author xaboy + * @day 2020/5/29 + */ +class StoreService extends BaseController +{ + /** + * @var StoreServiceRepository + */ + protected $repository; + /** + * @var StoreServiceLogRepository + */ + protected $logRepository; + + /** + * StoreService constructor. + * @param App $app + * @param StoreServiceRepository $repository + */ + public function __construct(App $app, StoreServiceRepository $repository, StoreServiceLogRepository $logRepository) + { + parent::__construct($app); + $this->repository = $repository; + $this->logRepository = $logRepository; + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function lst() + { + $where = $this->request->params(['keyword', 'status']); + [$page, $limit] = $this->getPage(); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020/5/29 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->request->merId()))); + } + + /** + * @param StoreServiceValidate $validate + * @return mixed + * @author xaboy + * @day 2020/5/29 + */ + public function create(StoreServiceValidate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->request->merId(); + if ($this->repository->issetService($data['mer_id'], $data['uid'])) + return app('json')->fail('该用户已绑定客服'); + if ($this->repository->fieldExists('account', $data['account'])) { + return app('json')->fail('账号已存在'); + } + $data['pwd'] = password_hash($data['pwd'], PASSWORD_BCRYPT); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @param StoreServiceValidate $validate + * @return array + * @author xaboy + * @day 2020/5/29 + */ + public function checkParams(StoreServiceValidate $validate, $isUpdate = false) + { + $data = $this->request->params([['uid', []], 'nickname', 'account', 'pwd', 'confirm_pwd', 'is_open', 'status', 'customer', 'is_verify', 'is_goods', 'notify', 'avatar', 'phone', ['sort', 0]]); + if ($isUpdate) { + $validate->update(); + } + if (!$this->request->merId()) { + $data['is_verify'] = 0; + $data['customer'] = 0; + $data['is_goods'] = 0; + $data['notify'] = 0; + $data['phone'] = ''; + } + $validate->check($data); + if (!$data['avatar']) $data['avatar'] = $data['uid']['src']; + if ($data['pwd'] && $data['pwd'] != $data['confirm_pwd']) { + throw new ValidateException('客服密码与确认密码不一致'); + } + $data['uid'] = $data['uid']['id']; + unset($data['confirm_pwd']); + return $data; + } + + /** + * @param $id + * @return mixed + * @throws FormBuilderException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020/5/29 + */ + public function updateForm($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($id))); + } + + /** + * @param $id + * @param StoreServiceValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function update($id, StoreServiceValidate $validate) + { + $data = $this->checkParams($validate, true); + if (!$this->repository->merExists($merId = $this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + if ($this->repository->issetService($merId, $data['uid'], $id)) + return app('json')->fail('该用户已绑定客服'); + if ($this->repository->fieldExists('account', $data['account'], $id)) { + return app('json')->fail('账号已存在'); + } + if ($data['pwd']) { + $data['pwd'] = password_hash($data['pwd'], PASSWORD_BCRYPT); + } else { + unset($data['pwd']); + } + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function changeStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_open' => $status == 1 ? 1 : 0]); + return app('json')->success('修改成功'); + } + + /** + * @param $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020/5/29 + */ + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * TODO 客服的全部用户 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-18 + */ + public function serviceUserList($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getServiceUserList($id, $page, $limit)); + } + + + /** + * TODO 商户的全部用户列表 + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function merchantUserList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getMerchantUserList($this->request->merId(), $page, $limit)); + } + + /** + * TODO 用户与客服聊天记录 + * @param $id + * @param $uid + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function getUserMsnByService($id, $uid) + { + [$page, $limit] = $this->getPage(); + if (!$this->repository->getWhereCount(['service_id' => $id, 'mer_id' => $this->request->merId()])) + return app('json')->fail('客服不存在'); + return app('json')->success($this->logRepository->getUserMsn($uid, $page, $limit, $this->request->merId(), $id)); + } + + /** + * TODO 用户与商户聊天记录 + * @param $id + * @return mixed + * @author Qinii + * @day 2020-06-19 + */ + public function getUserMsnByMerchant($id) + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->logRepository->getUserMsn($id, $page, $limit, $this->request->merId())); + } + + public function getUserList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['nickname']); + $where['status'] = 1; + $data = app()->make(UserRepository::class)->getPulbicLst($where, $page, $limit); + return app('json')->success($data); + } + + public function login($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $adminInfo = $this->repository->get($id); + $tokenInfo = $this->repository->createToken($adminInfo); + $admin = $adminInfo->toArray(); + unset($admin['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $admin, + 'url' => '/' . config('admin.service_prefix') + ]; + return app('json')->success($data); + } +} diff --git a/app/controller/merchant/store/service/StoreServiceReply.php b/app/controller/merchant/store/service/StoreServiceReply.php new file mode 100644 index 00000000..81dfe94a --- /dev/null +++ b/app/controller/merchant/store/service/StoreServiceReply.php @@ -0,0 +1,92 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\service; + +use app\common\repositories\store\service\StoreServiceReplyRepository; +use app\validate\merchant\ServiceReplyValidate; +use crmeb\basic\BaseController; +use think\App; + +class StoreServiceReply extends BaseController +{ + /** + * @var StoreServiceReplyRepository + */ + protected $repository; + + /** + * StoreService constructor. + * @param App $app + * @param StoreServiceReplyRepository $repository + */ + public function __construct(App $app, StoreServiceReplyRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + + $where = $this->request->params(['keyword', 'status']); + $where['mer_id'] = $this->request->merId(); + + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function create() + { + $data = $this->checkParams(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function update($id) + { + $data = $this->checkParams(); + if (!$this->repository->existsWhere(['mer_id' => $data['mer_id'], 'service_reply_id' => $id])) { + return app('json')->fail('数据不存在'); + } + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + public function delete($id) + { + if (!$this->repository->existsWhere(['mer_id' => $this->request->merId(), 'service_reply_id' => $id])) { + return app('json')->fail('数据不存在'); + } + $this->repository->delete((int)$id); + return app('json')->success('删除成功'); + } + + public function changeStatus($id) + { + $data = $this->request->params(['status']); + if (!$this->repository->existsWhere(['mer_id' => $this->request->merId(), 'service_reply_id' => $id])) { + return app('json')->fail('数据不存在'); + } + $this->repository->update($id, $data); + return app('json')->success('修改成功'); + } + + public function checkParams() + { + $data = $this->request->params(['keyword', 'status', 'content', 'type']); + app()->make(ServiceReplyValidate::class)->check($data); + $data['mer_id'] = $this->request->merId(); + return $data; + } + +} diff --git a/app/controller/merchant/store/shipping/City.php b/app/controller/merchant/store/shipping/City.php new file mode 100644 index 00000000..8247d8b7 --- /dev/null +++ b/app/controller/merchant/store/shipping/City.php @@ -0,0 +1,75 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\shipping; + +use app\common\repositories\store\CityAreaRepository; +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\shipping\CityRepository as repository; +use think\facade\Log; + +class City extends BaseController +{ + protected $repository; + + /** + * City constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:40 + * @return mixed + */ + public function lst() + { + return app('json')->success($this->repository->getFormatList([['is_show', '=', 1],['level','<',2]])); + } + + public function lstV2($pid) + { + return app('json')->success(app()->make(CityAreaRepository::class)->getChildren(intval($pid))); + } + + public function cityList() + { + $address = $this->request->param('address'); + if (!$address) + return app('json')->fail('地址不存在'); + $make = app()->make(CityAreaRepository::class); + $city = $make->search(compact('address'))->order('id DESC')->find(); + if (!$city){ + Log::info('用户定位对比失败,请在城市数据中增加:'.var_export($address,true)); + return app('json')->fail('地址不存在'); + } + return app('json')->success($make->getCityList($city)); + } + + + /** + * @return mixed + * @author Qinii + */ + public function getlist() + { + return app('json')->success($this->repository->getFormatList(['is_show' => 1])); + } +} diff --git a/app/controller/merchant/store/shipping/ShippingTemplate.php b/app/controller/merchant/store/shipping/ShippingTemplate.php new file mode 100644 index 00000000..acb3ac9a --- /dev/null +++ b/app/controller/merchant/store/shipping/ShippingTemplate.php @@ -0,0 +1,137 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\shipping; + +use think\App; +use crmeb\basic\BaseController; +use app\validate\merchant\ShippingTemplateValidate as validate; +use app\common\repositories\store\shipping\ShippingTemplateRepository as repository; + +class ShippingTemplate extends BaseController +{ + protected $repository; + + /** + * ShippingTemplate constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @return mixed + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['type','name']); + return app('json')->success($this->repository->search($this->request->merId(),$where, $page, $limit)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/18 + * @return mixed + */ + public function getList() + { + return app('json')->success($this->repository->getList($this->request->merId())); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param validate $validate + * @return mixed + */ + public function create(validate $validate) + { + $data = $this->checkParams($validate); + $data['mer_id'] = $this->request->merId(); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param $id + * @return mixed + */ + public function detail($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + return app('json')->success($this->repository->getOne($id)); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param $id + * @param validate $validate + * @return mixed + */ + public function update($id,validate $validate) + { + $data = $this->checkParams($validate); + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id,$data,$this->request->merId()); + + return app('json')->success('编辑成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + if($this->repository->merDefaultExists($this->request->merId(),$id)) + return app('json')->fail('默认模板不能删除'); + if($this->repository->getProductUse($this->request->merId(),$id)) + return app('json')->fail('模板使用中,不能删除'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param validate $validate + * @return array + */ + public function checkParams(validate $validate) + { + $data = $this->request->params(['name','type','appoint','undelivery','region','free','undelives','sort','info']); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/merchant/store/shipping/ShippingTemplateFree.php b/app/controller/merchant/store/shipping/ShippingTemplateFree.php new file mode 100644 index 00000000..96c2e5f4 --- /dev/null +++ b/app/controller/merchant/store/shipping/ShippingTemplateFree.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\shipping; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\shipping\ShippingTemplateFreeRepository as repository; + +class ShippingTemplateFree extends BaseController +{ + protected $repository; + + /** + * ShippingTemplateFree constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:38 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功') ; + } + +} diff --git a/app/controller/merchant/store/shipping/ShippingTemplateRegion.php b/app/controller/merchant/store/shipping/ShippingTemplateRegion.php new file mode 100644 index 00000000..5cf1bc2a --- /dev/null +++ b/app/controller/merchant/store/shipping/ShippingTemplateRegion.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\shipping; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\shipping\ShippingTemplateRegionRepository as repository; + +class ShippingTemplateRegion extends BaseController +{ + protected $repository; + + /** + * ShippingTemplateRegion constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功') ; + } + +} diff --git a/app/controller/merchant/store/shipping/ShippingTemplateUndelive.php b/app/controller/merchant/store/shipping/ShippingTemplateUndelive.php new file mode 100644 index 00000000..796369e2 --- /dev/null +++ b/app/controller/merchant/store/shipping/ShippingTemplateUndelive.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace app\controller\merchant\store\shipping; + +use think\App; +use crmeb\basic\BaseController; +use app\common\repositories\store\shipping\ShippingTemplateUndeliveRepository as repository; + +class ShippingTemplateUndelive extends BaseController +{ + protected $repository; + + /** + * ShippingTemplateUndelive constructor. + * @param App $app + * @param repository $repository + */ + public function __construct(App $app, repository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @Author:Qinii + * @Date: 2020/5/8 + * @Time: 14:39 + * @param $id + * @return mixed + */ + public function delete($id) + { + if(!$this->repository->merExists($this->request->merId(),$id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功') ; + } + +} diff --git a/app/controller/merchant/system/Merchant.php b/app/controller/merchant/system/Merchant.php new file mode 100644 index 00000000..7a30d73f --- /dev/null +++ b/app/controller/merchant/system/Merchant.php @@ -0,0 +1,201 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system; + + +use app\common\repositories\store\MerchantTakeRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use app\common\repositories\user\UserBillRepository; +use app\validate\merchant\MerchantTakeValidate; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\merchant\MerchantUpdateValidate; +use crmeb\jobs\ChangeMerchantStatusJob; +use think\App; +use think\facade\Queue; + +/** + * Class Merchant + * @package app\controller\merchant\system + * @author xaboy + * @day 2020/6/25 + */ +class Merchant extends BaseController +{ + /** + * @var MerchantRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param MerchantRepository $repository + */ + public function __construct(App $app, MerchantRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws \FormBuilder\Exception\FormBuilderException + * @author xaboy + * @day 2020/6/25 + */ + public function updateForm() + { + return app('json')->success(formToData($this->repository->merchantForm($this->request->merchant()->toArray()))); + } + + /** + * @param MerchantUpdateValidate $validate + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public function update(MerchantUpdateValidate $validate, MerchantTakeValidate $takeValidate, MerchantTakeRepository $repository) + { + + $type = $this->request->param('type',1); + $merchant = $this->request->merchant(); + if ($type == 2) { + $data = $this->request->params([ + 'mer_info', + 'mer_certificate', + 'service_phone', + 'mer_avatar', + 'mer_banner', + 'mer_state', + 'mini_banner', + 'mer_keyword', + 'mer_address', + 'long', + 'lat', + ['delivery_way',[2]], + ]); + $validate->check($data); + $sys_bases_status = systemConfig('sys_bases_status') === '0' ? 0 : 1; + if ($sys_bases_status && empty($data['mer_certificate'])) + return app('json')->fail('店铺资质不可为空'); + + app()->make(ConfigValueRepository::class)->setFormData([ + 'mer_certificate' => $data['mer_certificate'] + ], $this->request->merId()); + unset($data['mer_certificate']); + + foreach ($data['delivery_way'] as $datum) { + if ($datum == 1) { + $takeData = $this->request->params(['mer_take_status', 'mer_take_name', 'mer_take_phone', 'mer_take_address', 'mer_take_location', 'mer_take_day', 'mer_take_time']); + $takeValidate->check($takeData); + $repository->set($this->request->merId(), $takeData); + break; + } + } + $delivery_way = implode(',',$data['delivery_way']); + if (count($data['delivery_way']) == 1 && $data['delivery_way'] != $merchant->delivery_way) { + app()->make(ProductRepository::class)->getSearch([]) + ->where('mer_id',$merchant->mer_id) + ->update(['delivery_way' => $delivery_way]); + } + + $data['delivery_way'] = $delivery_way; + + } else { + $data = $this->request->params(['mer_state']); + + if ($merchant->is_margin == 1 && $data['mer_state'] == 1) + return app('json')->fail('开启店铺前请先支付保证金'); + + if ($data['mer_state'] && !$merchant->sub_mchid && systemConfig('open_wx_combine')) + return app('json')->fail('开启店铺前请先完成微信子商户入驻'); + } + $merchant->save($data); + + Queue::push(ChangeMerchantStatusJob::class, $this->request->merId()); + return app('json')->success('修改成功'); + } + + + /** + * @return mixed + * @author xaboy + * @day 2020/7/21 + */ + public function info(MerchantTakeRepository $repository) + { + $merchant = $this->request->merchant(); + $append = ['merchantCategory', 'merchantType', 'mer_certificate']; + if ($merchant->is_margin == -10) + $append[] = 'refundMarginOrder'; + + $data = $merchant->append($append)->hidden(['mark', 'reg_admin_id', 'sort'])->toArray(); + $delivery = $repository->get($this->request->merId()) + systemConfig(['tx_map_key']); + $data = array_merge($data,$delivery); + $data['sys_bases_status'] = systemConfig('sys_bases_status') === '0' ? 0 : 1; + + return app('json')->success($data); + } + + /** + * @param MerchantTakeRepository $repository + * @return mixed + * @author xaboy + * @day 2020/8/1 + */ + public function takeInfo(MerchantTakeRepository $repository) + { + $merId = $this->request->merId(); + return app('json')->success($repository->get($merId) + systemConfig(['tx_map_key'])); + } + + /** + * @param MerchantTakeValidate $validate + * @param MerchantTakeRepository $repository + * @return mixed + * @author xaboy + * @day 2020/8/1 + */ + public function take(MerchantTakeValidate $validate, MerchantTakeRepository $repository) + { + $data = $this->request->params(['mer_take_status', 'mer_take_name', 'mer_take_phone', 'mer_take_address', 'mer_take_location', 'mer_take_day', 'mer_take_time']); + $validate->check($data); + $repository->set($this->request->merId(), $data); + return app('json')->success('设置成功'); + } + + + public function getMarginQrCode() + { + $data['pay_type'] = 1; + $res = app()->make(ServeOrderRepository::class)->QrCode($this->request->merId(), 'margin', $data); + return app('json')->success($res); + } + + public function getMarginLst() + { + [$page, $limit] = $this->getPage(); + $where = [ + 'mer_id' => $this->request->merId(), + 'category' => 'mer_margin' + ]; + $data = app()->make(UserBillRepository::class)->getLst($where, $page, $limit); + return app('json')->success($data); + } + + +} diff --git a/app/controller/merchant/system/MerchantApplyments.php b/app/controller/merchant/system/MerchantApplyments.php new file mode 100644 index 00000000..92240b43 --- /dev/null +++ b/app/controller/merchant/system/MerchantApplyments.php @@ -0,0 +1,137 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system; + +use app\validate\merchant\MerchantApplymentsValidate; +use think\App; +use think\facade\Config; +use think\facade\Queue; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantApplymentsRepository; + +class MerchantApplyments extends BaseController +{ + /** + * @var MerchantRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param MerchantRepository $repository + */ + public function __construct(App $app, MerchantApplymentsRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 创建申请 + * @param MerchantApplymentsValidate $validate + * @return \think\response\Json + * @author Qinii + * @day 6/22/21 + */ + public function create(MerchantApplymentsValidate $validate) + { + if(!systemConfig('open_wx_sub_mch')) return app('json')->fail('未开启子商户入驻'); + $data = $this->checkParams($validate); + + $this->repository->create($data,$this->request->merId()); + + return app('json')->success('申请提交成功'); + } + + public function detail() + { + $merId = $this->request->merId(); + $data = $this->repository->detail($merId); + $data['open_wx_sub_mch'] = systemConfig('open_wx_sub_mch'); + return app('json')->success($data); + } + + public function update($id,MerchantApplymentsValidate $validate) + { + if(!systemConfig('open_wx_sub_mch')) return app('json')->fail('未开启子商户入驻'); + $data = $this->checkParams($validate); + unset($data['id']); + $this->repository->edit($id,$data); + + return app('json')->success('编辑提交成功'); + } + + public function check() + { + $mer_id = $this->request->merId(); + $this->repository->check($mer_id); + return app('json')->success('查询状态已更新'); + } + + public function uploadImage($field) + { + $file = $this->request->file($field); + $water = $this->request->param('water'); + if (!$file) return app('json')->fail('请上传图片'); + $file = is_array($file) ? $file[0] : $file; + validate(["$field|图片" => [ + 'fileSize' => config('upload.filesize'), + 'fileExt' => 'jpg,jpeg,png,bmp,gif', + 'fileMime' => 'image/jpeg,image/png,image/gif', + function ($file) { + $ext = $file->extension(); + if ($ext != strtolower($file->extension())) { + return '图片后缀必须为小写'; + } + return true; + } + ]])->check([$field => $file]); + + $res = $this->repository->uploadImage($field,$water); + + return app('json')->success($res); + } + + + public function checkParams(MerchantApplymentsValidate $validate) + { + //'organization_cert_info', + $data = $this->request->params([ + 'organization_type','business_license_info','id_doc_type','id_card_info','id_doc_info','need_account_info','account_info','contact_info','sales_scene_info','merchant_shortname','qualifications','business_addition_pics','business_addition_desc' + ]); + + if($data['id_doc_type'] == 1){ + unset($data['id_doc_info']); + }else{ + unset($data['id_card_info']); + } + + if(in_array($data['organization_type'],['2401','2500'])){ + unset($data['business_license_info']); +// unset($data['organization_cert_info']); + } + +// if(isset($data['organization_cert_info']) && !is_array($data['organization_cert_info'])) unset($data['organization_cert_info']); + + if(isset($data['qualifications']) && !$data['qualifications']) unset($data['qualifications']); + + if(isset($data['business_addition_pics']) && !$data['business_addition_pics']) unset($data['business_addition_pics']); + if($data['organization_type'] !== 2 && isset($data['id_card_info']['id_card_address'])){ + unset($data['id_card_info']['id_card_address']); + } + $validate->check($data); + return $data; + } +} diff --git a/app/controller/merchant/system/admin/Login.php b/app/controller/merchant/system/admin/Login.php new file mode 100644 index 00000000..acd96879 --- /dev/null +++ b/app/controller/merchant/system/admin/Login.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system\admin; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\validate\admin\LoginValidate; +use crmeb\services\SwooleTaskService; +use Gregwar\Captcha\CaptchaBuilder; +use Gregwar\Captcha\PhraseBuilder; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\facade\Cache; + +class Login extends BaseController +{ + protected $repository; + + public function __construct(App $app, MerchantAdminRepository $repository) + { + + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 判断是否需要滑块验证码 + * @return \think\response\Json + * @author Qinii + * @day 2022/10/11 + */ + public function ajCaptchaStatus() + { + $data = $this->request->params(['account']); + $key = 'mer_login_failuree_'.$data['account']; + $numb = (Cache::get($key) ?? 0); + return app('json')->success(['status' => $numb > 2 ]); + } + + /** + * @param LoginValidate $validate + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-10 + */ + public function login(LoginValidate $validate) + { + $data = $this->request->params(['account', 'password', 'code', 'key',['captchaType', ''], ['captchaVerification', ''],'token']); + $validate->check($data); + + //图形验证码废弃 +// if(Cache::get('mer_login_freeze_'.$data['account'])) +// return app('json')->fail('账号或密码错误次数太多,请稍后在尝试'); +// $this->repository->checkCode($data['key'], $data['code']); + + $key = 'mer_login_failuree_'.$data['account']; + $numb = (Cache::get($key) ?? 0); + if($numb > 2){ + if (!$data['captchaType'] || !$data['captchaVerification']) + return app('json')->fail('请滑动滑块验证'); + try { + aj_captcha_check_two($data['captchaType'], $data['captchaVerification']); + } catch (\Throwable $e) { + return app('json')->fail($e->getMessage()); + } + } + $adminInfo = $this->repository->login($data['account'], $data['password']); + $tokenInfo = $this->repository->createToken($adminInfo); + $admin = $adminInfo->toArray(); + unset($admin['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $admin + ]; + Cache::delete($key); + return app('json')->success($data); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-10 + */ + public function logout() + { + if ($this->request->isLogin()) + $this->repository->clearToken($this->request->token()); + return app('json')->success('退出登录'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-09 + */ + public function getCaptcha() + { + $codeBuilder = new CaptchaBuilder(null, new PhraseBuilder(4)); + $key = $this->repository->createLoginKey($codeBuilder->getPhrase()); + $captcha = $codeBuilder->build()->inline(); + return app('json')->success(compact('key', 'captcha')); + } +} diff --git a/app/controller/merchant/system/admin/MerchantAdmin.php b/app/controller/merchant/system/admin/MerchantAdmin.php new file mode 100644 index 00000000..2cda04f6 --- /dev/null +++ b/app/controller/merchant/system/admin/MerchantAdmin.php @@ -0,0 +1,288 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system\admin; + + +use app\common\repositories\system\auth\RoleRepository; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\validate\admin\AdminEditValidate; +use app\validate\admin\AdminValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class MerchantAdmin + * @package app\controller\admin\system\admin + * @author xaboy + * @day 2020-04-18 + */ +class MerchantAdmin extends BaseController +{ + /** + * @var MerchantAdminRepository + */ + protected $repository; + + /** + * @var int + */ + protected $merId; + + /** + * MerchantAdmin constructor. + * @param App $app + * @param MerchantAdminRepository $repository + */ + public function __construct(App $app, MerchantAdminRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + $this->merId = $this->request->merId(); + } + + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function getList() + { + $where = $this->request->params(['keyword', 'date', 'status']); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($this->merId, $where, $page, $limit)); + } + + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function switchStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->exists($id, $this->merId, 1)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status == 1 ? 1 : 0]); + return app('json')->success('编辑成功'); + } + + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-18 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->form($this->merId))); + } + + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function updateForm($id) + { + if (!$this->repository->exists($id, $this->merId, 1)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->updateForm($this->merId, $id))); + } + + + /** + * @param int $id + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-18 + */ + public function passwordForm($id) + { + if (!$this->repository->exists($id, $this->merId)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->passwordForm($id))); + } + + + /** + * @param AdminValidate $validate + * @return mixed + * @author xaboy + * @day 2020-04-18 + */ + public function create(AdminValidate $validate) + { + $data = $this->request->params(['account', 'phone', 'pwd', 'againPassword', 'real_name', ['roles', []], ['status', 0]]); + $validate->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + unset($data['againPassword']); + if ($this->repository->merFieldExists($this->merId, 'account', $data['account'])) + return app('json')->fail('账号已存在'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + $data['mer_id'] = $this->merId; + $data['level'] = 1; + $check = app()->make(RoleRepository::class)->checkRole($data['roles'],$this->merId); + if (!$check ) { + return app('json')->fail('未开启或者不存在的身份不能添加'); + } + $this->repository->create($data); + + return app('json')->success('添加成功'); + } + + + /** + * @param int $id + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function update($id, AdminValidate $validate) + { + $data = $this->request->params(['account', 'phone', 'real_name', ['roles', []], ['status', 0]]); + $validate->isUpdate()->check($data); + if ($this->repository->merFieldExists($this->merId, 'account', $data['account'], $id)) + return app('json')->fail('账号已存在'); + + $check = app()->make(RoleRepository::class)->checkRole($data['roles'],$this->merId); + if (!$check ) { + return app('json')->fail('未开启或者不存在的身份不能添加'); + } + $this->repository->update($id, $data); + + return app('json')->success('编辑成功'); + } + + /** + * @param int $id + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function password($id, AdminValidate $validate) + { + $data = $this->request->params(['pwd', 'againPassword']); + $validate->isPassword()->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + if (!$this->repository->exists($id, $this->merId)) + return app('json')->fail('管理员不存在'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + unset($data['againPassword']); + $this->repository->update($id, $data); + + return app('json')->success('修改密码成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function delete($id) + { + if (!$this->repository->exists($id, $this->merId, 1)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['is_del' => 1]); + return app('json')->success('删除成功'); + } + + /** + * @param AdminEditValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function edit(AdminEditValidate $validate) + { + $data = $this->request->params(['real_name', 'phone']); + $validate->check($data); + $this->repository->update($this->request->adminId(), $data); + return app('json')->success('修改成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function editForm() + { + $adminInfo = $this->request->adminInfo(); + return app('json')->success(formToData($this->repository->editForm(['real_name' => $adminInfo->real_name, 'phone' => $adminInfo->phone]))); + } + + /** + * @param AdminValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-20 + */ + public function editPassword(AdminValidate $validate) + { + $data = $this->request->params(['pwd', 'againPassword']); + $validate->isPassword()->check($data); + + if ($data['pwd'] !== $data['againPassword']) + return app('json')->fail('两次密码输入不一致'); + $data['pwd'] = $this->repository->passwordEncode($data['pwd']); + unset($data['againPassword']); + $this->repository->update($this->request->adminId(), $data); + + return app('json')->success('修改密码成功'); + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-20 + */ + public function editPasswordForm() + { + return app('json')->success(formToData($this->repository->passwordForm($this->request->adminId(), 3))); + } + +} diff --git a/app/controller/merchant/system/auth/Role.php b/app/controller/merchant/system/auth/Role.php new file mode 100644 index 00000000..207a9a61 --- /dev/null +++ b/app/controller/merchant/system/auth/Role.php @@ -0,0 +1,155 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system\auth; + + +use crmeb\basic\BaseController; +use app\common\repositories\system\auth\RoleRepository; +use app\validate\admin\RoleValidate; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +class Role extends BaseController +{ + protected $repository; + + public function __construct(App $app, RoleRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return mixed + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-18 + */ + public function createForm() + { + $merchant = $this->request->merchant(); + return app('json')->success(formToData($this->repository->form((int)$merchant->type_id))); + } + + /** + * @param int $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function updateForm($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $merchant = $this->request->merchant(); + return app('json')->success(formToData($this->repository->updateForm((int)$merchant->type_id, $id))); + } + + /** + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-04-18 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->search($this->request->merId(), [], $page, $limit)); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-09 + */ + public function switchStatus($id) + { + $status = $this->request->param('status'); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, ['status' => $status == 1 ? 1 : 0]); + return app('json')->success('编辑成功'); + } + + /** + * @param int $id + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function delete($id) + { + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->delete($id); + return app('json')->success('删除成功'); + } + + /** + * @param RoleValidate $validate + * @return mixed + * @author xaboy + * @day 2020-04-18 + */ + public function create(RoleValidate $validate) + { + $data = $this->checkParam($validate); + $data['mer_id'] = $this->request->merId(); + + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + /** + * @param int $id + * @param RoleValidate $validate + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-04-18 + */ + public function update($id, RoleValidate $validate) + { + $data = $this->checkParam($validate); + if (!$this->repository->merExists($this->request->merId(), $id)) + return app('json')->fail('数据不存在'); + $this->repository->update($id, $data); + return app('json')->success('编辑成功'); + } + + /** + * @param RoleValidate $validate + * @return array + * @author xaboy + * @day 2020-04-18 + */ + private function checkParam(RoleValidate $validate) + { + $data = $this->request->params(['role_name', ['rules', []], ['status', 0]]); + $validate->check($data); + return $data; + } +} diff --git a/app/controller/merchant/system/financial/Financial.php b/app/controller/merchant/system/financial/Financial.php new file mode 100644 index 00000000..9ec70428 --- /dev/null +++ b/app/controller/merchant/system/financial/Financial.php @@ -0,0 +1,171 @@ + +// +---------------------------------------------------------------------- +namespace app\controller\merchant\system\financial; + +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\system\financial\FinancialRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\validate\merchant\MerchantFinancialAccountValidate; +use crmeb\basic\BaseController; +use crmeb\services\ExcelService; +use think\App; + +class Financial extends BaseController +{ + /** + * @var FinancialRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param FinancialRepository $repository + */ + public function __construct(App $app, FinancialRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + + /** + * TODO 转账信息Form + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/18/21 + */ + public function accountForm() + { + return app('json')->success(formToData($this->repository->financialAccountForm($this->request->merId()))); + } + + /** + * TODO 转账信息保存 + * @param MerchantFinancialAccountValidate $accountValidate + * @return \think\response\Json + * @author Qinii + * @day 3/18/21 + */ + public function accountSave(MerchantFinancialAccountValidate $accountValidate) + { + $data = $this->request->params(['account','financial_type','name','bank','bank_code','wechat','wechat_code','alipay','alipay_code']); //idcard + $accountValidate->check($data); + + $this->repository->saveAccount($this->request->merId(),$data); + return app('json')->success('保存成功'); + } + + /** + * TODO 申请转账form + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function createForm() + { + return app('json')->success(formToData($this->repository->applyForm($this->request->merId()))); + } + + /** + * TODO 申请转账保存 + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function createSave() + { + $data = $this->request->param(['extract_money','financial_type','mark']); + $data['mer_admin_id'] = $this->request->adminId(); + $this->repository->saveApply($this->request->merId(),$data); + return app('json')->success('保存成功'); + } + + public function refundMargin() + { + $this->repository->refundMargin($this->request->merId(), $this->request->adminId()); + return app('json')->success('申请提交成功'); + } + + /** + * TODO 列表 + * @author Qinii + * @day 3/19/21 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','status','financial_type','financial_status','keyword']); + $where['keywords_'] = $where['keyword']; + unset($where['keyword']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getAdminList($where,$page,$limit); + return app('json')->success($data); + } + + /** + * TODO 取消申请 + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function delete($id) + { + $this->repository->cancel($this->request->merId(),$id,['is_del' => 1]); + return app('json')->success('取消申请'); + } + + /** + * TODO + * @param $id + * @return \think\response\Json + * @author Qinii + * @day 3/19/21 + */ + public function detail($id) + { + $data = $this->repository->detail($id,$this->request->merId()); + if(!$data) return app('json')->fail('数据不存在'); + return app('json')->success($data); + } + + + public function markForm($id) + { + return app('json')->success(formToData($this->repository->markForm($id))); + } + + public function mark($id) + { + $ret = $this->repository->getWhere([$this->repository->getPk() => $id,'mer_id' => $this->request->merId()]); + + if(!$ret) return app('json')->fail('数据不存在'); + $data = $this->request->params(['mark']); + $this->repository->update($id,$data); + + return app('json')->success('备注成功'); + } + + public function export() + { + $where = $this->request->params(['date','status','financial_type','financial_status','keyword']); + $where['keywords_'] = $where['keyword']; + unset($where['keyword']); + $where['mer_id'] = $this->request->merId(); + + [$page, $limit] = $this->getPage(); + $data = app()->make(ExcelService::class)->financialLog($where,$page,$limit); + return app('json')->success($data); + + } +} diff --git a/app/controller/merchant/system/notice/SystemNoticeLog.php b/app/controller/merchant/system/notice/SystemNoticeLog.php new file mode 100644 index 00000000..97ad0804 --- /dev/null +++ b/app/controller/merchant/system/notice/SystemNoticeLog.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system\notice; + + +use app\common\repositories\system\notice\SystemNoticeLogRepository; +use crmeb\basic\BaseController; +use think\App; + +/** + * Class SystemNotice + * @package app\controller\merchant\system\notice + * @author xaboy + * @day 2020/11/6 + */ +class SystemNoticeLog extends BaseController +{ + /** + * @var SystemNoticeLogRepository + */ + protected $repository; + + /** + * SystemNoticeLog constructor. + * @param App $app + * @param SystemNoticeLogRepository $repository + */ + public function __construct(App $app, SystemNoticeLogRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return \think\response\Json + * @author xaboy + * @day 2020/11/6 + */ + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['is_read', 'date', 'keyword']); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * @param $id + * @author xaboy + * @day 2020/11/6 + */ + public function read($id) + { + $this->repository->read(intval($id), $this->request->merId()); + return app('json')->success(); + } + + public function del($id) + { + $this->repository->del(intval($id), $this->request->merId()); + return app('json')->success(); + } + + public function unreadCount() + { + return app('json')->success(['count' => $this->repository->unreadCount($this->request->merId())]); + } + +} diff --git a/app/controller/merchant/system/serve/Config.php b/app/controller/merchant/system/serve/Config.php new file mode 100644 index 00000000..369f3a17 --- /dev/null +++ b/app/controller/merchant/system/serve/Config.php @@ -0,0 +1,89 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system\serve; + +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use crmeb\basic\BaseController; +use app\common\repositories\system\merchant\MerchantRepository; +use think\App; +use think\facade\Cache; + +class Config extends BaseController +{ + /** + * @var ServeOrderRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param ServeOrderRepository $repository + */ + public function __construct(App $app, ServeOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function info() + { + $sms_info = Cache::get('serve_account'); + $mer_id = $this->request->merId(); + $ret = app()->make(MerchantRepository::class)->get($mer_id); + $data['mer_id'] = $ret['mer_id']; + $data = [ + 'info' =>$sms_info, + 'copy_product_status' => systemConfig('copy_product_status'), + 'copy_product_num' => $ret['copy_product_num'], + 'crmeb_serve_dump' => systemConfig('crmeb_serve_dump'), + 'export_dump_num' => $ret['export_dump_num'], + ]; + return app('json')->success($data); + } + + public function getConfig() + { + $merId = $this->request->merId(); + $config = [ + 'mer_from_com', + 'mer_from_name', + 'mer_from_tel', + 'mer_from_addr', + 'mer_config_siid', + 'mer_config_temp_id' + ]; + $data = merchantConfig($merId,$config); + return app('json')->success($data); + } + + public function setConfig() + { + $config = [ + 'mer_from_com', + 'mer_from_name', + 'mer_from_tel', + 'mer_from_addr', + 'mer_config_siid', + 'mer_config_temp_id' + ]; + $data = $this->request->params($config); + + app()->make(ConfigValueRepository::class)->setFormData($data,$this->request->merId()); + + return app('json')->success('保存成功'); + } + +} diff --git a/app/controller/merchant/system/serve/Serve.php b/app/controller/merchant/system/serve/Serve.php new file mode 100644 index 00000000..55a2c888 --- /dev/null +++ b/app/controller/merchant/system/serve/Serve.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\system\serve; + +use app\common\repositories\system\serve\ServeMealRepository; +use app\common\repositories\system\serve\ServeOrderRepository; +use crmeb\basic\BaseController; +use think\App; +use think\facade\Cache; + +class Serve extends BaseController +{ + /** + * @var ServeOrderRepository + */ + protected $repository; + + /** + * Merchant constructor. + * @param App $app + * @param ServeOrderRepository $repository + */ + public function __construct(App $app, ServeOrderRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getQrCode() + { + $sms_info = Cache::get('serve_account'); + if (!$sms_info) { + return app('json')->fail('平台未登录一号通'); + } + $data = $this->request->params(['meal_id','pay_type']); + $ret = $this->repository->QrCode($this->request->merId(),'meal', $data); + return app('json')->success($ret); + } + + public function meal() + { + $sms_info = Cache::get('serve_account'); + if (!$sms_info) { + return app('json')->fail('平台未登录一号通'); + } + + [$page, $limit] = $this->getPage(); + $type = $this->request->param( 'type','copy'); + + if ($type == 'copy' && systemConfig('copy_product_status') != 2) { + return app('json')->fail('平台未开启一号通商品复制'); + } + + if ($type == 'dump' && systemConfig('crmeb_serve_dump') != 1) { + return app('json')->fail('平台未开启一号通电子面单'); + } + + $where['type'] = $type == 'copy' ? 1 : 2; + $where['status'] = 1; + + $data = app()->make(ServeMealRepository::class)->getList($where, $page, $limit); + return app('json')->success($data); + } + + public function lst() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['status', 'type']); + $where['mer_id'] = $this->request->merId(); + $data = $this->repository->getList($where, $page, $limit); + return app('json')->success($data); + } + +} diff --git a/app/controller/merchant/user/LabelRule.php b/app/controller/merchant/user/LabelRule.php new file mode 100644 index 00000000..a3d2a351 --- /dev/null +++ b/app/controller/merchant/user/LabelRule.php @@ -0,0 +1,97 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\user; + + +use app\common\repositories\user\LabelRuleRepository; +use app\common\repositories\user\UserLabelRepository; +use app\validate\merchant\LabelRuleValidate; +use crmeb\basic\BaseController; +use think\App; +use think\exception\ValidateException; + +class LabelRule extends BaseController +{ + protected $repository; + + public function __construct(App $app, LabelRuleRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getList() + { + $where = $this->request->params(['keyword', 'type']); + $where['mer_id'] = $this->request->merId(); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + public function create() + { + $data = $this->checkParams(); + $data['mer_id'] = $this->request->merId(); + if (app()->make(UserLabelRepository::class)->existsName($data['label_name'], $data['mer_id'], 1)) + return app('json')->fail('标签名已存在'); + $this->repository->create($data); + return app('json')->success('添加成功'); + } + + public function update($id) + { + $data = $this->checkParams(); + $mer_id = $this->request->merId(); + if (!$label = $this->repository->getWhere(['label_rule_id' => $id, 'mer_id' => $mer_id])) + return app('json')->fail('数据不存在'); + if (app()->make(UserLabelRepository::class)->existsName($data['label_name'], $mer_id, 1, $label->label_id)) + return app('json')->fail('标签名已存在'); + $this->repository->update(intval($id), $data); + return app('json')->success('编辑成功'); + } + + public function delete($id) + { + if (!$this->repository->existsWhere(['label_rule_id' => $id, 'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $this->repository->delete(intval($id)); + return app('json')->success('删除成功'); + } + + public function sync($id) + { + if (!$this->repository->existsWhere(['label_rule_id' => $id, 'mer_id' => $this->request->merId()])) + return app('json')->fail('数据不存在'); + $this->repository->syncUserNum(intval($id)); + return app('json')->success('更新成功'); + + } + + /** + * @return array + * @author xaboy + * @day 2020/10/21 + */ + public function checkParams() + { + $data = $this->request->params(['label_name', 'min', 'max', 'type', 'data']); + app()->make(LabelRuleValidate::class)->check($data); + if (!$data['type']) { + if (false === filter_var($data['min'], FILTER_VALIDATE_INT) || false === filter_var($data['max'], FILTER_VALIDATE_INT)) { + throw new ValidateException('数值必须为整数'); + } + } + return $data; + } +} diff --git a/app/controller/merchant/user/User.php b/app/controller/merchant/user/User.php new file mode 100644 index 00000000..edd8caa7 --- /dev/null +++ b/app/controller/merchant/user/User.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\user; + +use crmeb\basic\BaseController; +use app\common\repositories\user\UserRepository; +use think\App; + +class User extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + public function getUserList() + { + $keyword = $this->request->param('keyword', ''); + if (!$keyword) + return app('json')->fail('请输入关键字'); + [$page, $limit] = $this->getPage(); + return app('json')->success($this->repository->merList($keyword, $page, $limit)); + } +} diff --git a/app/controller/merchant/user/UserIntegral.php b/app/controller/merchant/user/UserIntegral.php new file mode 100644 index 00000000..7aa1c57a --- /dev/null +++ b/app/controller/merchant/user/UserIntegral.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\user; + + +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserLabelRepository; +use app\common\repositories\user\UserMerchantRepository; +use crmeb\basic\BaseController; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class UserMerchant + * @package app\controller\merchant\user + * @author xaboy + * @day 2020/10/20 + */ +class UserIntegral extends BaseController +{ + protected $repository; + + public function __construct(App $app, UserBillRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * TODO 积分日志 + * @return \think\response\Json + * @author Qinii + * @day 6/9/21 + */ + public function getList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword', 'date']); + $where['category'] = 'mer_integral'; + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + /** + * TODO + * @return \think\response\Json + * @author Qinii + * @day 6/9/21 + */ + public function getTitle() + { + return app('json')->success($this->repository->getStat($this->request->merId())); + } + +} diff --git a/app/controller/merchant/user/UserMerchant.php b/app/controller/merchant/user/UserMerchant.php new file mode 100644 index 00000000..ce80d5d8 --- /dev/null +++ b/app/controller/merchant/user/UserMerchant.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- + + +namespace app\controller\merchant\user; + + +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\user\UserLabelRepository; +use app\common\repositories\user\UserMerchantRepository; +use crmeb\basic\BaseController; +use FormBuilder\Exception\FormBuilderException; +use think\App; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; + +/** + * Class UserMerchant + * @package app\controller\merchant\user + * @author xaboy + * @day 2020/10/20 + */ +class UserMerchant extends BaseController +{ + /** + * @var UserMerchantRepository + */ + protected $repository; + + /** + * UserMerchant constructor. + * @param App $app + * @param UserMerchantRepository $repository + */ + public function __construct(App $app, UserMerchantRepository $repository) + { + parent::__construct($app); + $this->repository = $repository; + } + + /** + * @return \think\response\Json + * @author xaboy + * @day 2020/10/20 + */ + public function getList() + { + $where = $this->request->params(['nickname', 'sex', 'is_promoter', 'user_time_type', 'user_time', 'pay_count', 'label_id', 'user_type']); + [$page, $limit] = $this->getPage(); + $where['mer_id'] = $this->request->merId(); + return app('json')->success($this->repository->getList($where, $page, $limit)); + } + + + /** + * @param $id + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws FormBuilderException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-08 + */ + public function changeLabelForm($id) + { + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + return app('json')->success(formToData($this->repository->changeLabelForm($this->request->merId(), $id))); + } + + + /** + * @param $id + * @param UserLabelRepository $labelRepository + * @return mixed + * @throws DbException + * @author xaboy + * @day 2020-05-08 + */ + public function changeLabel($id, UserLabelRepository $labelRepository) + { + $label_id = (array)$this->request->param('label_id', []); + if (!$this->repository->exists($id)) + return app('json')->fail('数据不存在'); + $merId = $this->request->merId(); + $label_id = $labelRepository->intersection((array)$label_id, $merId, 0); + $label_id = array_unique(array_merge($label_id, $this->repository->get($id)->authLabel)); + $label_id = implode(',', $label_id); + $this->repository->update($id, compact('label_id')); + return app('json')->success('修改成功'); + } + + public function order($uid) + { + [$page, $limit] = $this->getPage(); + $data = app()->make(StoreOrderRepository::class)->userMerList($uid, $this->request->merId(), $page, $limit); + return app('json')->success($data); + } + + public function coupon($uid) + { + [$page, $limit] = $this->getPage(); + $data = app()->make(StoreCouponUserRepository::class)->userList(['mer_id' => $this->request->merId(), 'uid' => (int)$uid], $page, $limit); + return app('json')->success($data); + } + +} diff --git a/app/controller/service/Common.php b/app/controller/service/Common.php new file mode 100644 index 00000000..aafbae4c --- /dev/null +++ b/app/controller/service/Common.php @@ -0,0 +1,41 @@ +request->merId(); + if ($merId) { + $merchant = app()->make(MerchantRepository::class)->get($merId); + $data = [ + 'mer_id' => $merchant['mer_id'], + 'avatar' => $merchant['mer_avatar'], + 'name' => $merchant['mer_name'], + ]; + } else { + $config = systemConfig(['site_logo', 'site_name','login_logo']); + $data = [ + 'mer_id' => 0, + 'avatar' => $config['login_logo'], + 'name' => $config['site_name'], + ]; + } + return app('json')->success($data); + } + + public function user() + { + $admin = $this->request->adminInfo(); + return app('json')->success($admin->hidden(['pwd', 'merchant'])->toArray()); + } + + public function config() + { + return app('json')->success(systemConfig(['site_name', 'site_logo', 'beian_sn'])); + } +} diff --git a/app/controller/service/Login.php b/app/controller/service/Login.php new file mode 100644 index 00000000..e99f8fd4 --- /dev/null +++ b/app/controller/service/Login.php @@ -0,0 +1,132 @@ +success(['timeout' => $timeout, 'key' => $key, 'qrcode' => $siteUrl . '/pages/chat/customer_login/index?key=' . $key]); + } + + public function checkScanLogin() + { + $key = (string)$this->request->param('key'); + if ($key) { + $uid = Cache::get('_scan_ser_login' . $key); + if ($uid) { + Cache::delete('_scan_ser_login' . $key); + $repository = app()->make(StoreServiceRepository::class); + $user = $repository->get($uid); + if (!$user) { + return app('json')->status(400, '登录失败'); + } + if (!$user['is_open']) + return app('json')->status(400, '登录失败'); + if (!$user['status']) + return app('json')->status(400, '登录失败'); + + $tokenInfo = $repository->createToken($user); + $user = $user->toArray(); + unset($user['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $user + ]; + return app('json')->status(200, $data); + } + } + return app('json')->status(201, '未登录'); + } + + public function login(StoreServiceRepository $repository) + { + $data = $this->request->params(['account', 'password', 'key', 'code']); +// if (Cache::get('ser_login_freeze_' . $data['account'])) +// return app('json')->fail('账号或密码错误次数太多,请稍后在尝试'); +// $repository->checkCode($data['key'], $data['code']); + + $service = $repository->getWhere(['account' => $data['account'], 'is_del' => 0]); + + if (!$service) { + return app('json')->fail('账号不存在'); + } + if (!$service['is_open']) + return app('json')->fail('账号未开启'); +// if (!$service['status']) +// return app('json')->fail('账号已被禁用'); + +// if (!password_verify($data['password'], $service['pwd'])) { +// return $this->loginFailure($data['account']); +// } + $tokenInfo = $repository->createToken($service); + $admin = $service->toArray(); + unset($admin['pwd']); + $data = [ + 'token' => $tokenInfo['token'], + 'exp' => $tokenInfo['out'], + 'admin' => $admin + ]; + + return app('json')->success($data); + } + + public function logout(StoreServiceRepository $repository) + { + if ($this->request->isLogin()) + $repository->clearToken($this->request->token()); + return app('json')->success('退出登录'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-04-09 + */ + public function getCaptcha(StoreServiceRepository $repository) + { + $codeBuilder = new CaptchaBuilder(null, new PhraseBuilder(4)); + $key = $repository->createLoginKey($codeBuilder->getPhrase()); + $captcha = $codeBuilder->build()->inline(); + return app('json')->success(compact('key', 'captcha')); + } + + /** + * TODO 登录尝试次数限制 + * @param $account + * @param int $number + * @param int $n + * @author Qinii + * @day 7/6/21 + */ + public function loginFailure($account, $number = 5, $n = 3) + { + $key = 'ser_login_failuree_' . $account; + $numb = Cache::get($key) ?? 0; + $numb++; + if ($numb >= $number) { + $fail_key = 'ser_login_freeze_' . $account; + Cache::set($fail_key, 1, 15 * 60); + return app('json')->fail('账号或密码错误次数太多,请稍后在尝试'); + } + Cache::set($key, $numb, 5 * 60); + $msg = '账号或密码错误'; + $_n = $number - $numb; + if ($_n <= $n) { + $msg .= ',还可尝试' . $_n . '次'; + } + return app('json')->fail($msg); + } +} diff --git a/app/controller/service/Service.php b/app/controller/service/Service.php new file mode 100644 index 00000000..e5e81b61 --- /dev/null +++ b/app/controller/service/Service.php @@ -0,0 +1,105 @@ +repository = $repository; + } + + public function serviceUserList() + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['keyword']); + $admin = $this->request->adminInfo(); + $where['service_id'] = $admin->service_id; + return app('json')->success($this->repository->serviceUserList($where, $admin->mer_id, $page, $limit)); + } + + public function mark($uid, StoreServiceUserRepository $serviceUserRepository, ExtendRepository $extendRepository) + { + $data = $this->request->params(['mark']); + $service = $this->request->adminInfo(); + if ($service->mer_id && !$serviceUserRepository->existsWhere(['uid' => (int)$uid, 'mer_id' => $service->mer_id])) { + return app('json')->fail('用户不存在'); + } + $extendRepository->updateInfo(ExtendRepository::TYPE_SERVICE_USER_MARK, (int)$uid, $service->mer_id, (string)$data['mark']); + return app('json')->success('备注成功'); + } + + public function history($uid, StoreServiceLogRepository $logRepository) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['last_id']); + $service = $this->request->adminInfo(); + return app('json')->success($logRepository->serviceList($service->mer_id, $service->service_id, (int)$uid, $page, $limit, $where['last_id'])); + } + + public function upload($field) + { + $file = $this->request->file($field); + if (!$file) return app('json')->fail('请上传图片'); + $upload = UploadService::create(); + $data = $upload->to('attach')->validate()->move($field); + if ($data === false) { + return app('json')->fail($upload->getError()); + } + return app('json')->success(['src' => tidy_url($upload->getFileInfo()->filePath)]); + } + + public function getOrderInfo($id) + { + return app('json')->success(app()->make(StoreOrderRepository::class)->getOne($id, null)); + } + + public function orderStatus($id) + { + [$page, $limit] = $this->getPage(); + $where = $this->request->params(['date','user_type']); + $where['id'] = $id; + return app('json')->success(app()->make(StoreOrderRepository::class)->getOrderStatus($where, $page, $limit)); + } + + public function getRefundOder($id) + { + $data = app()->make(StoreRefundOrderRepository::class)->getOne($id); + if (!$data) return app('json')->fail("数据不存在"); + return app('json')->success($data); + } + + public function orderExpress($id) + { + $make = app()->make(StoreOrderRepository::class); + return app('json')->success($make->express($id, null)); + } + + public function refundOrderExpress($id) + { + $make = app()->make(StoreRefundOrderRepository::class); + return app('json')->success($make->express($id)); + } + + + public function product($id) + { + $data = app()->make(ProductRepository::class)->getWhere(['product_id' => $id],'*',['content']); + return app('json')->success($data); + } + +} diff --git a/app/event.php b/app/event.php new file mode 100644 index 00000000..fe668017 --- /dev/null +++ b/app/event.php @@ -0,0 +1,70 @@ + +// +---------------------------------------------------------------------- + +// 事件定义文件 +return [ + 'bind' => [], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + 'swoole.task' => [\crmeb\listens\SwooleTaskListen::class], + 'swoole.init' => [ + \crmeb\listens\InitSwooleLockListen::class, + \crmeb\listens\CreateTimerListen::class, +// \crmeb\listens\QueueListen::class, + ], + 'swoole.workerStart' => [\app\webscoket\SwooleWorkerStart::class], + 'swoole.workerExit' => [\crmeb\listens\SwooleWorkerExitListen::class], + 'swoole.workerError' => [\crmeb\listens\SwooleWorkerExitListen::class], + 'swoole.workerStop' => [\crmeb\listens\SwooleWorkerExitListen::class], + 'create_timer' => env('INSTALLED', false) ? [ + \crmeb\listens\AutoOrderProfitsharingListen::class, + \crmeb\listens\AuthTakeOrderListen::class, + \crmeb\listens\AutoCancelGroupOrderListen::class, + \crmeb\listens\AuthCancelPresellOrderListen::class, + \crmeb\listens\AutoUnLockBrokerageListen::class, + \crmeb\listens\AutoSendPayOrderSmsListen::class, + \crmeb\listens\SyncSmsResultCodeListen::class, + \crmeb\listens\SyncBroadcastStatusListen::class, + \crmeb\listens\ExcelFileDelListen::class, + \crmeb\listens\RefundOrderAgreeListen::class, + \crmeb\listens\SeckillTImeCheckListen::class, + \crmeb\listens\AutoOrderReplyListen::class, + \crmeb\listens\ProductPresellStatusListen::class, + \crmeb\listens\ProductGroupStatusCheckListen::class, + \crmeb\listens\SyncSpreadStatusListen::class, + \crmeb\listens\GuaranteeCountListen::class, + \crmeb\listens\AutoUnLockIntegralListen::class, + \crmeb\listens\AutoClearIntegralListen::class, + \crmeb\listens\MerchantApplyMentsCheckListen::class, + \crmeb\listens\AutoUnlockMerchantMoneyListen::class, + \crmeb\listens\SumCountListen::class, + \crmeb\listens\SyncHotRankingListen::class, + \crmeb\listens\AuthCancelActivityListen::class, + \crmeb\listens\CloseUserSvipListen::class, + \crmeb\listens\SendSvipCouponListen::class, + ] : [], + 'pay_success_user_recharge' => [\crmeb\listens\pay\UserRechargeSuccessListen::class], + 'pay_success_user_order' => [\crmeb\listens\pay\UserOrderSuccessListen::class], + 'pay_success_order' => [\crmeb\listens\pay\OrderPaySuccessListen::class], + 'pay_success_micro_pay' => [\crmeb\listens\pay\OrderMicroPaySuccessListen::class], + 'pay_success_presell' => [\crmeb\listens\pay\PresellPaySuccessListen::class], + 'pay_success_meal' => [\crmeb\listens\pay\MealSuccessListen::class], + 'community_address'=>[\app\listener\CommunityAddress::class], + 'order.paySuccess'=>[\app\listener\OrderPaySuccess::class] + ], + + 'subscribe' => [], +]; diff --git a/app/event.php.bak b/app/event.php.bak new file mode 100644 index 00000000..f388f8aa --- /dev/null +++ b/app/event.php.bak @@ -0,0 +1,67 @@ + +// +---------------------------------------------------------------------- + +// 事件定义文件 +return [ + 'bind' => [], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + 'swoole.task' => [\crmeb\listens\SwooleTaskListen::class], + 'swoole.init' => [ + \crmeb\listens\InitSwooleLockListen::class, + \crmeb\listens\CreateTimerListen::class, +// \crmeb\listens\QueueListen::class, + ], + 'swoole.workerStart' => [\app\webscoket\SwooleWorkerStart::class], + 'swoole.workerExit' => [\crmeb\listens\SwooleWorkerExitListen::class], + 'swoole.workerError' => [\crmeb\listens\SwooleWorkerExitListen::class], + 'swoole.workerStop' => [\crmeb\listens\SwooleWorkerExitListen::class], + 'create_timer' => env('INSTALLED', false) ? [ + \crmeb\listens\AutoOrderProfitsharingListen::class, + \crmeb\listens\AuthTakeOrderListen::class, + \crmeb\listens\AutoCancelGroupOrderListen::class, + \crmeb\listens\AuthCancelPresellOrderListen::class, + \crmeb\listens\AutoUnLockBrokerageListen::class, + \crmeb\listens\AutoSendPayOrderSmsListen::class, + \crmeb\listens\SyncSmsResultCodeListen::class, + \crmeb\listens\SyncBroadcastStatusListen::class, + \crmeb\listens\ExcelFileDelListen::class, + \crmeb\listens\RefundOrderAgreeListen::class, + \crmeb\listens\SeckillTImeCheckListen::class, + \crmeb\listens\AutoOrderReplyListen::class, + \crmeb\listens\ProductPresellStatusListen::class, + \crmeb\listens\ProductGroupStatusCheckListen::class, + \crmeb\listens\SyncSpreadStatusListen::class, + \crmeb\listens\GuaranteeCountListen::class, + \crmeb\listens\AutoUnLockIntegralListen::class, + \crmeb\listens\AutoClearIntegralListen::class, + \crmeb\listens\MerchantApplyMentsCheckListen::class, + \crmeb\listens\AutoUnlockMerchantMoneyListen::class, + \crmeb\listens\SumCountListen::class, + \crmeb\listens\SyncHotRankingListen::class, + \crmeb\listens\AuthCancelActivityListen::class, + \crmeb\listens\CloseUserSvipListen::class, + \crmeb\listens\SendSvipCouponListen::class, + ] : [], + 'pay_success_user_recharge' => [\crmeb\listens\pay\UserRechargeSuccessListen::class], + 'pay_success_user_order' => [\crmeb\listens\pay\UserOrderSuccessListen::class], + 'pay_success_order' => [\crmeb\listens\pay\OrderPaySuccessListen::class], + 'pay_success_presell' => [\crmeb\listens\pay\PresellPaySuccessListen::class], + 'pay_success_meal' => [\crmeb\listens\pay\MealSuccessListen::class], + ], + + 'subscribe' => [], +]; diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 00000000..12950600 --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- + +// 全局中间件定义文件 +return [ + // 全局请求缓存 + // \think\middleware\CheckRequestCache::class, + // 多语言加载 + // \think\middleware\LoadLangPack::class, + // Session初始化 + // \think\middleware\SessionInit::class +]; diff --git a/app/provider.php b/app/provider.php new file mode 100644 index 00000000..9b78e02b --- /dev/null +++ b/app/provider.php @@ -0,0 +1,21 @@ + +// +---------------------------------------------------------------------- + + +use app\ExceptionHandle; +use app\Request; + +// 容器Provider定义文件 +return [ + 'think\Request' => Request::class, + 'think\exception\Handle' => ExceptionHandle::class, + 'json' => \crmeb\services\ApiResponseService::class, +]; diff --git a/app/service.php b/app/service.php new file mode 100644 index 00000000..9c1e7c19 --- /dev/null +++ b/app/service.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- + + +use app\AppService; + +// 系统服务定义文件 +// 服务在完成全局初始化之后执行 +return [ + AppService::class, +]; + diff --git a/app/validate/admin/AdminEditValidate.php b/app/validate/admin/AdminEditValidate.php new file mode 100644 index 00000000..5c3fe604 --- /dev/null +++ b/app/validate/admin/AdminEditValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class AdminEditValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'real_name|管理员姓名' => 'require|max:16', + 'phone|手机号' => 'max:12', + ]; + +} diff --git a/app/validate/admin/AdminValidate.php b/app/validate/admin/AdminValidate.php new file mode 100644 index 00000000..7719cd48 --- /dev/null +++ b/app/validate/admin/AdminValidate.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class AdminValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'account|账号' => 'require|max:16|min:4', + 'pwd|密码' => 'require|max:16|min:6', + 'phone|联系电话' => 'isPhone', + 'againPassword|确认密码' => 'require|max:16|min:6', + 'real_name|管理员姓名' => 'max:16', + 'roles|权限组' => 'require|array|min', + 'status|启用状态' => 'require|in:0,1', + ]; + + protected function isPhone($val) + { + if ($val && !preg_match('/^1[3456789]{1}\d{9}$/', $val)) + return '请输入正确的手机号'; + else + return true; + } + + public function isUpdate() + { + unset($this->rule['pwd|密码'], $this->rule['againPassword|确认密码']); + return $this; + } + + public function isPassword() + { + unset($this->rule['account|账号'], $this->rule['real_name|姓名'], $this->rule['roles|权限组'], $this->rule['status|启用状态'], $this->rule['phone|联系电话']); + return $this; + } +} diff --git a/app/validate/admin/ArticleCategoryValidate.php b/app/validate/admin/ArticleCategoryValidate.php new file mode 100644 index 00000000..80ac9626 --- /dev/null +++ b/app/validate/admin/ArticleCategoryValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class ArticleCategoryValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'pid|选择分类' => 'require|integer', + 'title|分类名称' => 'require|max:12', + 'info|分类简介' => 'max:255', + 'status|状态' => 'require|in:0,1', + 'image|分类图片' => 'max:128', + 'sort|排序' => 'require|integer' + ]; +} diff --git a/app/validate/admin/ArticleValidate.php b/app/validate/admin/ArticleValidate.php new file mode 100644 index 00000000..b0e38e83 --- /dev/null +++ b/app/validate/admin/ArticleValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + +use think\Validate; + +class ArticleValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'cid|选择分类' => 'require|integer', + 'title|标题' => 'require|max:32', + 'content|内容' => 'require', + 'author|作者' => 'require|max:32', + 'image_input|图片' => 'require|max:128', + 'is_hot|是否热门' => 'require|integer', + 'is_banner|是否为Banner' => 'require|integer' + ]; +} diff --git a/app/validate/admin/AttachmentCategoryValidate.php b/app/validate/admin/AttachmentCategoryValidate.php new file mode 100644 index 00000000..cca75421 --- /dev/null +++ b/app/validate/admin/AttachmentCategoryValidate.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class AttachmentCategoryValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'pid|选择分类' => 'require|integer', + 'attachment_category_name|分类名称' => 'require|max:16', + 'attachment_category_enname|分类目录' => 'require|alphaNum|max:16', + 'sort|排序' => 'require|integer' + ]; +} diff --git a/app/validate/admin/AttachmentValidate.php b/app/validate/admin/AttachmentValidate.php new file mode 100644 index 00000000..ced04d5b --- /dev/null +++ b/app/validate/admin/AttachmentValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class AttachmentValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'attachment_category_id|选择分类' => 'require|integer', + 'attachment_name|附件名称' => 'require|max:255', + 'attachment_src|分类目录' => 'require|max:255', + ]; +} diff --git a/app/validate/admin/CommunityTopicValidate.php b/app/validate/admin/CommunityTopicValidate.php new file mode 100644 index 00000000..4bb07c21 --- /dev/null +++ b/app/validate/admin/CommunityTopicValidate.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class CommunityTopicValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'category_id|选择分类' => 'require|integer', + 'topic_name|输入话题' => 'require|max:20', + 'is_hot|推荐' => 'in:0,1', + 'status|状态' => 'require|in:0,1', + ]; +} diff --git a/app/validate/admin/ConfigClassifyValidate.php b/app/validate/admin/ConfigClassifyValidate.php new file mode 100644 index 00000000..dec2da13 --- /dev/null +++ b/app/validate/admin/ConfigClassifyValidate.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class ConfigClassifyValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'pid|上级分类' => 'require|integer', + 'classify_name|配置分类名称' => 'require|max:20', + 'classify_key|配置分类key' => 'require|max:20', + 'info|配置分类说明' => 'max:30', + 'status|显示状态' => 'require|integer|in:0,1', + 'sort|排序' => 'require|integer', + 'icon|图标' => 'max:15' + ]; +} diff --git a/app/validate/admin/ConfigValidate.php b/app/validate/admin/ConfigValidate.php new file mode 100644 index 00000000..65974ea8 --- /dev/null +++ b/app/validate/admin/ConfigValidate.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class ConfigValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'config_classify_id|配置分类' => 'require|integer', + 'config_name|配置名称' => 'require|max:64', + 'config_key|配置key' => 'require|max:64', + 'config_type|配置类型' => 'require|max:15', + 'config_rule|配置规则' => 'max:250', + 'required|必填状态' => 'require|in:0,1', + 'info|配置说明' => 'max:255', + 'sort|排序' => 'require|integer', + 'status|状态' => 'require|in:0,1', + 'user_type|后台类型' => 'require|in:0,1' + ]; +} diff --git a/app/validate/admin/CrmebServeValidata.php b/app/validate/admin/CrmebServeValidata.php new file mode 100644 index 00000000..8e13f80c --- /dev/null +++ b/app/validate/admin/CrmebServeValidata.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\admin; + + +use think\Validate; + +class CrmebServeValidata extends Validate +{ + + protected $failException = true; + /** + * 定义验证规则 + * 格式:'字段名' => ['规则1','规则2'...] + * + * @var array + */ + protected $rule = [ + 'phone' => 'require|number|mobile', + 'password' => 'require', + 'verify_code' => 'require|number', + 'account' => 'require', + ]; + + /** + * 定义错误信息 + * 格式:'字段名.规则名' => '错误信息' + * + * @var array + */ + protected $message = [ + 'phone.require' => '请填写手机号码', + 'phone.number' => '您输入的手机号码必须为数字', + 'phone.mobile' => '您输入的手机号码有误', + 'password.require' => '密码必须填写', + 'verify_code.require' => '请填写短信验证码', + 'verify_code.number' => '短信验证码必须为数字', + 'account.require' => '请填写账号', + ]; + + protected $scene = [ + 'login' => ['password', 'account'], + 'phone' => ['phone'] + ]; +} diff --git a/app/validate/admin/ExpressValidata.php b/app/validate/admin/ExpressValidata.php new file mode 100644 index 00000000..0d59a15e --- /dev/null +++ b/app/validate/admin/ExpressValidata.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\admin; + + +use think\Validate; + +class ExpressValidata extends Validate +{ + /** + * 定义验证规则 + * 格式:'字段名' => ['规则1','规则2'...] + * + * @var array + */ + protected $rule = [ + 'com' => 'require', + 'temp_id' => 'require', + 'to_name' => 'require', + 'to_tel' => 'require|mobile', + 'to_address' => 'require', + 'siid' => 'require', + ]; + + /** + * 定义错误信息 + * 格式:'字段名.规则名' => '错误信息' + * + * @var array + */ + protected $message = [ + 'com.require' => '请选择快递公司', + 'temp_id.number' => '请选择快递模板', + 'to_name.require' => '请填写寄件人姓名', + 'to_tel.require' => '请输入寄件人手机号码', + 'to_tel.mobile' => '寄件人手机号码不正确', + 'to_address.require' => '请填写寄件人详细地址', + 'siid.require' => '请填写云打印机编号', + ]; +} diff --git a/app/validate/admin/GroupDataValidate.php b/app/validate/admin/GroupDataValidate.php new file mode 100644 index 00000000..9facc819 --- /dev/null +++ b/app/validate/admin/GroupDataValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class GroupDataValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'status|显示状态' => 'require|in:0,1', + 'sort|排序' => 'require|integer' + ]; +} diff --git a/app/validate/admin/GroupValidate.php b/app/validate/admin/GroupValidate.php new file mode 100644 index 00000000..ffd018c2 --- /dev/null +++ b/app/validate/admin/GroupValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class GroupValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'group_name|数据组名称' => 'require|max:32', + 'group_info|数据组说明' => 'max:128', + 'group_key|数据组key' => 'require|max:32', + 'fields|数据组字段' => 'require|array', + 'sort|排序' => 'require|integer', + 'user_type|后台类型' => 'require|in:0,1' + ]; +} diff --git a/app/validate/admin/GuaranteeTemplateValidate.php b/app/validate/admin/GuaranteeTemplateValidate.php new file mode 100644 index 00000000..28dd0522 --- /dev/null +++ b/app/validate/admin/GuaranteeTemplateValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + +use think\Validate; + +class GuaranteeTemplateValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'template_name|模板名称' => 'require', + 'template_value|保障服务条款' => 'require|array', + 'status|是否开启' => 'in:0,1', + ]; +} diff --git a/app/validate/admin/GuaranteeValidate.php b/app/validate/admin/GuaranteeValidate.php new file mode 100644 index 00000000..94c9c807 --- /dev/null +++ b/app/validate/admin/GuaranteeValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + +use think\Validate; + +class GuaranteeValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'guarantee_name|保障服务名称' => 'require', + 'guarantee_info|保障服务简介' => 'require', + 'image|图标' => 'require', + 'status|是否开启' => 'in:0,1', + ]; +} diff --git a/app/validate/admin/IntegralConfigValidate.php b/app/validate/admin/IntegralConfigValidate.php new file mode 100644 index 00000000..0f37b28d --- /dev/null +++ b/app/validate/admin/IntegralConfigValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class IntegralConfigValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'integral_status|积分开关' => 'require|in:0,1', + 'integral_clear_time|积分清除时间' => 'require|integer|>=:0', + 'integral_order_rate|下单赠送积分比例' => 'require|float|>=:0', + 'integral_freeze|下单赠送积分冻结期' => 'require|integer|>=:0', + 'integral_user_give|邀请好友赠送积分' => 'require|integer|>=:0', + 'integral_money|积分抵用金额' => 'require|float|>=:0', + ]; + +} diff --git a/app/validate/admin/LoginValidate.php b/app/validate/admin/LoginValidate.php new file mode 100644 index 00000000..481335a6 --- /dev/null +++ b/app/validate/admin/LoginValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class LoginValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'account|账号' => 'require|min:4|max:32', + 'password|密码' => 'require|min:6|max:16', + ]; +} diff --git a/app/validate/admin/MealValidata.php b/app/validate/admin/MealValidata.php new file mode 100644 index 00000000..784155a9 --- /dev/null +++ b/app/validate/admin/MealValidata.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\admin; + + +use think\Validate; + +class MealValidata extends Validate +{ + + protected $failException = true; + /** + * 定义验证规则 + * 格式:'字段名' => ['规则1','规则2'...] + * + * @var array + */ + protected $rule = [ + 'meal_id' => 'require|number', + 'price' => 'require|min:0', + 'num' => 'require|number|min:0', + 'type' => 'require', + ]; + + /** + * 定义错误信息 + * 格式:'字段名.规则名' => '错误信息' + * + * @var array + */ + protected $message = [ + 'meal_id.require' => '请传入套餐id', + 'meal_id.number' => '套餐id必须为数字', + 'price.require' => '请填写套餐金额', + 'num.require' => '请填写购买数量', + 'num.number' => '购买数量必须为数字', + 'type.require' => '请填写购买套餐类型' + ]; + + protected $scene = [ + 'create' => ['price','num','type'], + ]; + +} diff --git a/app/validate/admin/MenuValidate.php b/app/validate/admin/MenuValidate.php new file mode 100644 index 00000000..ee04ab10 --- /dev/null +++ b/app/validate/admin/MenuValidate.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class MenuValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'pid|选择父级分类' => 'require|integer|max:5', + 'icon|图标' => 'max:16', + 'menu_name|按钮名' => 'require|max:32', + 'route|菜单地址' => 'require|max:64', + 'sort|排序' => 'integer|max:3', + 'is_show|是否显示' => 'integer|in:0,1', + ]; + + public function isAuth() + { + unset($this->rule['icon|图标']); + unset($this->rule['is_show|是否显示']); + return $this; + } +} diff --git a/app/validate/admin/MerchantCategoryValidate.php b/app/validate/admin/MerchantCategoryValidate.php new file mode 100644 index 00000000..4fd0fa7d --- /dev/null +++ b/app/validate/admin/MerchantCategoryValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class MerchantCategoryValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'category_name|分类名称' => 'require|max:32', + 'commission_rate|手续费' => 'require|float|>=:0|<=:100' + ]; +} diff --git a/app/validate/admin/MerchantTypeValidate.php b/app/validate/admin/MerchantTypeValidate.php new file mode 100644 index 00000000..e02bd476 --- /dev/null +++ b/app/validate/admin/MerchantTypeValidate.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class MerchantTypeValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'type_name|店铺类型名称' => 'require|max:5', + 'type_info|店铺类型要求' => 'max:256', + 'is_margin|是否有保证金' => 'require|in:0,1', + 'auth|权限' => 'require|array|min:1', + 'margin|保证金(¥)' => 'requireIf:is_margin,1', + 'description|其他说明' => 'max:256', + ]; +} diff --git a/app/validate/admin/MerchantValidate.php b/app/validate/admin/MerchantValidate.php new file mode 100644 index 00000000..f24d74a8 --- /dev/null +++ b/app/validate/admin/MerchantValidate.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +/** + * Class MerchantValidate + * @package app\validate\admin + * @author xaboy + * @day 2020-04-17 + */ +class MerchantValidate extends Validate +{ + /** + * @var bool + */ + protected $failException = true; + + /** + * @var array + */ + protected $rule = [ + 'category_id|商户分类' => 'require', + 'type_id|店铺类型' => 'integer', + 'mer_name|商户名称' => 'require|max:32', + 'mer_account|商户账号' => 'require|alphaNum|min:4|max:16', + 'mer_password|商户密码' => 'require|min:4|max:16', + 'real_name|商户姓名' => 'max:16', + 'mer_phone|商户手机号' => 'require', + 'sort|排序' => 'require', + 'mer_keyword|商户关键字' => 'max:64', + 'mer_address|商户地址' => 'max:64', + 'mark|备注' => 'max:64', + 'status|开启状态' => 'require|in:0,1', + 'is_audit|产品审核状态' => 'require|in:0,1', + 'is_best|推荐状态' => 'require|in:0,1', + 'is_bro_goods|直播商品状态' => 'require|in:0,1', + 'is_bro_room|直播间状态' => 'require|in:0,1', + 'is_trader|自营状态' => 'require|in:0,1', + 'commission_rate|提成比例' => '>=:0' + ]; + + /** + * @return $this + * @author xaboy + * @day 2020-04-17 + */ + public function isUpdate() + { + unset($this->rule['mer_account|商户账号'], $this->rule['mer_password|商户密码'], $this->rule['status|开启状态']); + return $this; + } +} diff --git a/app/validate/admin/ParameterTemplateValidate.php b/app/validate/admin/ParameterTemplateValidate.php new file mode 100644 index 00000000..be706db8 --- /dev/null +++ b/app/validate/admin/ParameterTemplateValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class ParameterTemplateValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'template_name|模板名称' => 'require|max:25', + 'params|参数' => 'require|array', + ]; +} + diff --git a/app/validate/admin/PriceRuleValidate.php b/app/validate/admin/PriceRuleValidate.php new file mode 100644 index 00000000..617ff2b3 --- /dev/null +++ b/app/validate/admin/PriceRuleValidate.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\admin; + + +use think\Validate; + +class PriceRuleValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'rule_name|名称' => 'require|max:32', + 'cate_id|分类' => 'array', + 'sort|排序' => 'require|integer', + 'is_show|是否显示' => 'require|in:0,1', + 'content|价格说明详情' => 'require', + ]; + +} diff --git a/app/validate/admin/ProductLabelValidate.php b/app/validate/admin/ProductLabelValidate.php new file mode 100644 index 00000000..26c3ddb8 --- /dev/null +++ b/app/validate/admin/ProductLabelValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class ProductLabelValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'label_name|标签名称' => 'require|max:6', + 'info|说明' => 'max:32', + 'sort|排序' => 'integer|min:0' + ]; +} diff --git a/app/validate/admin/RoleValidate.php b/app/validate/admin/RoleValidate.php new file mode 100644 index 00000000..3e8cda69 --- /dev/null +++ b/app/validate/admin/RoleValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class RoleValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'role_name|管理名称' => 'require|max:32', + 'rules|权限' => 'require|array|min:1', + 'status|是否启用' => 'require', + ]; +} diff --git a/app/validate/admin/SmsRegisterValidate.php b/app/validate/admin/SmsRegisterValidate.php new file mode 100644 index 00000000..de2f48a8 --- /dev/null +++ b/app/validate/admin/SmsRegisterValidate.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class SmsRegisterValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'account|账号' => 'require', + 'password|密码' => 'require', + 'phone|手机号' => 'require|isPhone', + 'code|验证码' => 'require', + 'url|域名' => 'require|url', + 'sign|短信签名' => 'require|max:8' + ]; + + protected function isPhone($val) + { + if (!preg_match('/^1[3456789]{1}\d{9}$/', $val)) + return '请输入正确的手机号'; + else + return true; + } + + public function isLogin() + { + unset($this->rule['phone|手机号'], $this->rule['code|验证码'], $this->rule['url|域名'], $this->rule['sign|短信签名']); + return $this; + } +} diff --git a/app/validate/admin/StoreActivityValidate.php b/app/validate/admin/StoreActivityValidate.php new file mode 100644 index 00000000..e3e3bc5f --- /dev/null +++ b/app/validate/admin/StoreActivityValidate.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class StoreActivityValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "activity_name|活动名称" => 'require', + "start_time|开始时间" => "require", + "end_time|结束时间" => "require|checkEndTime", + ]; + + protected function checkEndTime($value) + { + if (strtotime($value) <= time()) { + return '结束时间必须大于当前时间'; + } + return true; + } +} diff --git a/app/validate/admin/StoreBrandCategoryValidate.php b/app/validate/admin/StoreBrandCategoryValidate.php new file mode 100644 index 00000000..8769e878 --- /dev/null +++ b/app/validate/admin/StoreBrandCategoryValidate.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class StoreBrandCategoryValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'pid|上级分类' => 'require|integer', + 'cate_name|分类名称' => 'require|max:12', + 'is_show|状态' => 'require|in:0,1', + 'sort|排序' => 'require|integer' + ]; +} diff --git a/app/validate/admin/StoreBrandValidate.php b/app/validate/admin/StoreBrandValidate.php new file mode 100644 index 00000000..3680846f --- /dev/null +++ b/app/validate/admin/StoreBrandValidate.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class StoreBrandValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'brand_category_id|上级分类' => 'require|integer', + 'brand_name|名称' => 'require|max:32', + 'is_show|状态' => 'require|in:0,1', + 'sort|排序' => 'require|integer', + 'pic|图标' => 'max:128' + ]; +} diff --git a/app/validate/admin/StoreCategoryValidate.php b/app/validate/admin/StoreCategoryValidate.php new file mode 100644 index 00000000..8e19d1ad --- /dev/null +++ b/app/validate/admin/StoreCategoryValidate.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class StoreCategoryValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'pid|上级分类' => 'require|integer', + 'cate_name|分类名称' => 'require|max:12', + 'is_show|状态' => 'require|in:0,1', + 'pic|分类图标' => 'max:128', + 'sort|排序' => 'require|integer' + ]; +} diff --git a/app/validate/admin/StoreProductReplyValidate.php b/app/validate/admin/StoreProductReplyValidate.php new file mode 100644 index 00000000..501e100d --- /dev/null +++ b/app/validate/admin/StoreProductReplyValidate.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class StoreProductReplyValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'product_id|商品' => 'require|array|min:1', + 'nickname|用户昵称' => 'require|max:20', + 'comment|评论' => 'require|max:128', + 'product_score|商品分数' => 'require|integer|max:5', + 'service_score|服务分数' => 'require|integer|max:5', + 'postage_score|物流分数' => 'require|integer|max:5', + 'avatar|用户头像' => 'require', + 'pics|评价图片' => 'array|max:6', + ]; +} diff --git a/app/validate/admin/StoreSeckillValidate.php b/app/validate/admin/StoreSeckillValidate.php new file mode 100644 index 00000000..206787fb --- /dev/null +++ b/app/validate/admin/StoreSeckillValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class StoreSeckillValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'start_time|开始时间' => 'require|number|between:0,24', + 'end_time|结束时间' => 'require|number|between:0,24|>:start_time', + 'status|状态' => 'require|in:0,1', + ]; +} diff --git a/app/validate/admin/SystemNoticeConfigValidate.php b/app/validate/admin/SystemNoticeConfigValidate.php new file mode 100644 index 00000000..cdfd8ffe --- /dev/null +++ b/app/validate/admin/SystemNoticeConfigValidate.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class SystemNoticeConfigValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'notice_title|通知名称' => 'require', + 'notice_key|消息键名称' => 'require', + 'notice_info|消息说明' => 'max:50', + 'notice_sys|站内消息' => 'in:0,1,-1', + 'notice_wechat|公众号模板消息' => 'in:0,1,-1', + 'notice_routine|小程序订阅消息' => 'in:0,1,-1', + 'notice_sms|短信消息' => 'in:0,1,-1' + ]; + +} diff --git a/app/validate/admin/SystemNoticeValidate.php b/app/validate/admin/SystemNoticeValidate.php new file mode 100644 index 00000000..56a7518a --- /dev/null +++ b/app/validate/admin/SystemNoticeValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class SystemNoticeValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'type|商户类型' => 'require|in:1,2,3,4', + 'mer_id|商户' => 'requireIf:type,1|array', + 'is_trader|自营类型' => 'requireIf:type,2|in:0,1', + 'category_id|商户分类' => 'requireIf:type,3|array', + 'notice_title|公告标题' => 'require|max:100', + 'notice_content|公告内容' => 'require|max:800', + ]; +} diff --git a/app/validate/admin/TemplateMessageValidate.php b/app/validate/admin/TemplateMessageValidate.php new file mode 100644 index 00000000..b7e14180 --- /dev/null +++ b/app/validate/admin/TemplateMessageValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\admin; + +use think\Validate; + +class TemplateMessageValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'tempkey|模板编号' => 'require', + 'name|模板名' => 'require', + 'tempid|模板ID' => 'require', + 'content|回复内容' => 'require', + 'status|状态' => 'require', + ]; +} diff --git a/app/validate/admin/UserBrokerageValidate.php b/app/validate/admin/UserBrokerageValidate.php new file mode 100644 index 00000000..cf0280db --- /dev/null +++ b/app/validate/admin/UserBrokerageValidate.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use app\common\repositories\user\UserBrokerageRepository; +use think\Validate; + +class UserBrokerageValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'brokerage_level|会员等级' => 'require|integer|>:0', + 'brokerage_name|会员名称' => 'require|max:16', + 'brokerage_icon|会员图标' => 'require', + 'brokerage_rule|会员升级规则' => 'requireIf:type,0|array|checkBrokerageRule', + 'extension_one|一级佣金比例' => 'requireIf:type,0|float|>=:0|<=:100', + 'extension_two|二级佣金比例' => 'requireIf:type,0|float|>=:0|<=:100', + 'image|背景图' => 'requireIf:type,1|max:128', + 'value|会员成长值' => 'requireIf:type,1|float|>=:0', + 'type|类型' => 'require|in:0,1', + ]; + + public function checkBrokerageRule($value, $rlue, $data) + { + if (!$data['type']) { + $types = UserBrokerageRepository::BROKERAGE_RULE_TYPE; + if (count($types) != count($value)) { + return '请输入正确的升级任务'; + } + $flag = 0; + foreach ($types as $type) { + $val = $value[$type] ?? ''; + if (!is_array($val) || !isset($val['name'], $val['num'], $val['info']) || count($val) != 3) return '请输入正确的升级任务'; + if ($val['num'] < 0) + return '请输入正确的任务数量'; + if ($val['num'] > 0 && !$val['name']) return '请输入任务名称'; + if ($val['num'] > 0) $flag++; + } + if (!$flag) return '请至少设置一个升级任务'; + } + + return true; + } +} diff --git a/app/validate/admin/UserGroupValidate.php b/app/validate/admin/UserGroupValidate.php new file mode 100644 index 00000000..13ce4bc8 --- /dev/null +++ b/app/validate/admin/UserGroupValidate.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class UserGroupValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'group_name|分组名称' => 'require|max:32' + ]; +} diff --git a/app/validate/admin/UserLabelValidate.php b/app/validate/admin/UserLabelValidate.php new file mode 100644 index 00000000..395d5040 --- /dev/null +++ b/app/validate/admin/UserLabelValidate.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class UserLabelValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'label_name|标签名称' => 'require|max:32' + ]; +} diff --git a/app/validate/admin/UserNowMoneyValidate.php b/app/validate/admin/UserNowMoneyValidate.php new file mode 100644 index 00000000..c8934254 --- /dev/null +++ b/app/validate/admin/UserNowMoneyValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class UserNowMoneyValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'now_money|余额' => 'require|float|>=:0', + 'type|修改类型' => 'require|in:0,1' + ]; +} diff --git a/app/validate/admin/UserValidate.php b/app/validate/admin/UserValidate.php new file mode 100644 index 00000000..235d5618 --- /dev/null +++ b/app/validate/admin/UserValidate.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +class UserValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'real_name|真实姓名' => 'max:25', + 'phone|手机号' => 'isPhone', + 'birthday|生日' => 'dateFormat:Y-m-d', + 'card_id|身份证' => 'length:18', + 'addres|用户地址' => 'max:64', + 'mark|备注' => 'max:200', + 'group_id|分组' => 'integer', + 'label_id|标签' => 'array', + 'is_promoter|推广人' => 'in:0,1', + 'status|推广人' => 'in:0,1' + ]; + + protected function isPhone($val) + { + if (!preg_match('/^1[3456789]{1}\d{9}$/', $val)) + return '请输入正确的手机号'; + else + return true; + } + + protected function sceneCreate() + { + return $this->append('account','require|unique:user,account|max:16|min:5') + ->append('pwd','require') + ->append('repwd','require|confirm:pwd') + ->append('sex','in:0,1,2'); + } + + protected $message = [ + 'account.require' => '账号必填', + 'account.unique' => '账号已经存在', + 'account.min' => '账号最小长度为5', + 'account.max' => '账号最大长度为16', + 'pwd.require' => '密码必填', + 'repwd.require' => '确认密码必填', + 'repwd.confirm' => '密码不一致', + ]; +} diff --git a/app/validate/admin/WechatNewsValidate.php b/app/validate/admin/WechatNewsValidate.php new file mode 100644 index 00000000..9c81dd04 --- /dev/null +++ b/app/validate/admin/WechatNewsValidate.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + +use think\Validate; + +class WechatNewsValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'data' => 'array|checkArray', +// 'title|标题' => 'require', +// 'author|作者' => 'require', +// 'synopsis|摘要' => 'require', +// 'image_input|图片' => 'require', +// 'content|内容' => 'require', + ]; + + + + protected function checkArray($value,$rule,$data = []) + { + foreach ($value as $v) { + if(empty($v['title'])) + return '标题不能为空'; + if(empty($v['author'])) + return '作者不能为空'; + if(empty($v['synopsis'])) + return '摘要不能为空'; + if(empty($v['image_input'])) + return '图片不能为空'; + if(empty($v['content'])) + return '内容不能为空'; + } + return true; + } + + +} diff --git a/app/validate/admin/WechatReplyValidate.php b/app/validate/admin/WechatReplyValidate.php new file mode 100644 index 00000000..63dcae55 --- /dev/null +++ b/app/validate/admin/WechatReplyValidate.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\admin; + + +use think\Validate; + +/** + * Class WechatReplyValidate + * @package app\validate\admin + * @author xaboy + * @day 2020-04-27 + */ +class WechatReplyValidate extends Validate +{ + /** + * @var bool + */ + protected $failException = true; + + /** + * @var array + */ + protected $rule = [ + 'type|类型' => 'require|in:text,image,news,voice', + 'key|关键字' => 'require|max:32', + 'data|回复内容' => 'require|array', + 'status|开启状态' => 'require|in:0,1' + ]; + + /** + * @return $this + * @author xaboy + * @day 2020-04-27 + */ + public function isUpdate() + { + unset($this->rule['key|关键字']); + return $this; + } +} diff --git a/app/validate/api/BackGoodsValidate.php b/app/validate/api/BackGoodsValidate.php new file mode 100644 index 00000000..483b2e80 --- /dev/null +++ b/app/validate/api/BackGoodsValidate.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + + +use think\Validate; + +class BackGoodsValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'delivery_type|快递公司' => 'require', + 'delivery_id|快递单号' => 'require', + 'delivery_phone|联系电话' => 'require|mobile', + 'delivery_mark|备注' => 'max:128', + 'delivery_pics|凭证' => 'array|max:9', + ]; +} diff --git a/app/validate/api/ChangePasswordValidate.php b/app/validate/api/ChangePasswordValidate.php new file mode 100644 index 00000000..b11fd3ec --- /dev/null +++ b/app/validate/api/ChangePasswordValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + + +use think\Validate; + +class ChangePasswordValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'phone|手机号' => 'require|mobile', + 'pwd|密码' => 'require|min:6', + 'sms_code|短信验证码' => 'require|max:4', + ]; +} diff --git a/app/validate/api/CommunityValidate.php b/app/validate/api/CommunityValidate.php new file mode 100644 index 00000000..fd6974f1 --- /dev/null +++ b/app/validate/api/CommunityValidate.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class CommunityValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'image|图片' => 'require|array', + 'content|内容' => 'require|max:600', + 'spu_id|关联商品' => 'array', + ]; + +} diff --git a/app/validate/api/FeedbackValidate.php b/app/validate/api/FeedbackValidate.php new file mode 100644 index 00000000..e97eea80 --- /dev/null +++ b/app/validate/api/FeedbackValidate.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class FeedbackValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'type|类型' => 'require', + 'images|图片' => 'array|max:6', + 'realname|姓名' => 'require|>:1', + 'contact|联系方式' => 'require|checkContact' + ]; + + protected function checkContact($val) + { + if ($this->regex($val, 'mobile') || $this->filter($val, 'email')) + return true; + else + return '请输入正确的联系方式'; + } +} diff --git a/app/validate/api/MerchantIntentionValidate.php b/app/validate/api/MerchantIntentionValidate.php new file mode 100644 index 00000000..e3d1e81d --- /dev/null +++ b/app/validate/api/MerchantIntentionValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + + +use think\Validate; + +class MerchantIntentionValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'phone|手机号' => 'require|mobile', + 'name|姓名' => 'require', + 'mer_name|姓名' => 'require|max:32', + 'merchant_category_id|商户分类' => 'require', + 'mer_type_id|店铺类型' => 'integer', + 'code|验证码' => 'require', + 'images|资质' => 'array', + ]; +} diff --git a/app/validate/api/OrderVirtualFieldValidate.php b/app/validate/api/OrderVirtualFieldValidate.php new file mode 100644 index 00000000..73b8dd1a --- /dev/null +++ b/app/validate/api/OrderVirtualFieldValidate.php @@ -0,0 +1,103 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class OrderVirtualFieldValidate extends Validate +{ + protected $failException = true; + + protected $rule = []; + + public function load(array $extend, array $value) + { + $extend = array_combine(array_column($extend, 'title'), $extend); + $rule = []; + foreach ($extend as $title => $val) { + $item = []; + if ($val['key'] === 'image') { + if ($val['require']) { + $item[] = 'isRequireImage'; + } else { + $item[] = 'isImage'; + } + + } else { + if ($val['require']) { + $item[] = 'require'; + } + $item[] = 'is' . ucfirst($val['key']); + } + $rule[$title.' '] = implode('|', $item); + } + $this->rule = $rule; + $data = []; + foreach ($value as $v) { + $data[(string)$v['title'].' '] = $v['value'] ?? ''; + } + $this->check($data); + return $data; + } + + public function isMobile($val) + { + return $this->regex($val, 'mobile'); + } + + public function isDate($val) + { + return $this->dateFormat($val, 'Y-m-d'); + } + + public function isTime($val) + { + return $this->dateFormat($val, 'H:i'); + } + + public function isRequireImage($val) + { + if (!count($val)) return false; + foreach ($val as $v) { + if (!is_string($v)) return false; + } + return true; + } + + public function isImage($val) + { + if (!count($val)) return true; + return $this->isRequireImage($val); + } + + public function isEmail($val) + { + return $this->filter($val, FILTER_VALIDATE_EMAIL); + } + + public function isNumber($val) + { + return ctype_digit((string)$val); + } + + public function isText($val) + { + return (bool)trim((string)$val); + } + + public function isIdCard($val) + { + return $this->regex($val, 'idCard'); + } +} diff --git a/app/validate/api/ProductReplyValidate.php b/app/validate/api/ProductReplyValidate.php new file mode 100644 index 00000000..2b13e1dd --- /dev/null +++ b/app/validate/api/ProductReplyValidate.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + + +use think\Validate; + +class ProductReplyValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'comment|评论' => 'require|max:128', + 'product_score|商品分数' => 'require|integer|max:5', + 'service_score|服务分数' => 'require|integer|max:5', + 'postage_score|物流分数' => 'require|integer|max:5', + 'pics|评价图片' => 'array|max:6', + ]; + + protected $message = [ + 'pics.max' => '评价最多上传6张图片' + ]; +} diff --git a/app/validate/api/StoreCartValidate.php b/app/validate/api/StoreCartValidate.php new file mode 100644 index 00000000..f0047826 --- /dev/null +++ b/app/validate/api/StoreCartValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class StoreCartValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'product_id|商品ID' => 'require', + 'product_attr_unique|SKU' => 'require', + 'cart_num|购买数量' => 'require|integer|>:0', + ]; +} diff --git a/app/validate/api/StoreRefundOrderValidate.php b/app/validate/api/StoreRefundOrderValidate.php new file mode 100644 index 00000000..349e3628 --- /dev/null +++ b/app/validate/api/StoreRefundOrderValidate.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + + +use think\Validate; + +class StoreRefundOrderValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'type|退款类型' => 'require|in:1,2', + 'refund_type|退款方式' => 'require|in:1,2', + 'num|商品件数' => 'requireIf:type,1|integer|>:0', + 'ids|退款商品' => 'require', + 'refund_message|退款原因' => 'require|max:128', + 'mark|备注' => 'max:128', + 'refund_price|退款金额' => 'require|float|>=:0', + 'pics|凭证' => 'array|max:9', + ]; +} diff --git a/app/validate/api/UserAddressValidate.php b/app/validate/api/UserAddressValidate.php new file mode 100644 index 00000000..cb8089e7 --- /dev/null +++ b/app/validate/api/UserAddressValidate.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class UserAddressValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'real_name|收货人姓名' => 'require', + 'phone|收货人电话' => 'require|alphaDash|mobile', + 'area|收货信息' => 'require|array|min:3|checkArea', + 'detail|收货人详细地址' => 'require', + ]; + + protected $scene = [ + 'take' => ['real_name', 'phone'] + ]; + + public function checkArea($list) + { + foreach ($list as $item) { + if (!isset($item['name'], $item['id'])) + return '请选择正确的收货地址'; + } + return true; + } +} diff --git a/app/validate/api/UserAuthValidate.php b/app/validate/api/UserAuthValidate.php new file mode 100644 index 00000000..e7fa52e6 --- /dev/null +++ b/app/validate/api/UserAuthValidate.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class UserAuthValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'phone|手机号' => 'require|mobile', + 'pwd|密码' => 'require|min:6', + 'sms_code|短信验证码' => 'require|max:4', + ]; + + + public function scenePwdlogin() + { + return $this->remove('sms_code','require|max:4'); + } + + public function sceneSmslogin() + { + return $this->remove('pwd','require|min:6'); + } + + public function sceneVerify() + { + return $this->remove('pwd','require|min:6') + ->remove('sms_code','require|max:4'); + } +} diff --git a/app/validate/api/UserBaseInfoValidate.php b/app/validate/api/UserBaseInfoValidate.php new file mode 100644 index 00000000..f48173da --- /dev/null +++ b/app/validate/api/UserBaseInfoValidate.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + + +use think\Validate; + +class UserBaseInfoValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'nickname|昵称' => 'require|max:8' + ]; + + protected $message = [ + 'nickname.max' => '昵称最多8个字符' + ]; +} diff --git a/app/validate/api/UserExtractValidate.php b/app/validate/api/UserExtractValidate.php new file mode 100644 index 00000000..f558ebe1 --- /dev/null +++ b/app/validate/api/UserExtractValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class UserExtractValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'wechat|微信号' => 'requireIf:extract_type,1', + 'real_name|姓名' => 'requireIf:extract_type,0', + 'bank_code|银行卡号' => 'requireIf:extract_type,0|number', + 'extract_type|收款方式' => 'require', + 'extract_price|提现金额' => 'require|gt:0', + 'alipay_code|支付宝账户' => 'requireIf:extract_type,2', + ]; + +} diff --git a/app/validate/api/UserReceiptValidate.php b/app/validate/api/UserReceiptValidate.php new file mode 100644 index 00000000..6eb8b60c --- /dev/null +++ b/app/validate/api/UserReceiptValidate.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\api; + +use think\Validate; + +class UserReceiptValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'receipt_type|发票类型' => 'require|in:1,2', + 'receipt_title|发票抬头' => 'require', + 'receipt_title_type|发票抬头类型' => 'require|in:1,2', + 'duty_paragraph|税号' => 'requireIf:receipt_title_type,2|alphaNum', + 'email|邮箱' => 'requireIf:receipt_type,1|email', + 'bank_name|开户行' => 'requireIf:receipt_type,2', + 'bank_code|银行卡号' => 'requireIf:receipt_type,2|number', + 'address|企业地址' => 'requireIf:receipt_type,2', + 'tel|企业电话' => 'requireIf:receipt_type,2', + ]; + +} diff --git a/app/validate/merchant/BroadcastGoodsValidate.php b/app/validate/merchant/BroadcastGoodsValidate.php new file mode 100644 index 00000000..4ac5afa1 --- /dev/null +++ b/app/validate/merchant/BroadcastGoodsValidate.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class BroadcastGoodsValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'name|商品名称' => 'require|min:3|max:14', + 'cover_img|商品图' => 'require', + 'price|价格' => 'require|min:0.01', + 'product_id|商品' => 'require|array|length:2', + ]; + + public function isBatch() + { + $this->rule['product_id|商品'] = 'require|integer'; + return $this; + } +} diff --git a/app/validate/merchant/BroadcastRoomValidate.php b/app/validate/merchant/BroadcastRoomValidate.php new file mode 100644 index 00000000..13539177 --- /dev/null +++ b/app/validate/merchant/BroadcastRoomValidate.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class BroadcastRoomValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'name|直播间名字' => 'require|min:3|max:17', + 'cover_img|背景图' => 'require', + 'share_img|分享图' => 'require', + 'anchor_name|主播昵称' => 'require|min:4|max:15', + 'anchor_wechat|主播微信号' => 'require', + 'phone|联系电话' => 'require|mobile', + 'start_time|直播时间' => 'require|array|length:2|checkTime', + 'type|直播间类型' => 'require|in:0,1', + 'screen_type|显示样式' => 'require|in:0,1', + 'close_like|是否开启点赞' => 'require|in:0,1', + 'close_goods|是否开启货架' => 'require|in:0,1', + 'close_comment|是否开启评论' => 'require|in:0,1', + 'replay_status|是否开启回放' => 'require|in:0,1', + 'close_share|是否开启分享' => 'require|in:0,1', + 'close_kf|是否开启客服' => 'require|in:0,1', + ]; + + protected function checkTime($value) + { + $start = strtotime($value[0]); + $end = strtotime($value[1]); + if ($end < $start) return '请选择正确的直播时间'; + if ($start < strtotime('+ 15 minutes')) return '开播时间必须大于当前时间15分钟'; + if ($start >= strtotime('+ 6 month')) return '开播时间不能在6个月后'; + if (($end - $start) < (60 * 30)) return '直播时间不得小于30分钟'; + if (($end - $start) > (60 * 60 * 24)) return '直播时间不得超过24小时'; + return true; + } +} diff --git a/app/validate/merchant/DeliveryStationValidate.php b/app/validate/merchant/DeliveryStationValidate.php new file mode 100644 index 00000000..997a1f02 --- /dev/null +++ b/app/validate/merchant/DeliveryStationValidate.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class DeliveryStationValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'station_name|门店名称' => 'require', + 'business|支持配送的物品品类' => 'require|number', + 'station_address|门店地址' => 'require', + 'city_name|所属城市' => 'require', + 'lng|门店经度' => 'require', + 'lat|门店纬度' => 'require', + 'contact_name|联系人姓名' => 'require', + 'phone|联系人电话' => 'require|mobile', + ]; + + public function sceneDada() + { + return $this->append('username','require|mobile') + ->append('password','require'); + } + + public $message = [ + 'username.mobile' => '达达账号必须是手机号', + 'username.require'=> '达达账号必须填写', + 'password' => '达达密码必须填写', + ]; +} diff --git a/app/validate/merchant/LabelRuleValidate.php b/app/validate/merchant/LabelRuleValidate.php new file mode 100644 index 00000000..f4c93ee9 --- /dev/null +++ b/app/validate/merchant/LabelRuleValidate.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class LabelRuleValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'type|规则类型' => 'require|in:0,1', + 'min|最小值' => 'require|float|>=:0', + 'max|最大值' => 'require|float|>=:min', + 'label_name|标签名' => 'require|length:2,10' + ]; + + protected $message = [ + 'max.egt' => '最大值必须大于等于最小值', + ]; +} diff --git a/app/validate/merchant/MerchantApplymentsValidate.php b/app/validate/merchant/MerchantApplymentsValidate.php new file mode 100644 index 00000000..6aaa5848 --- /dev/null +++ b/app/validate/merchant/MerchantApplymentsValidate.php @@ -0,0 +1,297 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class MerchantApplymentsValidate extends Validate +{ + protected $failException = true; + + //2401:小微商户,指无营业执照的个人商家。 + //2500:个人卖家,指无营业执照,已持续从事电子商务经营活动满6个月,且期间经营收入累计超过20万元的个人商家。(若选择该主体,请在“补充说明”填写相关描述) + //4:个体工商户,营业执照上的主体类型一般为个体户、个体工商户、个体经营。 + //2:企业,营业执照上的主体类型一般为有限公司、有限责任公司。 + //3:党政、机关及事业单位,包括国内各级、各类政府机构、事业单位等(如:公安、党 团、司法、交通、旅游、工商税务、市政、医疗、教育、学校等机构)。 + //1708:其他组织,不属于企业、政府/事业单位的组织机构(如社会团体、民办非企业、基 金会),要求机构已办理组织机构代码证。 + + protected $rule = [ + 'organization_type|主体类型' => 'require|in:2,3,4,2401,2500,1708', + 'business_license_info|营业执照/登记证书信息' => 'checkBusinessInfo', +// 'organization_cert_info|组织机构代码证信息' => 'checkOrganization', + 'id_doc_type|证件类型' => 'require|in:1,2,3,4,5,6,7,8', + 'id_card_info|经营者/法人身份证信息' => 'checkIdCardInfo', + 'id_doc_info|经营者/法人身份证信息' => 'checkIdDocInfo', +// 'need_account_info|是否填写结算银行账户' => 'require|in:true,false', 废弃字段 + 'account_info|结算银行账户' => 'getAccountInfo', + 'contact_info|超级管理员信息' => 'getContactInfo', + 'sales_scene_info|店铺信息'=>'checkSalesSceneInfo', + 'merchant_shortname|商户简称' => 'require', + 'business_addition_desc' => 'checkBusinessAdditionDesc', + ]; + + /** + * TODO 营业执照/登记证书信息 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function checkBusinessInfo($item,$rule,$data) + { + if(!in_array($data['organization_type'],['2401','2500'])){ + if(empty($item)) return '营业执照/登记证书信息为空'; + + if(!isset($item['business_license_copy']) || empty($item['business_license_copy'])) return '证件扫描件为空'; + if(!isset($item['business_license_number']) || empty($item['business_license_number'])) return '证件注册号为空'; + if(!isset($item['merchant_name']) || empty($item['merchant_name'])) return '商户名称为空'; + if(!isset($item['legal_person']) || empty($item['legal_person'])) return '经营者/法定代表人姓名为空'; + + if(isset($item['business_time'])) { + $statr = $item['business_time'][0]; + $end = $item['business_time'][1]; + if ($end !== '长期') { + $statr = strtotime($statr); + $end = strtotime($end); + $t = $end - $statr; + if (($t / (3600 * 24)) <= 60) return '营业执照/登记证书有效期必须大于60天,即结束时间距当前时间需超过60天'; + } + } + + } + return true; + } + + /** + * TODO 组织机构代码证信息 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function checkOrganization($item,$rule,$data) + { + $len = strlen($data['business_license_info']['business_license_number']); + if(!in_array($data['organization_type'],['4','2401','2500']) && $len === 18){ + if(empty($item)) return '组织机构代码证信息为空'; + + if(!isset($item['organization_copy']) || empty($item['organization_copy'])) return '组织机构代码证照片为空'; + if(!isset($item['organization_number']) || empty($item['organization_number'])) return '组织机构代码为空'; + if(!isset($item['organization_time']) || empty($item['organization_time'])) return '组织机构代码有效期限为空'; + +// list($statr,$end) = explode(',',$item['organization_time']); + + $statr = $item['organization_time'][0]; + $end = $item['organization_time'][1]; + + if($end !== '长期') { + $statr = strtotime($statr); + $end = strtotime($end); + $t = $end - $statr; + if(($t/(3600 * 24)) <= 60) return '组织机构代码证有效期必须大于60天,即结束时间距当前时间需超过60天'; + } + } + return true; + } + + /** + * TODO 经营者/法人身份证信息/身份证 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function checkIdCardInfo($item,$rule,$data) + { + if($data['id_doc_type'] == 1){ + if(empty($item)) return '经营者/法人身份证信息为空'; + + if(!isset($item['id_card_copy']) || empty($item['id_card_copy'])) return '身份证人像面照片为空'; + if(!isset($item['id_card_national']) || empty($item['id_card_national'])) return '身份证国徽面照片为空'; + if(!isset($item['id_card_name']) || empty($item['id_card_name'])) return '身份证姓名为空'; + if(!isset($item['id_card_number']) || empty($item['id_card_number'])) return '身份证号码为空'; + if(!isset($item['id_card_valid_time_begin']) || empty($item['id_card_valid_time_begin'])) return '经营者/法人身份证信息身份证开始时间为空'; + if(!isset($item['id_card_valid_time']) || empty($item['id_card_valid_time'])) return '经营者/法人身份证信息身份证有效期限为空'; + + if($item['id_card_valid_time'] !== '长期') { + $statr = time(); + $end = strtotime($item['id_card_valid_time']); + $t = $end - $statr; + if(($t/(3600 * 24)) <= 60) return '经营者/法人身份证信息证件结束日期必须大于60天,即结束时间距当前时间需超过60天'; + if(strtotime($item['id_card_valid_time_begin']) >= strtotime($item['id_card_valid_time'])) return '经营者/法人身份证信息证件结束日期必须大于证件开始时间'; + } + if($data['organization_type'] === 2){ + if(!isset($item['id_card_address']) || empty($item['id_card_address'])) return '经营者/法人身份证信息身份证居住地址为空'; + } + }; + return true; + } + + /** + * TODO 经营者/法人身份证信息/通行证 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function checkIdDocInfo($item,$rule,$data) + { + if(in_array($data['organization_type'],['2401','2500']) && !empty($item)) return '小微/个人卖家可选证件类型:身份证'; + + if($data['id_doc_type'] !== 1){ + if(empty($item)) return '经营者/法人身份证信息为空'; + + if(!isset($item['id_doc_name']) || empty($item['id_doc_name'])) return '证件姓名为空'; + if(!isset($item['id_doc_number']) || empty($item['id_doc_number'])) return '证件号码为空'; + if(!isset($item['id_doc_copy']) || empty($item['id_doc_copy'])) return '经营者/法人其他类型证件信息证件正面照片为空'; + if($data['id_doc_type'] !== 2) //护照不需要传反面 + { + if(!isset($item['id_doc_copy_back']) || empty($item['id_doc_copy_back'])) return '经营者/法人其他类型证件信息证件反面照片为空'; + } + if(!isset($item['doc_period_begin']) || empty($item['doc_period_begin'])) return '经营者/法人其他类型证件信息证件有效期开始时间为空'; + if(!isset($item['doc_period_end']) || empty($item['doc_period_end'])) return '经营者/法人其他类型证件信息证件结束日期为空'; + + if($item['doc_period_end'] !== '长期') { + $statr = time(); + $end = strtotime($item['doc_period_end']); + $t = $end - $statr; + if(($t/(3600 * 24)) <= 60) return '经营者/法人其他类型证件信息证件结束日期必须大于60天,即结束时间距当前时间需超过60天'; + if(strtotime($item['doc_period_begin']) >= strtotime($item['doc_period_end'])) return '经营者/法人其他类型证件信息证件结束日期必须大于证件开始时间'; + if($data['organization_type'] === 2){ + if(!isset($item['id_doc_address']) || empty($item['id_doc_address'])) return '经营者/法人其他类型证件信息证件居住地址为空'; + } + } + } + + return true; + } + + /** + * TODO 结算银行账户 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function getAccountInfo($item,$rule,$data) + { +// if($data['need_account_info']){ + + if(empty($item)) return '结算银行账户信息为空'; + + if(!isset($item['bank_account_type']) || empty($item['bank_account_type'])) return '账户类型为空'; + if(!isset($item['account_bank']) || empty($item['account_bank'])) return '开户银行为空'; + if(!isset($item['account_name']) || empty($item['account_name'])) return '开户名称为空'; + if(!isset($item['bank_address_code']) || empty($item['bank_address_code'])) return '开户银行省市编码为空'; + if(!isset($item['account_number']) || empty($item['account_number'])) return '银行帐号为空'; + +// } + + return true; + } + + /** + * TODO 超级管理员信息 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function getContactInfo($item,$rule,$data) + { + + if(empty($item)) return '超级管理员信息信息为空'; + + if(!isset($item['contact_type']) || empty($item['contact_type'])) return '超级管理员类型为空'; + if(!isset($item['contact_name']) || empty($item['contact_name'])) return '超级管理员姓名为空'; + if(!isset($item['contact_id_card_number']) || empty($item['contact_id_card_number'])) return '超级管理员身份证件号码为空'; + if(!isset($item['mobile_phone']) || empty($item['mobile_phone'])) return '超级管理员手机为空'; + + if(!in_array($data['organization_type'],['2401','2500'])){ + if(!isset($item['contact_email']) || empty($item['contact_email'])) return '邮箱为空'; + } + + if($item['contact_type'] === 66) //当超级管理员类型为66(经办人时) + { + if(!isset($item['contact_id_doc_type']) || empty($item['contact_id_doc_type']) || !in_array($item['contact_id_doc_type'],[1,2,3,4,5,6,7,8])) return '超级管理员证件类型为空或不合法'; + if(!isset($item['contact_id_doc_copy']) || empty($item['contact_id_doc_copy'])) return '超级管理员信息证件正面照片为空'; + if($item['contact_id_doc_type'] !== 2) //护照不需要传反面 + { + if(!isset($item['contact_id_doc_copy_back']) || empty($item['contact_id_doc_copy_back'])) return '超级管理员信息证件反面照片为空'; + } + if(!isset($item['contact_id_doc_period_begin']) || empty($item['contact_id_doc_period_begin'])) return '超级管理员信息证件有效期开始时间为空'; + if(!isset($item['contact_id_doc_period_end']) || empty($item['contact_id_doc_period_end'])) return '超级管理员信息证件结束日期为空'; + + if($item['contact_id_doc_period_end'] !== '长期') { + $statr = time(); + $end = strtotime($item['contact_id_doc_period_end']); + $t = $end - $statr; + if(($t/(3600 * 24)) <= 60) return '超级管理员信息证件结束日期必须大于60天,即结束时间距当前时间需超过60天'; + if(strtotime($item['contact_id_doc_period_begin']) >= strtotime($item['contact_id_doc_period_end'])) return '超级管理员信息证件结束日期必须大于证件开始时间'; + } + if(!isset($item['business_authorization_letter']) || empty($item['business_authorization_letter'])) return '超级管理员信息业务办理授权函为空'; + } + + return true; + } + + /** + * TODO 店铺信息 + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/22/21 + */ + protected function checkSalesSceneInfo($item,$rule,$data) + { + if(empty($item)) return '店铺信息为空'; + + if(!isset($item['store_name']) || empty($item['store_name'])) return '店铺名称为空'; + + if(!isset($item['store_url']) && !isset($item['store_url'])) return '店铺链接和店铺二维码二选一'; + + return true; + } + + /** + * TODO 补充说明s + * @param $item + * @param $rule + * @param $data + * @return bool|string + * @author Qinii + * @day 6/24/21 + */ + protected function checkBusinessAdditionDesc($item,$rule,$data) + { + if($data['organization_type'] == 2500 && empty($item)) return '若主体为“个人卖家”:补充说明不能为空'; + return true; + } + +} diff --git a/app/validate/merchant/MerchantFinancialAccountValidate.php b/app/validate/merchant/MerchantFinancialAccountValidate.php new file mode 100644 index 00000000..b6179e25 --- /dev/null +++ b/app/validate/merchant/MerchantFinancialAccountValidate.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class MerchantFinancialAccountValidate extends Validate +{ + protected $failException = true; + /* + { + "financial_type":2, + "name":"王二小", + "idcard":"", + "wechat":"1", + "wechat_code":"456461516" + } + { + "financial_type":3, + "name":"王二小", + "idcard":"", + "alipay":"1", + "alipay_code":"456461516" + } + */ + protected $rule = [ + 'financial_type|转账类型' => 'require|in:1,2,3', + 'name|姓名' => 'require|chs', + 'bank|开户银行' => 'requireIf:financial_type,1', + 'bank_code|银行卡号' => 'requireIf:financial_type,1', + //'idcard|身份证号' => 'requireIf:financial_type,2,3|idCard', + 'wechat|微信号' => 'requireIf:financial_type,2', + 'wechat_code|微信收款二维码' => 'requireIf:financial_type,2', + 'alipay|支付宝账号' => 'requireIf:financial_type,3', + 'alipay_code|收款二维码' => 'requireIf:financial_type,3', + ]; +} + diff --git a/app/validate/merchant/MerchantTakeValidate.php b/app/validate/merchant/MerchantTakeValidate.php new file mode 100644 index 00000000..2b0f729c --- /dev/null +++ b/app/validate/merchant/MerchantTakeValidate.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class MerchantTakeValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'mer_take_name|自提点名称' => 'require', + 'mer_take_phone|自提点手机号' => 'require|mobile', + 'mer_take_address|自提点地址' => 'require', + 'mer_take_location|店铺经纬度' => 'require|array|length:2', + 'mer_take_day|自提点营业日期' => 'array|max:7', + 'mer_take_time|自提点营业时间' => 'array|length:2', + ]; +} diff --git a/app/validate/merchant/MerchantUpdateValidate.php b/app/validate/merchant/MerchantUpdateValidate.php new file mode 100644 index 00000000..21e7aeb4 --- /dev/null +++ b/app/validate/merchant/MerchantUpdateValidate.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class MerchantUpdateValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'mer_info|店铺简介' => 'require|max:200', + 'mer_avatar|店铺头像' => 'require|max:128', + 'mer_banner|店铺banner' => 'require|max:128', + 'mini_banner|店铺街banner' => 'max:128', + 'mer_keyword|店铺关键字' => 'max:128', + 'mer_address|店铺地址' => 'require|max:128', + 'long|店铺经度' => 'max:24', + 'lat|店铺纬度' => 'max:24', + ]; + + protected function isPhone($val) + { + $res = preg_match('/^((\+86|\+86\-)|(86|86\-)|(0086|0086\-))?1\d{10}$|^(0\d{2,3}\-)?([2-9]\d{6,7})+(\-\d{1,6})?$/', $val); + if ($res) return true; + return '服务电话格式有误'; + } +} diff --git a/app/validate/merchant/ServiceReplyValidate.php b/app/validate/merchant/ServiceReplyValidate.php new file mode 100644 index 00000000..015d49c9 --- /dev/null +++ b/app/validate/merchant/ServiceReplyValidate.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +/** + * Class WechatReplyValidate + * @package app\validate\admin + * @author xaboy + * @day 2020-04-27 + */ +class ServiceReplyValidate extends Validate +{ + /** + * @var bool + */ + protected $failException = true; + + /** + * @var array + */ + protected $rule = [ + 'type|类型' => 'require|in:1,2', + 'keyword|关键字' => 'require|max:32', + 'content|回复内容' => 'require', + 'status|开启状态' => 'require|in:0,1' + ]; + +} diff --git a/app/validate/merchant/ShippingTemplateValidate.php b/app/validate/merchant/ShippingTemplateValidate.php new file mode 100644 index 00000000..20bef340 --- /dev/null +++ b/app/validate/merchant/ShippingTemplateValidate.php @@ -0,0 +1,70 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + +use think\Validate; + +class ShippingTemplateValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'name|名称' => 'require|max:32', + 'type|计费方式' => 'require|in:0,1,2', + 'appoint|指定包邮状态' => 'require|in:0,1', + 'region|配送区域信息' => 'Array|require|min:1|region', + 'undelivery|区域不配送状态' => 'require|in:0,1,2', + 'free|包邮信息' => 'requireIf:appoint,1|Array|free', + 'undelives|不配送区域信息'=>'requireIf:undelivery,1|Array|undelive', + ]; + + protected function region($value,$rule,$data) + { + foreach ($value as $k => $v){ + if ($k != 0 && empty($v['city_id'])) + return '配送城市信息不能为空'; + if (!is_numeric($v['first']) || $v['first'] < 0) + return '首件条件不能小0'; + if (!is_numeric($v['first_price']) || $v['first_price'] < 0) + return '首件金额不能小于0'; + if (!is_numeric($v['continue']) || ($v['continue'] < 0)) + return '续件必须为不小于零的整数'; + if (!is_numeric($v['continue_price']) || $v['continue_price'] < 0 ) + return '追加金额为不小于零的数'; + } + return true; + } + protected function free($value,$rule,$data) + { + if(!$data['appoint']) return true; + foreach ($value as $v){ + if (empty($v['city_id'])) + return '包邮城市信息不能为空'; + if (!is_int($v['number']) || $v['number'] < 0) + return '包邮条件为不小于零的整数'; + if (!is_numeric($v['price']) ||$v['price'] < 0) + return '包邮金额必须为不小于零的数字'; + } + return true; + } + + protected function undelive($value,$rule,$data) + { + if($data['undelivery'] == 1){ + if (empty($value['city_id'])) + return '不配送城市信息不能为空'; + } + return true; + } +} diff --git a/app/validate/merchant/StoreAttrTemplateValidate.php b/app/validate/merchant/StoreAttrTemplateValidate.php new file mode 100644 index 00000000..a731b185 --- /dev/null +++ b/app/validate/merchant/StoreAttrTemplateValidate.php @@ -0,0 +1,27 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class StoreAttrTemplateValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'template_name|模板名称' => 'require|max:32', + 'template_value|规则' => 'require|array|min:1' + ]; +} diff --git a/app/validate/merchant/StoreCouponSendValidate.php b/app/validate/merchant/StoreCouponSendValidate.php new file mode 100644 index 00000000..1cec617a --- /dev/null +++ b/app/validate/merchant/StoreCouponSendValidate.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class StoreCouponSendValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'coupon_id|优惠券' => 'require|integer', + 'mark|用户类型' => 'array', + 'is_all|用户类型' => 'require|in:0,1', + 'search|用户类型' => 'require|array', + 'uid|用户' => 'array' + ]; +} diff --git a/app/validate/merchant/StoreCouponValidate.php b/app/validate/merchant/StoreCouponValidate.php new file mode 100644 index 00000000..099998ff --- /dev/null +++ b/app/validate/merchant/StoreCouponValidate.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class StoreCouponValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'title|优惠券名称' => 'require|max:32', + 'coupon_price|优惠券面值' => 'require|float|>:0|dime', + 'use_min_price|最低消费金额' => 'require|float', + 'coupon_type|有效期类型' => 'require|in:0,1', + 'coupon_time|有效期限' => 'requireIf:coupon_type,0|integer|>:0', + 'use_start_time|有效期限' => 'requireIf:coupon_type,1|array|>:2', + 'sort|排序' => 'require|integer', + 'status|状态' => 'require|in:0,1', + 'type|优惠券类型' => 'require|in:0,1,10,11,12', + 'product_id|商品' => 'requireIf:type,1|array|>:0', + 'send_type|类型' => 'require|in:0,1,2,3,4,5', + 'full_reduction|满赠金额' => 'requireIf:send_type,1|float|>=:0', + 'is_limited|是否限量' => 'require|in:0,1', + 'is_timeout|是否限时' => 'require|in:0,1', + 'range_date|领取时间' => 'requireIf:is_timeout,1|array|length:2', + 'total_count|发布数量' => 'requireIf:is_limited,1|integer|>:0', + ]; + + protected function dime($value) + { + if (!bcadd($value, 0, 1) == $value) + return '优惠券面值最多1位小数'; + return true; + } + +} diff --git a/app/validate/merchant/StoreDiscountsValidate.php b/app/validate/merchant/StoreDiscountsValidate.php new file mode 100644 index 00000000..483353c6 --- /dev/null +++ b/app/validate/merchant/StoreDiscountsValidate.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Exception; +use think\File; +use think\Validate; + +class StoreDiscountsValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + //"image|套餐图片" => 'require|max:128', + "title|套餐标题" => 'require|max:128', + "type|套餐类型" => 'require|in:0,1', + "is_limit|是否限够" => 'require', + "limit_num|限购数量" => 'require|max:4', + "is_time|是否限时" => "in:0,1", + "sort|排序" => "require", + "free_shipping|是否包邮" => "require", + 'status|发货方式' => 'require', + 'products|发货方式' => 'require', + ]; +} diff --git a/app/validate/merchant/StoreProductAdminValidate.php b/app/validate/merchant/StoreProductAdminValidate.php new file mode 100644 index 00000000..7a150ed5 --- /dev/null +++ b/app/validate/merchant/StoreProductAdminValidate.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Validate; + +class StoreProductAdminValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "store_name|商品名称" => 'require', + "is_hot|是否热卖" => "in:0,1", + "is_best|是否精品" => "in:0,1", + "ficti|已售数量" => "number", + "status|审核状态" => "in:0,1,-1", + "refusal|拒绝理由" => "requireIf:status,-1" + ]; +} diff --git a/app/validate/merchant/StoreProductAssistValidate.php b/app/validate/merchant/StoreProductAssistValidate.php new file mode 100644 index 00000000..0cf8ba64 --- /dev/null +++ b/app/validate/merchant/StoreProductAssistValidate.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Validate; + +class StoreProductAssistValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "image|主图" => 'require|max:128', + "slider_image|轮播图" => 'require', + "store_name|商品名称" => 'require|max:128', + "store_info|商品简介" => 'require|max:128', + "product_id|原商品ID" => 'require', + "temp_id|运费模板" => 'require', + "start_time|开始时间" => 'require|checkTime', + "end_time|结束时间" => "require", + "assist_user_count|单人助力次数" => "require", + "assist_count|需助力总人数" => "require", + "attrValue|商品属性" => "require|Array" + ]; + + public function isUpdate() + { + $this->rule['start_time|开始时间'] = 'require'; + return $this; + } + + protected function checkTime($value,$rule,$data) + { + $start_time = strtotime($data['start_time']); + $end_time = strtotime($data['end_time']); + if($start_time > $end_time) return '活动开始时间必须小于结束时间'; + if($start_time < time()) return '活动开始时间必须大于当前时间'; + return true; + } +} diff --git a/app/validate/merchant/StoreProductGroupValidate.php b/app/validate/merchant/StoreProductGroupValidate.php new file mode 100644 index 00000000..69a56cc8 --- /dev/null +++ b/app/validate/merchant/StoreProductGroupValidate.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Validate; + +class StoreProductGroupValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "image|主图" => 'require|max:128', + "slider_image|轮播图" => 'require', + "store_name|商品名称" => 'require|max:128', + "store_info|商品简介" => 'require', + "product_id|原商品ID" => 'require', + "temp_id|运费模板" => 'require', + "start_time|开始时间" => 'require', + "end_time|结束时间" => "require", + "buying_count_num|开团总人数" => "require|>=:buying_num", + "attrValue|商品属性" => "require|Array", + "time|开团时长" => "require" + ]; +} diff --git a/app/validate/merchant/StoreProductPresellValidate.php b/app/validate/merchant/StoreProductPresellValidate.php new file mode 100644 index 00000000..7a228fd9 --- /dev/null +++ b/app/validate/merchant/StoreProductPresellValidate.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Validate; + +class StoreProductPresellValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "image|主图" => 'require|max:128', + "slider_image|轮播图" => 'require', + "store_name|商品名称" => 'require|max:128', + "store_info|商品简介" => 'require|max:128', + "product_id|原商品ID" => 'require', + "temp_id|运费模板" => 'require', + "start_time|开始时间" => 'require|checkTime', + "end_time|结束时间" => "require", + "presell_type|预售类型" => "require", + "final_start_time|尾款支付开始时间" => "requireIf:presell_type,2", + "final_end_time|尾款支付结束时间" => "requireIf:presell_type,2", + "delivery_type|发货类型" => "require", + "delivery_day|发货等待天数" => "require", + "attrValue|商品属性" => "require|Array" + ]; + + protected function checkTime($value,$rule,$data) + { + $start_time = strtotime($data['start_time']); + $end_time = strtotime($data['end_time']); + if($start_time > $end_time) return '活动开始时间必须小于结束时间'; + if($start_time < time()) return '活动开始时间必须大于当前时间'; + if($data['presell_type'] == 2){ + $final_start_time = strtotime($data['final_start_time']); + $final_end_time = strtotime($data['final_end_time']); + if($end_time > $final_start_time) return '尾款支付开始时间必须大于定金结束时间'; + if($final_end_time < $final_start_time) return '尾款支付开始时间必须小于结束时间'; + } + return true; + } +} diff --git a/app/validate/merchant/StoreProductValidate.php b/app/validate/merchant/StoreProductValidate.php new file mode 100644 index 00000000..4a25b2ab --- /dev/null +++ b/app/validate/merchant/StoreProductValidate.php @@ -0,0 +1,83 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Exception; +use think\File; +use think\Validate; + +class StoreProductValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "image|主图" => 'require|max:128', + "store_name|商品名称" => 'require|max:128', + "cate_id|平台分类" => 'require', + "mer_cate_id|商户分类" => 'array', + "unit_name|单位名" => 'require|max:4', + "spec_type" => "in:0,1", + "is_show|是否上架" => "in:0,1", + "extension_type|分销类型" => "in:0,1", + "attr|商品规格" => "requireIf:spec_type,1|Array|checkUnique", + "attrValue|商品属性" => "require|array|productAttrValue", + 'type|商品类型' => 'require|in:0,1,99', + 'delivery_way|发货方式' => 'requireIf:is_ficti,0|require', + 'once_min_count|最小限购' => 'min:0', + 'pay_limit|是否限购' => 'require|in:0,1,2|payLimit', + ]; + + protected function payLimit($value,$rule,$data) + { + if ($value && ($data['once_max_count'] < $data['once_min_count'])) + return '限购数量不能小于最少购买件数'; + return true; + } + + protected function productAttrValue($value,$rule,$data) + { + $arr = []; + try{ + foreach ($value as $v){ + $sku = ''; + if(isset($v['detail']) && is_array($v['detail'])){ + sort($v['detail'],SORT_STRING); + $sku = implode(',',$v['detail']); + } + if(in_array($sku,$arr)) return '商品SKU重复'; + $arr[] = $sku; + if(isset($data['extension_type']) && $data['extension_type'] && systemConfig('extension_status')){ + if(!isset($v['extension_one']) || !isset($v['extension_two'])) return '佣金金额必须填写'; + if(($v['extension_one'] < 0) || ($v['extension_two'] < 0)) + return '佣金金额不可存在负数'; + if($v['price'] < bcadd($v['extension_one'],$v['extension_two'],2)) + return '自定义佣金总金额不能大于商品售价'; + } + } + } catch (\Exception $exception) { + return '商品属性格式错误'; + } + return true; + } + + protected function checkUnique($value) + { + $arr = []; + foreach ($value as $item){ + if(in_array($item['value'],$arr)) return '规格重复'; + $arr[] = $item['value']; + if (count($item['detail']) != count(array_unique($item['detail']))) return '属性重复'; + } + return true; + } +} diff --git a/app/validate/merchant/StoreProductValidate.php.bak b/app/validate/merchant/StoreProductValidate.php.bak new file mode 100644 index 00000000..5099ac54 --- /dev/null +++ b/app/validate/merchant/StoreProductValidate.php.bak @@ -0,0 +1,83 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\Exception; +use think\File; +use think\Validate; + +class StoreProductValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "image|主图" => 'require|max:128', + "store_name|商品名称" => 'require|max:128', + "cate_id|平台分类" => 'require', + "mer_cate_id|商户分类" => 'array', + "unit_name|单位名" => 'require|max:4', + "spec_type" => "in:0,1", + "is_show|是否上架" => "in:0,1", + "extension_type|分销类型" => "in:0,1", + "attr|商品规格" => "requireIf:spec_type,1|Array|checkUnique", + "attrValue|商品属性" => "require|array|productAttrValue", + 'type|商品类型' => 'require|in:0,1', + 'delivery_way|发货方式' => 'requireIf:is_ficti,0|require', + 'once_min_count|最小限购' => 'min:0', + 'pay_limit|是否限购' => 'require|in:0,1,2|payLimit', + ]; + + protected function payLimit($value,$rule,$data) + { + if ($value && ($data['once_max_count'] < $data['once_min_count'])) + return '限购数量不能小于最少购买件数'; + return true; + } + + protected function productAttrValue($value,$rule,$data) + { + $arr = []; + try{ + foreach ($value as $v){ + $sku = ''; + if(isset($v['detail']) && is_array($v['detail'])){ + sort($v['detail'],SORT_STRING); + $sku = implode(',',$v['detail']); + } + if(in_array($sku,$arr)) return '商品SKU重复'; + $arr[] = $sku; + if(isset($data['extension_type']) && $data['extension_type'] && systemConfig('extension_status')){ + if(!isset($v['extension_one']) || !isset($v['extension_two'])) return '佣金金额必须填写'; + if(($v['extension_one'] < 0) || ($v['extension_two'] < 0)) + return '佣金金额不可存在负数'; + if($v['price'] < bcadd($v['extension_one'],$v['extension_two'],2)) + return '自定义佣金总金额不能大于商品售价'; + } + } + } catch (\Exception $exception) { + return '商品属性格式错误'; + } + return true; + } + + protected function checkUnique($value) + { + $arr = []; + foreach ($value as $item){ + if(in_array($item['value'],$arr)) return '规格重复'; + $arr[] = $item['value']; + if (count($item['detail']) != count(array_unique($item['detail']))) return '属性重复'; + } + return true; + } +} diff --git a/app/validate/merchant/StoreSeckillProductValidate.php b/app/validate/merchant/StoreSeckillProductValidate.php new file mode 100644 index 00000000..8086fa47 --- /dev/null +++ b/app/validate/merchant/StoreSeckillProductValidate.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace app\validate\merchant; + +use think\File; +use think\Validate; + +class StoreSeckillProductValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + "image|主图" => 'require|max:128', + "slider_image|轮播图" => 'require', + "store_name|商品名称" => 'require|max:128', + "brand_id|品牌ID" => 'require', + "cate_id|平台分类" => 'require', + "mer_cate_id|商户分类" => 'array', + "unit_name|单位名" => 'require|max:4', + "temp_id|运费模板" => 'require', + "spec_type" => "in:0,1", + "is_show|是否上架" => "in:0,1", + + "start_day|开始日期" => "require", + "end_day|结束日期" => "require", + "start_time|开始时间" => "require", + "end_time|结束时间" => "require", + "old_product_id|原商品ID" => 'require', + "once_pay_count|单场限购" => 'require', + "all_pay_count|限购总数" => 'require', + + "attr|商品规格" => "requireIf:spec_type,1|Array|checkUnique", + "attrValue|商品属性" => "Array|productAttrValue" + ]; + + protected function productAttrValue($value,$rule,$data) + { + $arr = []; + foreach ($value as $v){ + $sku = ''; + if(isset($v['detail']) && is_array($v['detail'])){ + sort($v['detail'],SORT_STRING); + $sku = implode(',',$v['detail']); + } + if($v['stock'] < 1) return '限量不能小于1'; + if(in_array($sku,$arr)) return '商品SKU重复'; + $arr[] = $sku; + } + return true; + } + + public function checkUnique($value) + { + $arr = []; + foreach ($value as $item){ + if(in_array($item['value'],$arr)) return '规格重复'; + $arr[] = $item['value']; + if (count($item['detail']) != count(array_unique($item['detail']))) return '属性重复'; + } + return true; + } +} diff --git a/app/validate/merchant/StoreServiceValidate.php b/app/validate/merchant/StoreServiceValidate.php new file mode 100644 index 00000000..56f09cd5 --- /dev/null +++ b/app/validate/merchant/StoreServiceValidate.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- + + +namespace app\validate\merchant; + + +use think\Validate; + +class StoreServiceValidate extends Validate +{ + protected $failException = true; + + protected $rule = [ + 'uid|客服' => 'require|array', + 'uid.id|客服' => 'require|integer', + 'nickname|客服名称' => 'require|max:12', + 'avatar|客服头像' => 'max:250', + 'account|客服账号' => 'require|min:5|max:16', + 'pwd|客服密码' => 'require|min:6|max:16', + 'confirm_pwd|确认密码' => 'require|min:6|max:16', + 'is_open|状态' => 'require|in:0,1', + 'status|状态' => 'require|in:0,1', + 'is_verify|核销状态' => 'require|in:0,1', + 'is_goods|商品管理状态' => 'require|in:0,1', + 'notify|订单通知状态' => 'require|in:0,1', + 'sort|排序' => 'require|integer', + 'customer|展示统计管理状态' => 'require|in:0,1', + ]; + + protected $message = [ + 'account.min' => '客服账号长度不能小于5个字符', + 'uid.require' => '请选择一个用户绑定为客服', + 'uid.id.require' => '用户ID不能为空' + ]; + + public function update() + { + $this->rule['pwd|客服密码'] = 'min:6|max:16'; + $this->rule['confirm_pwd|确认密码'] = 'min:6|max:16'; + return $this; + } +} diff --git a/app/view/install/step1.html b/app/view/install/step1.html new file mode 100644 index 00000000..ab600892 --- /dev/null +++ b/app/view/install/step1.html @@ -0,0 +1,119 @@ + + + + +安装许可协议 - Powered by CRMEB + + + +
    + +
    +

    logo

    +
    安装向导
    +
    +
    +
    +
    +
    +          

    软件许可协议

    + +提示条款: +本协议是您与西安众邦网络科技有限公司共同签署。 +CRMEB客户管理+电商系统(以下称“CRMEB”),由西安众邦网络科技有限公司(以下称“众邦科技”)独创开发,版权所有Copyright (c)2014-2024,众邦科技保留所有权利。CRMEB是国内最稳定、最强大、最先进的互联网电商平台解决方案之一,CRMEB基于 PHP + MySQL 的技术,采用ThinkPHP框架开发。CRMEB官方对此拥有最终修改权和解释权。 +CRMEB官方网站:http://www.crmeb.com +在使用CRMEB客户管理+电商系统(以下称“许可软件”或“本软件”)之前,请您仔细阅读本协议,特别是法律适用和争议解决条款,此等条款将以粗体标识,您需要重点阅读。如您对协议有任何疑问,可向客服咨询。如果您已下载、复制、安装或以其他任何方式使用该软件,则视为已经接受本协议。如果您不接受本协议的全部或部分条款,您将无权使用本软件。请立即终止安装、或以其他方式使用该软件,删除您已经安装或保留的该软件的任何组件。 +由于互联网高速发展,您与我们签署的本协议列明的条款并不能完整罗列并覆盖您与我们所有权利与义务,现有的约定也不能保证完全符合未来发展的需求。 +因此,《版权声明》及其他规则均为本协议的补充协议,与本协议不可分割且具有同等法律效力。如您使用许可软件,视为您同意上述补充协议。我们如修改本协议或其补充协议,协议条款修改后,请您仔细阅读并接受修改后的协议后再继续使用许可软件。 +
    +一、定义 +软件(许可软件或本软件):本协议中的“软件”是指CRMEB客户管理+电商系统,由若干模块或功能组成的已经植入或即将植入众邦科技指定产品内的信息处理程序或支持文件,其中支持文件具体包括软件的源代码、目标码以及相关软件中所包含的图片、照片、图标、动画、录音、录像、音乐、文字、代码的全部或部分,还包括与许可软件或众邦产品相关的所有描述其功能、特点、内容、质量、测试、用户手册、用户许可协议等纸质或电子版的资料、技术文档等。 +您:本协议中的“您”是指取得众邦科技合法许可使用本软件权利的个人或单个法人实体,法人实体包括公司、企业、机构、组织或单位。 +我们:本协议中的“我们”即是CRMEB官方,是指众邦科技,即西安众邦网络科技有限公司及其关联公司。 +二次开发:本协议中的“二次开发”在现有的软件上进行定制修改,如对功能扩展,达到您想要的功能,原则不得改变本软件原有系统内核及系统设定的框架,我们允许的二次开发仅指对部分软件界面、功能删改或扩展,并非对内核及框架进行实质性修改。 +
    +二、软件许可使用内容 +在您遵守本协议内容的前提下,您通过我们指定合法渠道购买软件商用许可后,众邦科技授予您的商用许可权利包括: +1、安装和使用权利:您可以为商用目的安装和使用本软件,使用本软件提供的全部功能。 +2、绑定唯一域名的权利:在安装本软件前,您应当自备一个域名并告知我们,以便我们将域名与本软件进行绑定。该绑定域名是商用许可软件的唯一指向。您应确保域名的唯一性、有效性,域名一经绑定,不得随意更换。您自备的域名可以是顶级、二级、或三级域名,您应对域名合法性、有效性承担责任。在使用本软件过程中,如需更换域名,应提前三个工作日以书面方式告知我们并如实告知被更换域名存在的问题,否则,我们有权利不予更换。 +3、申请商用授权码的权利:您在我们指定合法渠道购买软件商用许可后,凭借订单号可以在我们官网申请商用授权码,并通过我们官方网站下载授权证书。 +4、获取商用授权证书的权利:通过我们官方网站下载的商用授权证书是许可您将软件商用的合法凭证。该授权证书是授予您以本协议约定方式合法使用软件的永久授权,但我们不对授权作无限制使用的永久承诺。 +5、授权内容使用权:在取得我们许可后,您拥有使用本软件构建的网站全部内容使用权,并独立承担与之相关法律义务。您可以在协议规定的约束条件下和限制范围内修改 CRMEB 源代码或界面风格以适应您的网站要求,但应保留我们的版权信息。不管你的网站是否整体使用 CRMEB ,还是部份栏目使用 CRMEB,在你使用了 CRMEB 的网站主页上必须加上 CRMEB 官方网址(www.CRMEB.com)的链接。 +6、在获得商业授权之后,您才可以将本软件应用于商业用途,同时依据所购买的授权类型确定技术支持内容。商业授权用户享有反馈意见和提出建议的权力,相关意见和建议将在我们下一次软件升级中被优先考虑,但我们对此不作承诺或保证。 +7、CRMEB著作权已在中华人民共和国国家版权局注册(中国国家版权局著作权登记号 2018SR024463),著作权受到法律和国际公约保护。未经我们书面许可,不得删除网站底部及相应的官方链接。购买商业授权请联系众邦科技了解最新说明。 +8、本软件适用运营环境,在软件相关文档中已经明确提示,如因软件安装不符运营环境造成的故障,我们不承担任何责任。 +
    +三、权利限制 +1、单一使用限制:同一个域名,只允许绑定一次。您购买的许可,只允许您自己使用,不得再许可任何第三人使用。 +2、共享软件限制:您不得通过共享软件的全部或部分,允许多人使用软件的部分或全部功能。 +3、软件分解限制:您不得通过分解软件,把不同功能或把软件的不同部分嵌入到其他软件系统。 +4、软件完整性限制:您不得删除软件中的任何版权申明、提示,亦不得对软件中出现的任何商标或标识进行涂抹、修改或删除,除非已经获得我们的书面同意,您应将需要修改的标识等详细情况书面告知我们,以便我们评估您的需要。 +5、反向工程、反编译、反汇编限制:您不得对软件进行反向工程、反编译、反汇编,除非法律明确规定允许这些行为除外。 +6、转让限制:未经众邦科技的书面同意,您不得公开、转让、出租、出借、再许可、分发该软件的全部或任何部分或软件单一备份副本给第三方。 +7、保密限制:未经众邦科技书面同意,您不得将本软件的性能或其他任何评估、测试结果、技术秘密透露给任何第三方。 +
    +四、权利保留 +1、 众邦科技依法保留未在本协议中明确授予给您的其他一切在法律上属于众邦科技的权利。 +2、本软件受著作权法、国际著作权条约和其他的知识产权法律或国际条约保护。根据本协议,在此仅许可您非独占性的、非排他性的一般许可使用该软件的权利,而不是出售或转让。 +3、商标权:本协议不授予您众邦科技或其供应商的任何商标或服务标志相关的任何权利。 +4、本软件所涉及到的一切知识产权,包括但不限于专利权、著作权、商标权、商业秘密、技术秘密,均属于各自内容拥有者的财产,众邦科技保留从其所拥有的知识产权获取利益的权利。 +5、未经我们书面许可,不得对本软件或与之关联的商业授权进行出租、出售、抵押或发放子许可证。 +6、未经我们书面许可,禁止在 CRMEB 的整体或任何部分基础上以发展任何派生版本、修改版本或第三方版本用于重新分发。 +7、您一旦开始确认本协议并安装 CRMEB,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本授权协议并构成侵权,我们有权立即终止授权,责令停止损害,并保留追究相关责任的权力。 +
    +五、知识产权 +1、我们拥有许可软件的著作权、商业秘密以及其他相关的知识产权,包括与许可软件有关的各种文档资料。许可软件的相关标识属于我们及我们的关联公司的知识产权,并受到相关法律法规的保护。 +2、在未获得我们明确同意前,您不得复制、模仿、使用或发布上述图标,也不得修改或删除应用产品中体现我们及其关联公司的任何标识、图标或身份信息。 +3、未经我们及我们的关联公司事先书面同意,您不得为任何营利性或非营利性的目的自行实施、利用、转让或许可任何第三方实施、利用、转让上述知识产权。 +4、除非在此明确地许可或授予,本协议并不涉及任何技术转让,软件里所包含和涉及所有权利,产权和利益属于我们独自所有。除非在此明确地许可,本合同并不将任何技术转让给您。 +
    +六、升级版本 +1、我们会根据需要在后续进行一系列免费升级操作,您只有在获得商业使用授权许可后,才享有软件免费升级权益。我们有权决定将升级包何时以何种方式发送给您。 +2、升级版本的许可:如果该软件经众邦科技同意升级,除非升级版本有替代的软件许可协议,否则升级版本仍应遵循本协议条款。 +3、不论软件是否升级,您必须遵守本协议。 +
    +七、无担保和责任限制 +1、除众邦科技明确明示保证的事项以外,对其他任何默示、特定用途、适销性不做任何默示或明示的保证,由此引起的风险由您自己承担。 +2、有关本软件在使用过程中存在不适用性情况,您应当立即以书面方式反馈给我们,在我们现有技术可以解决的情况下,将依照众邦科技的软件产品标准保修政策规定。 +1)众邦科技不对试用期及免费试用软件因使用而产生的损失承担任何明示或暗示的责任。 +2)众邦科技承担的所有责任以您购买该软件所支付的价款为限。 +3、对因意外事故、滥用、错误使用、擅自修改所引起的软件使用问题,我们不承担任何责任,也不做任何保证。对因软件产品存在被攻击,或者自然灾害等不可抗力因素或非众邦科技原因导致软件不能使用,或造成损失的,我们不承担任何责任,也不做任何保证。 +4、对因使用软件引起的其他任何附带的、间接的或惩罚性的损失,包括但不限于商业利润的损失、信息或数据的丢失,众邦科技不承担任何责任,即使众邦科技已被告知存在此种损害的可能性也不例外。 +5、除法律法规有明确规定外,我们将尽最大努力确保许可软件及其所涉及的技术及信息安全、有效、准确、可靠,但受限于我们现有技术,您充分理解我们不能对此进行担保。您理解,对于因您自身、不可抗力及第三方原因导致的您的直接或间接损失,我们无法承担责任。 +6、由于您因下述任一情况所引起或与此有关的人身伤害或附带的、间接的损害赔偿,包括但不限于利润损失、资料损失、业务中断的损害赔偿或其他商业损害赔偿或损失,需由您自行承担:使用或未能使用许可软件;第三方未经批准的使用许可软件或更改您的数据;使用许可软件进行的行为产生的费用及损失;您对许可软件的误解;非因我们的原因而引起的与许可软件有关的其他损失。 +7、非经我们或我们授权开发并正式发布的其他任何由许可软件衍生的软件均属非法,下载、安装、使用此类软件,或未经绑定唯一指向域名,可能导致不可预知的风险,由此产生的法律责任与纠纷与我们无关,我们有权中止、终止使用许可和(或)其他一切服务。 +8、您与其他使用许可软件的用户之间通过许可软件进行时,因您受误导或欺骗而导致或可能导致的任何心理、生理上的伤害以及经济上的损失,均应由侵权方依法承担所有责任。 +
    +八、保密条款 +双方都应为可能获知另一方的商业计划、客户方资料、技术、产品、代码、文档和其他作为该方商业秘密的秘密信息予以保密。秘密信息包括所有有形的或无形的、标明为秘密的信息。秘密信息归披露方所有,除非经披露方声明许可否则不得披露或使用。 +
    +九、协议终止和违约责任 +1、如果您没有遵守本协议的部分或全部条款,众邦科技可以随时单方终止本协议。协议终止后,我们将取消对您的商用许可授权,同时您必须立即停止使用该软件,对已经安装的软件进行卸载,如果由于您违反了本协议的规定给众邦科技造成损失,应承担损失赔偿责任。 +2、您应理解按授权范围使用许可软件、尊重软件及软件包含内容的知识产权、按规范使用软件、按本协议约定履行义务是您获取我们授权使用软件的前提,如您违反本协议,我们有权终止使用许可。 +3、您对软件的使用有赖于我们及关联公司为您提供的配套服务,您违反与我们或我们关联公司的条款、协议、规则、通告等相关规定,我们有权终止使用许可。您违反了本协议的规定给众邦科技造成损失,应承担给我们造成损失的赔偿责任。 +4、您理解出于维护软件系统及软件平台秩序的目的,如果您向我们及(或)我们的关联公司作出任何形式的承诺,且相关公司已确认您违反了该承诺并通知我们依据您与其相关约定进行处理的,则我们可按您的承诺或协议约定的方式对您的使用许可及其他我们可控制的权益采取限制措施,包括中止或终止对您的使用许可,并追究您相关法律责任的权利。 +5、您如从获得我们授权认可的第三方取得许可软件,您需要遵守本协议及第三方对您使用许可软件方式与限制的约定,如果您违反本协议及与第三方约定,我们有权终止对您的使用许可,并追究您相关法律责任。 +6、您应对从本软件获得的代码、文档等技术信息保密,不得对源代码、文档及框架进行删改,不得破译加密部分,不得非法进行倒卖本软件,我们不对非法软件使用后果承担任何责任,并有权追究您的法律责任,您应当赔偿因您的侵权行为给我们造成的直接和间接损失。 +7、如您违反本协议规定的条款,则构成违约,应当承担软件销售价格十倍至五十倍不等的违约金,如给我们或其他用户造成损失的,您必须承担全部的赔偿责任(包括直接损失和间接损失),包括但不限于咨询费、诉讼费、执行费、保全费、保险费、律师费等费用。 +
    +十、管辖法律及可分割性 +1、本协议之效力、解释、变更、执行与争议解决均适用中华人民共和国法律,如无相关法律规定的,则应参照通用国际商业惯例和(或)行业惯例。本协议由您与我们于我们服务器所在地陕西省西安市莲湖区签署。因本协议产生或与本协议有关的争议,您可与我们以友好协商,协商不成时,提交西安仲裁委员会予以裁决。仲裁裁决是终局的,对双方均有拘束力。 +2、本协议任何条款被认定为无效的,不应影响其他条款或其任何部分的效力,您与我们仍应善意履行。 +
    +十一、其它说明 +1.CRMEB产品没有收集任何最终用户的个人隐私信息。 +2.为了保障您使用CRMEB的产品与/或服务稳定性和版权合法性我们需要收集您的设备信息(操作系统及软件版本、安装站点域名、IP地址、浏览器信息)。 +
    +十二、其它条款 +1、本协议未约定的,由双方另行商定。 +2、本协议的所有标题仅是为了醒目及阅读方便,本身并没有实际涵义,不能作为解释本协议涵义的依据。(正文完) + +西安众邦网络科技有限公司 +
    +
    + +
    +
    + + + diff --git a/app/view/install/step2.html b/app/view/install/step2.html new file mode 100644 index 00000000..14c211f9 --- /dev/null +++ b/app/view/install/step2.html @@ -0,0 +1,157 @@ + + + + + 运行环境检测 - Powered by CRMEB + + + +
    +
    +

    logo

    +
    安装向导
    +
    +
    +
    +
    +
      +
    • 1检测环境
    • +
    • 2创建数据
    • +
    • 3完成安装
    • +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    环境检测推荐配置当前状态最低要求
    PHP版本> 以上
    附件上传>2M不限制
    session开启开启
    safe_mode基础配置启用
    GD库必须开启1.0
    mysqli必须开启启用
    curl_init必须扩展启用
    zip必须扩展启用
    bcmath必须扩展启用
    swoole必须扩展启用
    swoole_loader必须扩展启用
    redis必须扩展启用
    openssl必须扩展启用
    fileinfo必须扩展启用
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    函数检测必须开启当前状态
    file_put_contents
    imagettftext
    proc_open
    pcntl_alarm
    pcntl_signal
    +
    +
    + 重新检测 + 0){?> + 下一步 + + 下一步 + +
    +
    +
    + + + diff --git a/app/view/install/step3.html b/app/view/install/step3.html new file mode 100644 index 00000000..af1f2ad8 --- /dev/null +++ b/app/view/install/step3.html @@ -0,0 +1,234 @@ + + + + + 安装许可协议 - Powered by CRMEB + + + +
    +
    +

    logo

    +
    安装向导
    +
    +
    +
    +
    +
      +
    • 1检测环境
    • +
    • 2创建数据
    • +
    • 3完成安装
    • +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    数据库信息  
    数据库服务器:
    数据库服务器地址,一般为127.0.0.1
    数据库端口:
    数据库服务器端口,一般为3306
    数据库用户名:
    数据库密码:
    数据库名:
    数据库表前缀:
    建议使用默认,同一数据库安装多个CrmEb时需修改
    演示数据:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    reids数据库信息  
    服务器地址:
    reids服务器地址,一般为127.0.0.1
    端口号:
    reids端口,默认为6379
    数据库:
    reids数据库,默认为0,一般不做更改
    密码:
    reids数据库密码
    + + + + + + + + + + + + + + + + + + + + + + +
    管理员信息  
    管理员帐号:
    管理员密码:
    重复密码:
    + +
    +
    上一步 + +
    +
    +
    +
    + + + + +
    + + + diff --git a/app/view/install/step4.html b/app/view/install/step4.html new file mode 100644 index 00000000..8157f5f1 --- /dev/null +++ b/app/view/install/step4.html @@ -0,0 +1,77 @@ + + + + + 安装详细过程 - Powered by CRMEB + + + + +
    +
    +

    logo

    +
    安装向导
    +
    +
    +
    +
    +
      +
    • 1检测环境
    • +
    • 2创建数据
    • +
    • 3完成安装
    • +
    +
    +
    +
      +
    +
    + +
    + +
    + + + diff --git a/app/view/install/step5.html b/app/view/install/step5.html new file mode 100644 index 00000000..134ca444 --- /dev/null +++ b/app/view/install/step5.html @@ -0,0 +1,53 @@ + + + + + 安装许可协议 - Powered by CRMEB + + + + +
    +
    +

    logo

    +
    安装向导
    +
    +
    +
    +
    +
    安装完成,请重启服务后,进入后台管理 +

    为了您站点的安全,安装完成后即可将网站根目录下[public目录下]的“install”文件夹删除,或者/install/目录下创建install.lock文件防止重复安装。

    +

    + +
    +
    +
    +
    + + + + diff --git a/app/view/mobile/view.html b/app/view/mobile/view.html new file mode 100644 index 00000000..aff6f254 --- /dev/null +++ b/app/view/mobile/view.html @@ -0,0 +1,23 @@ + + + + + <?=$siteName?> + + + + + + \ No newline at end of file diff --git a/app/webscoket/Manager.php b/app/webscoket/Manager.php new file mode 100644 index 00000000..21e5d8a6 --- /dev/null +++ b/app/webscoket/Manager.php @@ -0,0 +1,234 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket; + + +use app\webscoket\handler\AdminHandler; +use app\webscoket\handler\MerchantHandler; +use app\webscoket\handler\ServiceHandler; +use app\webscoket\handler\UserHandler; +use Swoole\Server; +use Swoole\Websocket\Frame; +use think\Config; +use think\Event; +use think\facade\Cache; +use think\Request; +use think\response\Json; +use think\swoole\Websocket; +use think\swoole\websocket\Room; + +/** + * Class Manager + * @package app\webscoket + * @author xaboy + * @day 2020-04-29 + */ +class Manager extends Websocket +{ + + /** + * @var \Swoole\WebSocket\Server + */ + protected $server; + + /** + * @var Ping + */ + protected $pingService; + + /** + * @var int + */ + protected $cache_timeout; + + const USER_TYPE = ['admin', 'user', 'mer', 'ser']; + + /** + * Manager constructor. + * @param Server $server + * @param Room $room + * @param Event $event + * @param Ping $ping + * @param Config $config + */ + public function __construct(Server $server, Room $room, Event $event, Ping $ping, Config $config) + { + parent::__construct($server, $room, $event); + $this->pingService = $ping; + $this->cache_timeout = (int)($config->get('swoole.websocket.ping_timeout', 60000) / 1000) + 2; + app()->bind('websocket_handler_admin', AdminHandler::class); + app()->bind('websocket_handler_user', UserHandler::class); + app()->bind('websocket_handler_mer', MerchantHandler::class); + app()->bind('websocket_handler_ser', ServiceHandler::class); + } + + /** + * @param int $fd + * @param Request $request + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function onOpen($fd, Request $request) + { + $type = $request->get('type'); + $token = $request->get('token'); + if (!$token || !in_array($type, self::USER_TYPE)) { + return $this->server->close($fd); + } + try { + $data = $this->exec($type, 'login', compact('fd', 'request', 'token'))->getData(); + } catch (\Exception $e) { +// var_dump($e->getMessage()); + return $this->server->close($fd); + } + if (!isset($data['status']) || $data['status'] != 200 || !($data['data']['uid'] ?? null)) { +// var_dump($data); + return $this->server->close($fd); + + } + $type = array_search($type, self::USER_TYPE); + $this->login($type, $fd, $data['data']); + $this->pingService->createPing($fd, time(), $this->cache_timeout); + return $this->send($fd, app('json')->message('ping', ['now' => time()])); + } + + public function login($type, $fd, $data) + { + $key = '_ws_' . $type; + + Cache::sadd($key, $fd); + Cache::sadd($key . $data['uid'], $fd); + Cache::set('_ws_f_' . $fd, [ + 'type' => $type, + 'uid' => $data['uid'], + 'fd' => $fd, + 'payload' => $data['payload'] ?? null, + 'mer_id' => $data['mer_id'] ?? null + ], 3600); + + if (isset($data['mer_id'])) { + $groupKey = $key . '_group' . $data['mer_id']; + Cache::sadd($groupKey, $fd); + Cache::expire($groupKey, 3600); + } + + $this->refresh($type, $fd, $data['uid']); + } + + public function refresh($type, $fd, $uid) + { + $key = '_ws_' . $type; + Cache::expire($key, 3600); + Cache::expire($key . $uid, 3600); + Cache::expire('_ws_f_' . $fd, 3600); + } + + public function logout($type, $fd) + { + $data = Cache::get('_ws_f_' . $fd); + $key = '_ws_' . $type; + Cache::srem($key, $fd); + if ($data) { + Cache::delete('_ws_f_' . $fd); + Cache::srem($key . $data['uid'], $fd); + if (($data['mer_id'] ?? null) !== null) { + $groupKey = $key . '_group' . $data['mer_id']; + Cache::srem($groupKey, $fd); + } + } + } + + public static function merFd($merId) + { + return Cache::smembers('_ws_2_group' . $merId) ?: []; + } + + public static function userFd($type, $uid = '') + { + $key = '_ws_' . $type . $uid; + return Cache::smembers($key) ?: []; + } + + /** + * @param $type + * @param $method + * @param $result + * @return null|Json + * @author xaboy + * @day 2020-05-06 + */ + protected function exec($type, $method, $result) + { + $handler = app()->make('websocket_handler_' . $type); + if (!method_exists($handler, $method)) return null; + /** @var Json $response */ + return $handler->{$method}($result); + } + + /** + * @param Frame $frame + * @return bool + * @author xaboy + * @day 2020-04-29 + */ + public function onMessage(Frame $frame) + { + $info = Cache::get('_ws_f_' . $frame->fd); + $result = json_decode($frame->data, true) ?: []; + + if (!isset($result['type']) || !$result['type']) return true; + $this->refresh($info['type'], $frame->fd, $info['uid']); + if (($info['mer_id'] ?? null) !== null) { + $groupKey = '_ws_' . $info['type'] . '_group' . $info['mer_id']; + Cache::expire($groupKey, 3600); + } + if ($result['type'] == 'ping') { + return $this->send($frame->fd, app('json')->message('ping', ['now' => time()])); + } + + $data = $result['data'] ?? []; + $frame->uid = $info['uid']; + $frame->payload = $info['payload']; + /** @var Json $response */ + $response = $this->exec(self::USER_TYPE[$info['type']], $result['type'], compact('data', 'frame', 'info')); + if ($response) return $this->send($frame->fd, $response); + return true; + } + + protected function send($fd, Json $json) + { + $this->pingService->createPing($fd, time(), $this->cache_timeout); + if ($this->server->isEstablished($fd) && $this->server->exist($fd)) { + $this->server->push($fd, json_encode($json->getData())); + } + return true; + } + + /** + * @param int $fd + * @param int $reactorId + * @author xaboy + * @day 2020-04-29 + */ + public function onClose($fd, $reactorId) + { + $data = Cache::get('_ws_f_' . $fd); + if ($data) { + $this->logout($data['type'], $fd); + $this->exec(self::USER_TYPE[$data['type']], 'close', $data); + } + $this->pingService->removePing($fd); + } +} diff --git a/app/webscoket/Ping.php b/app/webscoket/Ping.php new file mode 100644 index 00000000..deaa477b --- /dev/null +++ b/app/webscoket/Ping.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket; + + +use think\facade\Cache; + +/** + * Class Ping + * @package app\webscoket + * @author xaboy + * @day 2020-04-29 + */ +class Ping +{ + /** + * @var \Redis + */ + protected $redis; + + + const CACHE_PINK_KEY = 'ws.p.'; + + + const CACHE_SET_KEY = 'ws.s'; + + + /** + * Ping constructor. + */ + public function __construct() + { + $this->redis = Cache::store('redis')->handler(); + $this->destroy(); + } + + /** + * @param $id + * @param $time + * @param int $timeout + * @author xaboy + * @day 2020-04-29 + */ + public function createPing($id, $time, $timeout = 0) + { + $this->updateTime($id, $time, $timeout); + $this->redis->sAdd(self::CACHE_SET_KEY, $id); + } + + /** + * @param $id + * @param $time + * @param int $timeout + * @author xaboy + * @day 2020-04-29 + */ + public function updateTime($id, $time, $timeout = 0) + { + $this->redis->set(self::CACHE_PINK_KEY . $id, $time, $timeout); + } + + /** + * @param $id + * @author xaboy + * @day 2020-05-06 + */ + public function removePing($id) + { + $this->redis->del(self::CACHE_PINK_KEY . $id); + $this->redis->del(self::CACHE_SET_KEY, $id); + } + + /** + * @param $id + * @return bool|string + * @author xaboy + * @day 2020-04-29 + */ + public function getLastTime($id) + { + return $this->redis->get(self::CACHE_PINK_KEY . $id); + } + + /** + * @author xaboy + * @day 2020-04-29 + */ + public function destroy() + { + $members = $this->redis->sMembers(self::CACHE_SET_KEY) ?: []; + foreach ($members as $k => $member) { + $members[$k] = self::CACHE_PINK_KEY . $member; + } + if (count($members)) + $this->redis->del(self::CACHE_SET_KEY, ...$members); + } +} diff --git a/app/webscoket/SwooleWorkerStart.php b/app/webscoket/SwooleWorkerStart.php new file mode 100644 index 00000000..a2b2b44a --- /dev/null +++ b/app/webscoket/SwooleWorkerStart.php @@ -0,0 +1,96 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket; + + +use app\common\repositories\store\service\StoreServiceUserRepository; +use crmeb\interfaces\ListenerInterface; +use Swoole\Server; +use Swoole\Timer; +use think\Config; +use think\facade\Cache; + +/** + * Class SwooleWorkerStart + * @package app\webscoket + * @author xaboy + * @day 2020-04-29 + */ +class SwooleWorkerStart implements ListenerInterface +{ + + /** + * @var \Swoole\WebSocket\Server + */ + protected $server; + + /** + * @var Config + */ + protected $config; + + /** + * SwooleWorkerStart constructor. + * @param Server $server + * @param Config $config + */ + public function __construct(Server $server, Config $config) + { + $this->server = $server; + $this->config = $config; + } + + /** + * @param $event + * @author xaboy + * @day 2020-04-29 + */ + public function handle($event): void + { + if (!env('INSTALLED', false)) return; + if ($this->server->worker_id == ($this->config->get('swoole.server.options.worker_num')) && $this->config->get('swoole.websocket.enable', false)) { + $keys = array_merge(Cache::keys('m_chat*'), Cache::keys('u_chat*')); + if (count($keys)) { + Cache::del(...$keys); + } + $this->ping(); + app()->make(StoreServiceUserRepository::class)->onlineDown(); + } + } + + /** + * @author xaboy + * @day 2020-05-06 + */ + protected function ping() + { + /** + * @var $pingService Ping + */ + $pingService = app()->make(Ping::class); + $server = $this->server; + $timeout = (int)($this->config->get('swoole.websocket.ping_timeout', 60000) / 1000); + Timer::tick(1500, function (int $timer_id) use (&$server, &$pingService, $timeout) { + $nowTime = time(); + foreach ($server->connections as $fd) { + if ($server->isEstablished($fd) && $server->exist($fd)) { + $last = $pingService->getLastTime($fd); + if ($last && ($nowTime - $last) > $timeout) { + $server->close($fd); + } + } + } + }); + } +} diff --git a/app/webscoket/handler/AdminHandler.php b/app/webscoket/handler/AdminHandler.php new file mode 100644 index 00000000..a892ad37 --- /dev/null +++ b/app/webscoket/handler/AdminHandler.php @@ -0,0 +1,98 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket\handler; + + +use app\common\repositories\system\admin\AdminRepository; +use crmeb\services\JwtTokenService; +use Firebase\JWT\ExpiredException; +use Swoole\Server; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use Throwable; + +/** + * Class Handler + * @package app\webscoket + * @author xaboy + * @day 2020-04-29 + */ +class AdminHandler +{ + /** + * @var Server + */ + protected $server; + + /** + * AdminHandler constructor. + * @param Server $server + */ + public function __construct(Server $server) + { + $this->server = $server; + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function test(array $data) + { + return app('json')->success($data); + } + + /** + * @param array $data + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function login(array $data) + { + $token = $data['token'] ?? ''; + if (!$token) return app('json')->fail('token 无效'); + + /** + * @var AdminRepository $repository + */ + $repository = app()->make(AdminRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + return app('json')->fail('token 已过期'); + } + if ('admin' != $payload->jti[1]) + return app('json')->fail('无效的 token'); + + $admin = $repository->get($payload->jti[0]); + if (!$admin) + return app('json')->fail('账号不存在'); +// if (!$admin['status']) +// return app('json')->fail('账号已被禁用'); + + return app('json')->success(['uid' => $admin->admin_id, 'data' => $admin->toArray()]); + } + +} diff --git a/app/webscoket/handler/MerchantHandler.php b/app/webscoket/handler/MerchantHandler.php new file mode 100644 index 00000000..7eaaa45d --- /dev/null +++ b/app/webscoket/handler/MerchantHandler.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket\handler; + + +use app\common\repositories\system\merchant\MerchantAdminRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\services\JwtTokenService; +use Firebase\JWT\ExpiredException; +use Swoole\Server; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use Throwable; + +/** + * Class Handler + * @package app\webscoket + * @author xaboy + * @day 2020-04-29 + */ +class MerchantHandler +{ + /** + * @var Server + */ + protected $server; + + /** + * MerchantHandler constructor. + * @param Server $server + */ + public function __construct(Server $server) + { + $this->server = $server; + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function test(array $data) + { + return app('json')->success($data); + } + + /** + * @param array $data + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function login(array $data) + { + $token = $data['token'] ?? ''; + if (!$token) return app('json')->fail('token 无效'); + /** + * @var MerchantAdminRepository $repository + */ + $repository = app()->make(MerchantAdminRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + return app('json')->fail('token 已过期'); + } + if ('mer' != $payload->jti[1]) + return app('json')->fail('无效的 token'); + + $admin = $repository->get($payload->jti[0]); + if (!$admin) + return app('json')->fail('账号不存在'); +// if (!$admin['status']) +// return app('json')->fail('账号已被禁用'); + + /** + * @var MerchantRepository $merchantRepository + */ + $merchantRepository = app()->make(MerchantRepository::class); + + $merchant = $merchantRepository->get($admin['mer_id']); + + if (!$merchant || !$merchant['status']) + return app('json')->fail('商户已被锁定'); + + return app('json')->success(['uid' => $admin->merchant_admin_id, 'mer_id' => $admin['mer_id'], 'data' => $admin->toArray()]); + } + +} diff --git a/app/webscoket/handler/ServiceHandler.php b/app/webscoket/handler/ServiceHandler.php new file mode 100644 index 00000000..5f51b3ad --- /dev/null +++ b/app/webscoket/handler/ServiceHandler.php @@ -0,0 +1,201 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket\handler; + + +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\store\service\StoreServiceUserRepository; +use crmeb\services\JwtTokenService; +use crmeb\services\SwooleTaskService; +use Firebase\JWT\ExpiredException; +use Swoole\Server; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use Throwable; + +/** + * Class UserHandler + * @package app\webscoket\handler + * @author xaboy + * @day 2020-04-29 + */ +class ServiceHandler +{ + /** + * @var Server + */ + protected $server; + + /** + * UserHandler constructor. + * @param Server $server + */ + public function __construct(Server $server) + { + $this->server = $server; + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function test(array $data) + { + return app('json')->success($data); + } + + /** + * @param array $data + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function login(array $data) + { + $token = $data['token'] ?? ''; + if (!$token) return app('json')->message('err_tip', '登录过期'); + + $repository = app()->make(StoreServiceRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + return app('json')->message('err_tip', '登录过期'); + } + if ('service' != $payload->jti[1]) + return app('json')->message('err_tip', '登录过期'); + $service = $repository->get($payload->jti[0]); + + if (!$service) + return app('json')->message('err_tip', '账号不存在'); + if (!$service['is_open']) + return app('json')->message('err_tip', '账号已被禁用'); + $this->switchServiceChat($service->uid, $data['fd'], 0, 0); + return app('json')->success(['uid' => $service->uid, 'payload' => [$service->service_id], 'data' => $service->toArray()]); + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function uid(array $data) + { + return app('json')->success(['uid' => $data['frame']->uid]); + } + + public function closeServiceChat($uid, $fd) + { + $lst = Cache::sMembers('m_chat' . $uid) ?: []; + foreach ($lst as $key) { + if (strpos($key, $fd . '/') === 0) { + Cache::srem('m_chat' . $uid, $key); + } + } + } + + public function service_chat_end(array $result) + { + $this->closeServiceChat($result['frame']->uid, $result['frame']->fd); + } + + public function service_chat_start(array $result) + { + $this->switchServiceChat($result['frame']->uid, $result['frame']->fd, $result['data']['mer_id'] ?? 0, $result['data']['uid']); + } + + + public function switchServiceChat($uid, $fd, $merId, $toUid) + { + $this->closeServiceChat($uid, $fd); + Cache::sadd('m_chat' . $uid, $fd . '/' . $merId . '/' . $toUid); + } + + + /** + * 商户给用户发 + * @param array $result + * @return \think\response\Json + */ + public function service_chat(array $result) + { + $data = $result['data']; + $frame = $result['frame']; + if (!isset($data['msn_type']) || !isset($data['msn']) || !isset($data['uid']) || !isset($data['mer_id'])) + return app('json')->message('err_tip', '数据格式错误'); + if (!$data['msn']) return app('json')->message('err_tip', '请输入发送内容'); + if (!in_array($data['msn_type'], [1, 2, 3, 4, 5, 6, 7, 8, 100])) + return app('json')->message('err_tip', '消息类型有误'); + $service = app()->make(StoreServiceRepository::class)->get($frame->payload[0]); + if (!$service || !$service['status'] || !$service['is_open']) + return app('json')->message('err_tip', '没有权限'); + $storeServiceLogRepository = app()->make(StoreServiceLogRepository::class); + if ($service->mer_id && !$storeServiceLogRepository->issetLog($data['uid'], $service->mer_id)) + return app('json')->message('err_tip', '不能主动发送给用户'); + + $this->switchServiceChat($frame->uid, $frame->fd, $service->mer_id, $data['uid']); + + $data['msn'] = trim(strip_tags(htmlspecialchars_decode($data['msn']))); + $data['mer_id'] = $service->mer_id; + $data['service_id'] = $service->service_id; + $data['send_type'] = 1; + try { + $storeServiceLogRepository->checkMsn($service->mer_id, $data['uid'], $data['msn_type'], $data['msn']); + } catch (ValidateException $e) { + return app('json')->message('err_tip', $e->getMessage()); + } + if ($data['msn_type'] == 100) { + if (!$storeServiceLogRepository->query(['service_log_id' => $data['msn']]) + ->where('create_time', '>', date('Y-m-d H:i:s', strtotime('- 120 seconds')))->where('mer_id', $data['mer_id'])->where('send_type', 1)->count()) { + return app('json')->message('err_tip', '消息不能撤回'); + } + } + $log = $storeServiceLogRepository->create($data); + if ($data['msn_type'] == 100) { + $storeServiceLogRepository->query(['service_log_id' => $data['msn']])->delete(); + } + app()->make(StoreServiceUserRepository::class)->updateInfo($log, false); + $storeServiceLogRepository->getSendData($log); + $log->set('service', $service->visible(['service_id', 'avatar', 'nickname'])->toArray()); + $log = $log->toArray(); + $log['send_time'] = strtotime($log['create_time']); + $log['send_date'] = date('H:i',strtotime($log['create_time'])); + SwooleTaskService::chatToUser([ + 'uid' => $data['uid'], + 'data' => $log, + 'except' => [$frame->fd] + ]); + + return app('json')->message('chat', $log); + } + + public function close($result) + { + $this->closeServiceChat($result['uid'], $result['fd']); + } + +} diff --git a/app/webscoket/handler/UserHandler.php b/app/webscoket/handler/UserHandler.php new file mode 100644 index 00000000..9da6ae17 --- /dev/null +++ b/app/webscoket/handler/UserHandler.php @@ -0,0 +1,325 @@ + +// +---------------------------------------------------------------------- + + +namespace app\webscoket\handler; + + +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\store\service\StoreServiceUserRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserRepository; +use crmeb\services\JwtTokenService; +use crmeb\services\SwooleTaskService; +use Firebase\JWT\ExpiredException; +use Swoole\Server; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\exception\ValidateException; +use think\facade\Cache; +use Throwable; + +/** + * Class UserHandler + * @package app\webscoket\handler + * @author xaboy + * @day 2020-04-29 + */ +class UserHandler +{ + /** + * @var Server + */ + protected $server; + + /** + * UserHandler constructor. + * @param Server $server + */ + public function __construct(Server $server) + { + $this->server = $server; + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function test(array $data) + { + return app('json')->success($data); + } + + /** + * @param array $data + * @return mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author xaboy + * @day 2020-05-06 + */ + public function login(array $data) + { + $token = $data['token'] ?? ''; + if ($token && strpos($token, 'Bearer') === 0) + $token = trim(substr($token, 6)); + if (!$token) return app('json')->message('err_tip', '登录过期'); + + /** + * @var UserRepository $repository + */ + $repository = app()->make(UserRepository::class); + $service = new JwtTokenService(); + try { + $payload = $service->parseToken($token); + } catch (ExpiredException $e) { + $repository->checkToken($token); + $payload = $service->decode($token); + } catch (Throwable $e) {//Token 过期 + return app('json')->message('err_tip', '登录过期'); + } + if ('user' != $payload->jti[1]) + return app('json')->message('err_tip', '登录过期'); + + $user = $repository->get($payload->jti[0]); + if (!$user) + return app('json')->message('err_tip', '账号不存在'); + if (!$user['status']) + return app('json')->message('err_tip', '账号状态已关闭'); + + return app('json')->success(['uid' => $user->uid, 'data' => $user->toArray()]); + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-06 + */ + public function uid(array $data) + { + return app('json')->success(['uid' => $data['frame']->uid]); + } + + public static function serviceOnline($uid, $toUid) + { + $lst = Cache::sMembers('m_chat' . $uid) ?: []; + foreach ($lst as $key) { + if (strpos($key, '/' . $toUid) !== false) { + return true; + } + } + return false; + } + + public static function userOnline($uid, $merId) + { + $lst = Cache::sMembers('u_chat' . $uid) ?: []; + foreach ($lst as $key) { + if (strpos($key, '/' . $merId) !== false) { + return true; + } + } + return false; + } + + public function closeServiceChat($uid, $fd) + { + $lst = Cache::sMembers('m_chat' . $uid) ?: []; + foreach ($lst as $key) { + if (strpos($key, $fd . '/') === 0) { + Cache::srem('m_chat' . $uid, $key); + } + } + } + + public function service_chat_end(array $result) + { + $this->closeServiceChat($result['frame']->uid, $result['frame']->fd); + } + + public function closeChat($uid, $fd) + { + $lst = Cache::sMembers('u_chat' . $uid) ?: []; + foreach ($lst as $key) { + if (strpos($key, $fd . '/') === 0) { + Cache::srem('u_chat' . $uid, $key); + } + } + } + + public function chat_end(array $result) + { + app()->make(StoreServiceUserRepository::class)->online($result['frame']->uid, 0); + $this->closeChat($result['frame']->uid, $result['frame']->fd); + } + + public function service_chat_start(array $result) + { + $this->switchServiceChat($result['frame']->uid, $result['frame']->fd, $result['data']['mer_id'] ?? 0, $result['data']['uid']); + } + + public function chat_start(array $result) + { + app()->make(StoreServiceUserRepository::class)->online($result['frame']->uid, 1); + $this->switchChat($result['frame']->uid, $result['frame']->fd, $result['data']['mer_id'] ?? 0); + } + + + public function switchServiceChat($uid, $fd, $merId, $toUid) + { + $this->closeServiceChat($uid, $fd); + Cache::sadd('m_chat' . $uid, $fd . '/' . $merId . '/' . $toUid); + } + + public function switchChat($uid, $fd, $merId) + { + $this->closeChat($uid, $fd); + Cache::sadd('u_chat' . $uid, $fd . '/' . $merId); + } + + /** + * 商户给用户发 + * @param array $result + * @return \think\response\Json + */ + public function service_chat(array $result) + { + $data = $result['data']; + $frame = $result['frame']; + if (!isset($data['msn_type']) || !isset($data['msn']) || !isset($data['uid']) || !isset($data['mer_id'])) + return app('json')->message('err_tip', '数据格式错误'); + if (!$data['msn']) return app('json')->message('err_tip', '请输入发送内容'); + if (!in_array($data['msn_type'], [1, 2, 3, 4, 5, 6, 7, 8, 100])) + return app('json')->message('err_tip', '消息类型有误'); + $service = app()->make(StoreServiceRepository::class)->getService($frame->uid, (int)$data['mer_id']); + if (!$service || !$service['status']) + return app('json')->message('err_tip', '没有权限'); + $storeServiceLogRepository = app()->make(StoreServiceLogRepository::class); + if ($service->mer_id && !$storeServiceLogRepository->issetLog($data['uid'], $service->mer_id)) + return app('json')->message('err_tip', '不能主动发送给用户'); + + $this->switchServiceChat($frame->uid, $frame->fd, $service->mer_id, $data['uid']); + + $data['msn'] = trim(strip_tags(htmlspecialchars_decode($data['msn']))); + $data['mer_id'] = $service->mer_id; + $data['service_id'] = $service->service_id; + $data['send_type'] = 1; + try { + $storeServiceLogRepository->checkMsn($service->mer_id, $data['uid'], $data['msn_type'], $data['msn']); + } catch (ValidateException $e) { + return app('json')->message('err_tip', $e->getMessage()); + } + if ($data['msn_type'] == 100) { + if (!$storeServiceLogRepository->query(['service_log_id' => $data['msn']]) + ->where('create_time', '>', date('Y-m-d H:i:s', strtotime('- 120 seconds')))->where('mer_id', $data['mer_id'])->where('send_type', 1)->count()) { + return app('json')->message('err_tip', '消息不能撤回'); + } + } + $log = $storeServiceLogRepository->create($data); + if ($data['msn_type'] == 100) { + $storeServiceLogRepository->query(['service_log_id' => $data['msn']])->delete(); + } + app()->make(StoreServiceUserRepository::class)->updateInfo($log, false); + $storeServiceLogRepository->getSendData($log); + $log->set('service', $service->visible(['service_id', 'avatar', 'nickname'])->toArray()); + $log = $log->toArray(); + $log['send_time'] = strtotime($log['create_time']); + $log['send_date'] = date('H:i', strtotime($log['create_time'])); + SwooleTaskService::chatToUser([ + 'uid' => $data['uid'], + 'data' => $log, + 'except' => [$frame->fd] + ]); + + return app('json')->message('chat', $log); + } + + /** + * 用户给商户发 + * @param array $result + * @return \think\response\Json + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + */ + public function send_chat(array $result) + { + $data = $result['data']; + $frame = $result['frame']; + if (!isset($data['msn_type']) || !isset($data['msn']) || !isset($data['mer_id'])) + return app('json')->message('err_tip', '数据格式错误'); + if (!$data['msn']) return app('json')->message('err_tip', '请输入发送内容'); + if (!in_array($data['msn_type'], [1, 2, 3, 4, 5, 6, 7, 8, 100])) + return app('json')->message('err_tip', '消息类型有误'); + if ($data['mer_id'] && !app()->make(MerchantRepository::class)->exists(intval($data['mer_id']))) + return app('json')->message('err_tip', '商户不存在'); + if (!$data['mer_id'] && systemConfig('is_open_service') != 1) + return app('json')->message('err_tip', '功能未开启'); + $service = app()->make(StoreServiceRepository::class)->getChatService($data['mer_id'], $frame->uid); + if (!$service) + return app('json')->message('err_tip', '该商户暂无有效客服'); + $data['msn'] = trim(strip_tags(htmlspecialchars_decode($data['msn']))); + if (!$data['msn']) + return app('json')->message('err_tip', '内容字符无效'); + $this->switchChat($frame->uid, $frame->fd, $data['mer_id']); + $data['uid'] = $frame->uid; + $data['service_id'] = $service->service_id; + $data['send_type'] = 0; + $storeServiceLogRepository = app()->make(StoreServiceLogRepository::class); + try { + $storeServiceLogRepository->checkMsn($data['mer_id'], $frame->uid, $data['msn_type'], $data['msn']); + } catch (ValidateException $e) { + return app('json')->message('err_tip', $e->getMessage()); + } + if ($data['msn_type'] == 100) { + if (!$storeServiceLogRepository->query(['service_log_id' => $data['msn']]) + ->where('create_time', '>', date('Y-m-d H:i:s', strtotime('- 120 seconds')))->where('uid', $data['uid'])->where('send_type', 0)->count()) { + return app('json')->message('err_tip', '消息不能撤回'); + } + } + $log = $storeServiceLogRepository->create($data); + if ($data['msn_type'] == 100) { + $storeServiceLogRepository->query(['service_log_id' => $data['msn']])->delete(); + } + app()->make(StoreServiceUserRepository::class)->updateInfo($log, true); + $storeServiceLogRepository->getSendData($log); + $log->user; + $log = $log->toArray(); + $log['send_time'] = strtotime($log['create_time']); + $log['send_date'] = date('H:i',strtotime($log['create_time'])); + //TODO 发送给客服,是否在线,发送提醒 + SwooleTaskService::chatToService([ + 'uid' => $service->uid, + 'data' => $log, + 'except' => [$frame->fd] + ]); + + return app('json')->message('chat', $log); + } + + public function close($result) + { + if ($result['type'] === 'user') { + app()->make(StoreServiceUserRepository::class)->online($result['uid'], 0); + $this->closeChat($result['uid'], $result['fd']); + } else { + $this->closeServiceChat($result['uid'], $result['fd']); + } + } + +} diff --git a/backup/.gitignore b/backup/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/backup/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/cert_crmeb.key b/cert_crmeb.key new file mode 100644 index 00000000..57fa0b50 --- /dev/null +++ b/cert_crmeb.key @@ -0,0 +1 @@ +COWDsrWL/cgzxUeJghO6eXRCc6RlQeR+xvgK43b4gxdareBkRRlfnUMBP2AqmF1xmUGMLnAl9e+udwsBVWooya8VGPz94dT0YY7mDIjFlsoKR3zhXMxg7ARVux22aR9xCKaLGX6/zM/gqSTDtyz+9rVRlakzSrvEE9/EFgVrOZlAbwSAsK0YiVafiBoaIt4gj64CyWjfhlJDJjheCZjsX+y+YrLtZskprX2ongF8C8mkyJ0g02cPcUvEiocLbbHUXj/ijNgiLU3NYLE5z+mVoxD3ek7q9hWVspplG6Mebl56u2HoJzgBrG0EX9E6ejV1Tcbo959qTEh9PgKC5LFhuA==, \ No newline at end of file diff --git a/cert_public.pam b/cert_public.pam new file mode 100644 index 00000000..e28d81d6 --- /dev/null +++ b/cert_public.pam @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu8tEgg4uBv72HX7/24YNJIuCs +pcYHOemMx2wyh72Ke9uRs36pQaSF7IvrVjXc1AL5GeFzQRGi80hcNu46tTPSNKlt +cakkPgFkanVNjkTkhdxrcOUSEce1WxdMSaM7rZFm3CfK0vGWQSVUZvIgUxjlCcqS +EyMvmfS9o4kGAVlBLQIDAQAB +-----END PUBLIC KEY----- diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..09e90fa2 --- /dev/null +++ b/composer.json @@ -0,0 +1,81 @@ +{ + "name": "topthink/think", + "description": "the new thinkphp framework", + "type": "project", + "keywords": [ + "framework", + "thinkphp", + "ORM" + ], + "homepage": "http://thinkphp.cn/", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "require": { + "php": ">=7.1.0", + "ext-json": "*", + "ext-openssl": "*", + "ext-gd": "*", + "ext-redis": "*", + "ext-zip": "*", + "ext-pdo": "*", + "ext-curl": "*", + "ext-bcmath": "*", + "ext-mbstring": "*", + "ext-swoole": "^4.4.0", + "topthink/framework": "6.0.7", + "topthink/think-orm": "^2.0", + "topthink/think-swoole": "3.1.2", + "firebase/php-jwt": "^5.0", + "overtrue/wechat": "3.3.33", + "xaboy/form-builder": "2.0.15", + "phpoffice/phpexcel": "^1.8", + "topthink/think-queue": "^3.0", + "topthink/think-image": "^1.0", + "aliyuncs/oss-sdk-php": "^2.3", + "qcloud/cos-sdk-v5": "^1.3", + "qiniu/php-sdk": "^7.2", + "gregwar/captcha": "^1.1", + "guzzle/guzzle": "~3.7", + "endroid/qr-code": "^3.8", + "phpoffice/phpspreadsheet": "^1.14", + "riverslei/payment": "^5.1", + "lizhichao/word": "^2.1", + "joypack/tencent-map": "^1.0", + "obs/esdk-obs-php": "^3.21", + "ucloud/ufile-php-sdk": "^1.0", + "swoole/ide-helper": "^4.8", + "alibabacloud/dysmsapi-20170525": "2.0.9", + "fastknife/ajcaptcha": "^1.1" + }, + "require-dev": { + "symfony/var-dumper": "^4.2", + "topthink/think-trace":"^1.0" + }, + "autoload": { + "psr-4": { + "app\\": "app", + "crmeb\\": "crmeb" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist" + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..d5fa651f --- /dev/null +++ b/composer.lock @@ -0,0 +1,5503 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "a1e4f8118804a0d4921567860412c9a2", + "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0|^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.x" + }, + "time": "2019-01-01T23:59:15+00:00" + }, + { + "name": "alibabacloud/credentials", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/aliyun/credentials-php.git", + "reference": "e79d4151ad8924c0cf79d4fe0ec151b8d7663a25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/credentials-php/zipball/e79d4151ad8924c0cf79d4fe0ec151b8d7663a25", + "reference": "e79d4151ad8924c0cf79d4fe0ec151b8d7663a25", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "alibabacloud/tea": "^3.0", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "php": ">=5.6" + }, + "require-dev": { + "composer/composer": "^1.8", + "drupal/coder": "^8.3", + "ext-dom": "*", + "ext-pcre": "*", + "ext-sockets": "*", + "ext-spl": "*", + "mikey179/vfsstream": "^1.6", + "monolog/monolog": "^1.24", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Credentials\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Alibaba Cloud Credentials for PHP", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibaba", + "alibabacloud", + "aliyun", + "client", + "cloud", + "credentials", + "library", + "sdk", + "tool" + ], + "support": { + "issues": "https://github.com/aliyun/credentials-php/issues", + "source": "https://github.com/aliyun/credentials-php" + }, + "time": "2021-06-08T10:49:34+00:00" + }, + { + "name": "alibabacloud/darabonba-openapi", + "version": "0.2.5", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/darabonba-openapi.git", + "reference": "e57268b72616ed146eea1b5749d96b33e1f75ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/darabonba-openapi/zipball/e57268b72616ed146eea1b5749d96b33e1f75ec3", + "reference": "e57268b72616ed146eea1b5749d96b33e1f75ec3", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "alibabacloud/credentials": "^1.1", + "alibabacloud/gateway-spi": "^0.0.1", + "alibabacloud/openapi-util": "^0.1.10", + "alibabacloud/tea-utils": "^0.2.0", + "php": ">5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Darabonba\\OpenApi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud OpenApi Client", + "support": { + "issues": "https://github.com/alibabacloud-sdk-php/darabonba-openapi/issues", + "source": "https://github.com/alibabacloud-sdk-php/darabonba-openapi/tree/0.2.5" + }, + "time": "2021-12-22T07:45:24+00:00" + }, + { + "name": "alibabacloud/dysmsapi-20170525", + "version": "2.0.9", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/Dysmsapi-20170525.git", + "reference": "f3098cdd4196aa42413e60fececcea08a3374ff1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/Dysmsapi-20170525/zipball/f3098cdd4196aa42413e60fececcea08a3374ff1", + "reference": "f3098cdd4196aa42413e60fececcea08a3374ff1", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "alibabacloud/darabonba-openapi": "^0.2.5", + "alibabacloud/endpoint-util": "^0.1.0", + "alibabacloud/openapi-util": "^0.1.10", + "alibabacloud/tea-utils": "^0.2.0", + "php": ">5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\SDK\\Dysmsapi\\V20170525\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Dysmsapi (20170525) SDK Library for PHP", + "support": { + "source": "https://github.com/alibabacloud-sdk-php/Dysmsapi-20170525/tree/2.0.9" + }, + "time": "2022-01-24T07:38:41+00:00" + }, + { + "name": "alibabacloud/endpoint-util", + "version": "0.1.1", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/endpoint-util.git", + "reference": "f3fe88a25d8df4faa3b0ae14ff202a9cc094e6c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/endpoint-util/zipball/f3fe88a25d8df4faa3b0ae14ff202a9cc094e6c5", + "reference": "f3fe88a25d8df4faa3b0ae14ff202a9cc094e6c5", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Endpoint\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Endpoint Library for PHP", + "support": { + "source": "https://github.com/alibabacloud-sdk-php/endpoint-util/tree/0.1.1" + }, + "time": "2020-06-04T10:57:15+00:00" + }, + { + "name": "alibabacloud/gateway-spi", + "version": "0.0.1", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/alibabacloud-gateway-spi.git", + "reference": "36ba38571acbf821cfd84555cdb1327cdbf86935" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/alibabacloud-gateway-spi/zipball/36ba38571acbf821cfd84555cdb1327cdbf86935", + "reference": "36ba38571acbf821cfd84555cdb1327cdbf86935", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "alibabacloud/credentials": "^1.1", + "php": ">5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Darabonba\\GatewaySpi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Gateway SPI Client", + "support": { + "source": "https://github.com/alibabacloud-sdk-php/alibabacloud-gateway-spi/tree/0.0.1" + }, + "time": "2021-12-07T04:41:11+00:00" + }, + { + "name": "alibabacloud/openapi-util", + "version": "0.1.11", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/openapi-util.git", + "reference": "61ee137955a25c9f5f33170babb6071d4bccf12c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/openapi-util/zipball/61ee137955a25c9f5f33170babb6071d4bccf12c", + "reference": "61ee137955a25c9f5f33170babb6071d4bccf12c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "alibabacloud/tea": "^3.1", + "alibabacloud/tea-utils": "^0.2", + "lizhichao/one-sm": "^1.5", + "php": ">5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\OpenApiUtil\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud OpenApi Util", + "support": { + "issues": "https://github.com/alibabacloud-sdk-php/openapi-util/issues", + "source": "https://github.com/alibabacloud-sdk-php/openapi-util/tree/0.1.11" + }, + "time": "2021-12-28T07:57:21+00:00" + }, + { + "name": "alibabacloud/tea", + "version": "3.1.23", + "source": { + "type": "git", + "url": "https://github.com/aliyun/tea-php.git", + "reference": "61fce993274edf6e7131af07256ed7723d97a85f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/tea-php/zipball/61fce993274edf6e7131af07256ed7723d97a85f", + "reference": "61fce993274edf6e7131af07256ed7723d97a85f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "*", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Client of Tea for PHP", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibabacloud", + "client", + "cloud", + "tea" + ], + "support": { + "issues": "https://github.com/aliyun/tea-php/issues", + "source": "https://github.com/aliyun/tea-php" + }, + "time": "2021-12-20T02:32:43+00:00" + }, + { + "name": "alibabacloud/tea-utils", + "version": "0.2.14", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/tea-utils.git", + "reference": "381df15cb4bdb58dbf596f94869ffd2ef680eddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/tea-utils/zipball/381df15cb4bdb58dbf596f94869ffd2ef680eddd", + "reference": "381df15cb4bdb58dbf596f94869ffd2ef680eddd", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "alibabacloud/tea": "^3.1", + "php": ">5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\Utils\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Tea Utils for PHP", + "support": { + "issues": "https://github.com/aliyun/tea-util/issues", + "source": "https://github.com/aliyun/tea-util" + }, + "time": "2021-02-02T10:10:58+00:00" + }, + { + "name": "aliyuncs/oss-sdk-php", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/aliyun/aliyun-oss-php-sdk.git", + "reference": "053d7ba9e798e4c09b9c5c1edab153d25ea9643a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/aliyun-oss-php-sdk/zipball/053d7ba9e798e4c09b9c5c1edab153d25ea9643a", + "reference": "053d7ba9e798e4c09b9c5c1edab153d25ea9643a", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "satooshi/php-coveralls": "~1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "OSS\\": "src/OSS" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aliyuncs", + "homepage": "http://www.aliyun.com" + } + ], + "description": "Aliyun OSS SDK for PHP", + "homepage": "http://www.aliyun.com/product/oss/", + "time": "2019-11-15T11:05:42+00:00" + }, + { + "name": "bacon/bacon-qr-code", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "eaac909da3ccc32b748a65b127acd8918f58d9b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/eaac909da3ccc32b748a65b127acd8918f58d9b0", + "reference": "eaac909da3ccc32b748a65b127acd8918f58d9b0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "dasprid/enum": "^1.0", + "ext-iconv": "*", + "php": "^7.1" + }, + "require-dev": { + "phly/keep-a-changelog": "^1.4", + "phpunit/phpunit": "^6.4", + "squizlabs/php_codesniffer": "^3.1" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "http://www.dasprids.de", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "time": "2018-04-25T17:53:56+00:00" + }, + { + "name": "dasprid/enum", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "631ef6e638e9494b0310837fa531bedd908fc22b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/631ef6e638e9494b0310837fa531bedd908fc22b", + "reference": "631ef6e638e9494b0310837fa531bedd908fc22b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require-dev": { + "phpunit/phpunit": "^6.4", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "time": "2017-10-25T22:45:27+00:00" + }, + { + "name": "doctrine/annotations", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2015-08-31T12:32:49+00:00" + }, + { + "name": "doctrine/cache", + "version": "v1.4.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "6433826dd02c9e5be8a127320dc13e7e6625d020" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/6433826dd02c9e5be8a127320dc13e7e6625d020", + "reference": "6433826dd02c9e5be8a127320dc13e7e6625d020", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": ">=3.7", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2015-11-02T18:33:51+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "time": "2019-10-30T14:39:59+00:00" + }, + { + "name": "endroid/qr-code", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/endroid/qr-code.git", + "reference": "a7e07d26fad46d7032b39a076f6c85e07757028d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/a7e07d26fad46d7032b39a076f6c85e07757028d", + "reference": "a7e07d26fad46d7032b39a076f6c85e07757028d", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "bacon/bacon-qr-code": "^2.0", + "ext-gd": "*", + "khanamiryan/qrcode-detector-decoder": "^1.0.2", + "myclabs/php-enum": "^1.5", + "php": ">=7.2", + "symfony/options-resolver": "^3.4||^4.4||^5.0", + "symfony/property-access": "^3.4||^4.4||^5.0" + }, + "require-dev": { + "endroid/quality": "dev-master" + }, + "suggest": { + "roave/security-advisories": "Avoids installation of package versions with vulnerabilities", + "symfony/security-checker": "Checks your composer.lock for vulnerabilities" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl" + } + ], + "description": "Endroid QR Code", + "homepage": "https://github.com/endroid/qr-code", + "keywords": [ + "bundle", + "code", + "endroid", + "php", + "qr", + "qrcode" + ], + "time": "2020-06-02T20:10:27+00:00" + }, + { + "name": "fastknife/ajcaptcha", + "version": "v1.1.5", + "source": { + "type": "git", + "url": "https://gitee.com/fastknife/aj-captcha.git", + "reference": "9e8eb95c444d2ff4d78d1d1d4d5cb1d29c084609" + }, + "require": { + "ext-gd": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-openssl": "*", + "intervention/image": "^2.5", + "php": ">=7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fastknife\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0-only" + ], + "authors": [ + { + "name": "bruce", + "email": "2777314125@qq.com" + } + ], + "description": "This is a behavior verification code PHP back-end implementation package", + "time": "2022-07-04T10:17:37+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v5.1.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "4566062c68f76f43d44f1643f4970fe89757d4c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/4566062c68f76f43d44f1643f4970fe89757d4c6", + "reference": "4566062c68f76f43d44f1643f4970fe89757d4c6", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "time": "2020-02-24T23:15:03+00:00" + }, + { + "name": "gregwar/captcha", + "version": "v1.1.8", + "source": { + "type": "git", + "url": "https://github.com/Gregwar/Captcha.git", + "reference": "6088ad3db59bc226423ad1476a9f0424b19b1866" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/6088ad3db59bc226423ad1476a9f0424b19b1866", + "reference": "6088ad3db59bc226423ad1476a9f0424b19b1866", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-gd": "*", + "ext-mbstring": "*", + "php": ">=5.3.0", + "symfony/finder": "*" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "type": "captcha", + "autoload": { + "psr-4": { + "Gregwar\\": "src/Gregwar" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jeremy Livingston", + "email": "jeremy.j.livingston@gmail.com" + } + ], + "description": "Captcha generator", + "homepage": "https://github.com/Gregwar/Captcha", + "keywords": [ + "bot", + "captcha", + "spam" + ], + "time": "2020-01-22T14:54:02+00:00" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "abandoned": "guzzlehttp/guzzle", + "time": "2015-03-18T18:23:50+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/master" + }, + "time": "2017-06-22T18:50:49+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.4.2" + }, + "time": "2017-03-20T17:10:46+00:00" + }, + { + "name": "intervention/image", + "version": "2.7.2", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "04be355f8d6734c826045d02a1079ad658322dad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/04be355f8d6734c826045d02a1079ad658322dad", + "reference": "04be355f8d6734c826045d02a1079ad658322dad", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "~1.1 || ^2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + }, + "laravel": { + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ], + "aliases": { + "Image": "Intervention\\Image\\Facades\\Image" + } + } + }, + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@intervention.io", + "homepage": "https://intervention.io/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "support": { + "issues": "https://github.com/Intervention/image/issues", + "source": "https://github.com/Intervention/image/tree/2.7.2" + }, + "funding": [ + { + "url": "https://paypal.me/interventionio", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + } + ], + "time": "2022-05-21T17:30:32+00:00" + }, + { + "name": "joypack/tencent-map", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://gitee.com/lphkxd/tencent-map", + "reference": "6421402667943496618d67db4dc277094d404638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/joypack/tencent-map/zipball/6421402667943496618d67db4dc277094d404638", + "reference": "6421402667943496618d67db4dc277094d404638", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Joypack\\Tencent\\Map\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "堪笑", + "email": "jixiang.f@gmail.com", + "homepage": "http://cli.life", + "role": "Developer" + } + ], + "description": "腾讯位置服务(WebService)", + "homepage": "https://github.com/joypack/tencent-map", + "keywords": [ + "LBS", + "腾讯位置服务" + ], + "time": "2020-11-26T13:13:58+00:00" + }, + { + "name": "khanamiryan/qrcode-detector-decoder", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git", + "reference": "89b57f2d9939dd57394b83f6ccbd3e1a74659e34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/89b57f2d9939dd57394b83f6ccbd3e1a74659e34", + "reference": "89b57f2d9939dd57394b83f6ccbd3e1a74659e34", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.6|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Zxing\\": "lib/" + }, + "files": [ + "lib/Common/customFunctions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ashot Khanamiryan", + "email": "a.khanamiryan@gmail.com", + "homepage": "https://github.com/khanamiryan", + "role": "Developer" + } + ], + "description": "QR code decoder / reader", + "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder/", + "keywords": [ + "barcode", + "qr", + "zxing" + ], + "time": "2020-04-19T16:18:51+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.66", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/021569195e15f8209b1c4bebb78bd66aa4f08c21", + "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-fileinfo": "*", + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7.26" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2020-03-17T18:58:12+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/08ef74e9be88100807a3b92cc9048a312bf01d6f", + "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "time": "2018-07-09T20:51:04+00:00" + }, + { + "name": "lizhichao/one-sm", + "version": "1.10", + "source": { + "type": "git", + "url": "https://github.com/lizhichao/sm.git", + "reference": "687a012a44a5bfd4d9143a0234e1060543be455a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lizhichao/sm/zipball/687a012a44a5bfd4d9143a0234e1060543be455a", + "reference": "687a012a44a5bfd4d9143a0234e1060543be455a", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "OneSm\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "tanszhe", + "email": "1018595261@qq.com" + } + ], + "description": "国密sm3", + "keywords": [ + "php", + "sm3" + ], + "support": { + "issues": "https://github.com/lizhichao/sm/issues", + "source": "https://github.com/lizhichao/sm/tree/1.10" + }, + "funding": [ + { + "url": "https://www.vicsdf.com/img/w.jpg", + "type": "custom" + }, + { + "url": "https://www.vicsdf.com/img/z.jpg", + "type": "custom" + } + ], + "time": "2021-05-26T06:19:22+00:00" + }, + { + "name": "lizhichao/word", + "version": "v2.1", + "source": { + "type": "git", + "url": "https://github.com/lizhichao/VicWord.git", + "reference": "f17172d45f505e7140da0bde2103defc13255326" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lizhichao/VicWord/zipball/f17172d45f505e7140da0bde2103defc13255326", + "reference": "f17172d45f505e7140da0bde2103defc13255326", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lizhichao\\Word\\": "Lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "tanszhe", + "email": "1018595261@qq.com" + } + ], + "description": "This is a participle library", + "time": "2020-07-30T07:33:06+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "myclabs/php-enum": "^1.5", + "php": ">= 7.1", + "psr/http-message": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "guzzlehttp/guzzle": ">= 6.3", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": ">= 7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "time": "2020-05-30T13:11:16+00:00" + }, + { + "name": "markbaker/complex", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "8eaa40cceec7bf0518187530b2e63871be661b72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/8eaa40cceec7bf0518187530b2e63871be661b72", + "reference": "8eaa40cceec7bf0518187530b2e63871be661b72", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.6.0|^7.0.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "2.*", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^4.8.35|^5.4.0", + "sebastian/phpcpd": "2.*", + "squizlabs/php_codesniffer": "^3.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + }, + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "time": "2020-03-11T20:15:49+00:00" + }, + { + "name": "markbaker/matrix", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "5348c5a67e3b75cd209d70103f916a93b1f1ed21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/5348c5a67e3b75cd209d70103f916a93b1f1ed21", + "reference": "5348c5a67e3b75cd209d70103f916a93b1f1ed21", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.6.0|^7.0.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "dev-master", + "phploc/phploc": "^4", + "phpmd/phpmd": "dev-master", + "phpunit/phpunit": "^5.7", + "sebastian/phpcpd": "^3.0", + "squizlabs/php_codesniffer": "^3.0@dev" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + }, + "files": [ + "classes/src/functions/adjoint.php", + "classes/src/functions/antidiagonal.php", + "classes/src/functions/cofactors.php", + "classes/src/functions/determinant.php", + "classes/src/functions/diagonal.php", + "classes/src/functions/identity.php", + "classes/src/functions/inverse.php", + "classes/src/functions/minors.php", + "classes/src/functions/trace.php", + "classes/src/functions/transpose.php", + "classes/src/operations/add.php", + "classes/src/operations/directsum.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "time": "2019-10-06T11:29:25+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.23.0" + }, + "time": "2017-06-19T01:22:40+00:00" + }, + { + "name": "myclabs/php-enum", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/5f36467c7a87e20fbdc51e524fd8f9d1de80187c", + "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^3.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "time": "2020-02-14T08:15:52+00:00" + }, + { + "name": "nesbot/carbon", + "version": "2.31.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "bbc0ab53f41a4c6f223c18efcdbd9bc725eb5d2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bbc0ab53f41a4c6f223c18efcdbd9bc725eb5d2d", + "reference": "bbc0ab53f41a4c6f223c18efcdbd9bc725eb5d2d", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/translation": "^3.4 || ^4.0 || ^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", + "kylekatarnls/multi-tester": "^1.1", + "phpmd/phpmd": "^2.8", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "^7.5 || ^8.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + }, + { + "name": "kylekatarnls", + "homepage": "http://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2020-03-01T11:11:58+00:00" + }, + { + "name": "nette/php-generator", + "version": "v3.3.4", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "8fe7e699dca7db186f56d75800cb1ec32e39c856" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/8fe7e699dca7db186f56d75800cb1ec32e39c856", + "reference": "8fe7e699dca7db186f56d75800cb1ec32e39c856", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "nette/utils": "^2.4.2 || ^3.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.4 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "time": "2020-02-09T14:39:09+00:00" + }, + { + "name": "nette/utils", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "2c17d16d8887579ae1c0898ff94a3668997fd3eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/2c17d16d8887579ae1c0898ff94a3668997fd3eb", + "reference": "2c17d16d8887579ae1c0898ff94a3668997fd3eb", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "~2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize() and toAscii()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "time": "2020-02-09T14:10:55+00:00" + }, + { + "name": "obs/esdk-obs-php", + "version": "3.21.6", + "source": { + "type": "git", + "url": "https://github.com/huaweicloud/huaweicloud-sdk-php-obs.git", + "reference": "690ea452f1dfdfbf867e279e6ee8afe25f422c6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/huaweicloud/huaweicloud-sdk-php-obs/zipball/690ea452f1dfdfbf867e279e6ee8afe25f422c6f", + "reference": "690ea452f1dfdfbf867e279e6ee8afe25f422c6f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "guzzlehttp/guzzle": "6.3.0", + "guzzlehttp/promises": "1.3.1", + "guzzlehttp/psr7": "1.4.2", + "monolog/monolog": "1.23.0", + "php": ">=5.6.0", + "psr/http-message": "1.0.1", + "psr/log": "~1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Obs\\": "Obs/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "OBS PHP SDK", + "keywords": [ + "OBS", + "php" + ], + "support": { + "source": "https://github.com/huaweicloud/huaweicloud-sdk-php-obs/tree/v3.21.6" + }, + "time": "2021-07-22T08:52:54+00:00" + }, + { + "name": "open-smf/connection-pool", + "version": "v1.0.15", + "source": { + "type": "git", + "url": "https://github.com/open-smf/connection-pool.git", + "reference": "f9289cb5ee61d3e901bc74ab745e5b2162461a1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/open-smf/connection-pool/zipball/f9289cb5ee61d3e901bc74ab745e5b2162461a1e", + "reference": "f9289cb5ee61d3e901bc74ab745e5b2162461a1e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "ext-swoole": ">=4.2.9", + "php": ">=7.0.0" + }, + "require-dev": { + "swoole/ide-helper": "@dev" + }, + "suggest": { + "ext-redis": "A PHP extension for Redis." + }, + "type": "library", + "autoload": { + "psr-4": { + "Smf\\ConnectionPool\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Xie Biao", + "email": "hhxsv5@sina.com" + } + ], + "description": "A common connection pool based on Swoole is usually used as the database connection pool.", + "homepage": "https://github.com/open-smf/connection-pool", + "keywords": [ + "connection-pool", + "database-connection-pool", + "swoole" + ], + "time": "2020-05-29T05:20:59+00:00" + }, + { + "name": "overtrue/socialite", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/overtrue/socialite.git", + "reference": "fda55f0acef43a144799b1957a8f93d9f5deffce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/overtrue/socialite/zipball/fda55f0acef43a144799b1957a8f93d9f5deffce", + "reference": "fda55f0acef43a144799b1957a8f93d9f5deffce", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "guzzlehttp/guzzle": "~5.0|~6.0", + "php": ">=5.4.0", + "symfony/http-foundation": "~2.6|~2.7|~2.8|~3.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Overtrue\\Socialite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "overtrue", + "email": "anzhengchao@gmail.com" + } + ], + "description": "A collection of OAuth 2 packages that extracts from laravel/socialite.", + "keywords": [ + "login", + "oauth", + "qq", + "social", + "wechat", + "weibo" + ], + "time": "2017-08-04T06:28:22+00:00" + }, + { + "name": "overtrue/wechat", + "version": "3.3.33", + "source": { + "type": "git", + "url": "https://github.com/w7corp/easywechat.git", + "reference": "78e5476df330754040d1c400d0bca640d5b77cb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/w7corp/easywechat/zipball/78e5476df330754040d1c400d0bca640d5b77cb7", + "reference": "78e5476df330754040d1c400d0bca640d5b77cb7", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "doctrine/cache": "1.4.*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "~6.2", + "monolog/monolog": "^1.17", + "overtrue/socialite": "^1.0.25", + "php": ">=5.5.0", + "pimple/pimple": "~3.0", + "symfony/http-foundation": "~2.6|~2.7|~2.8|~3.0", + "symfony/psr-http-message-bridge": "~0.3|^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.9", + "overtrue/phplint": "dev-master", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "EasyWeChat\\": "src/" + }, + "files": [ + "src/Payment/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "overtrue", + "email": "anzhengchao@gmail.com" + } + ], + "description": "微信SDK", + "keywords": [ + "sdk", + "wechat", + "weixin", + "weixin-sdk" + ], + "time": "2018-10-17T12:27:27+00:00" + }, + { + "name": "phpoffice/phpexcel", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PHPExcel.git", + "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/1441011fb7ecdd8cc689878f54f8b58a6805f870", + "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "php": "^5.2|^7.0" + }, + "require-dev": { + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "PHPExcel": "Classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "http://blog.maartenballiauw.be" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Franck Lefevre", + "homepage": "http://rootslabs.net" + }, + { + "name": "Mark Baker", + "homepage": "http://markbakeruk.net" + } + ], + "description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PHPExcel", + "keywords": [ + "OpenXML", + "excel", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "abandoned": "phpoffice/phpspreadsheet", + "time": "2018-11-22T23:07:24+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.14.1", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "2383aad5689778470491581442aab38cec41bf1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/2383aad5689778470491581442aab38cec41bf1d", + "reference": "2383aad5689778470491581442aab38cec41bf1d", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "maennchen/zipstream-php": "^2.1", + "markbaker/complex": "^1.4", + "markbaker/matrix": "^1.2", + "php": "^7.2", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0" + }, + "require-dev": { + "dompdf/dompdf": "^0.8.5", + "friendsofphp/php-cs-fixer": "^2.16", + "jpgraph/jpgraph": "^4.0", + "mpdf/mpdf": "^8.0", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^8.5", + "squizlabs/php_codesniffer": "^3.5", + "tecnickcom/tcpdf": "^6.3" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "time": "2020-07-19T09:51:35+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "e55d12f9d6a0e7f9c85992b73df1267f46279930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/e55d12f9d6a0e7f9c85992b73df1267f46279930", + "reference": "e55d12f9d6a0e7f9c85992b73df1267f46279930", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3.4|^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2020-03-03T09:12:48+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "qcloud/cos-sdk-v5", + "version": "v1.3.4", + "source": { + "type": "git", + "url": "https://github.com/tencentyun/cos-php-sdk-v5.git", + "reference": "1b32aa422f6dffe4ea411e5095e4b0da9135551b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tencentyun/cos-php-sdk-v5/zipball/1b32aa422f6dffe4ea411e5095e4b0da9135551b", + "reference": "1b32aa422f6dffe4ea411e5095e4b0da9135551b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "guzzle/guzzle": "~3.7", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Qcloud\\Cos\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "yaozongyou", + "email": "yaozongyou@vip.qq.com" + }, + { + "name": "lewzylu", + "email": "327874225@qq.com" + } + ], + "description": "PHP SDK for QCloud COS", + "keywords": [ + "cos", + "php", + "qcloud" + ], + "time": "2019-09-02T12:08:44+00:00" + }, + { + "name": "qiniu/php-sdk", + "version": "v7.2.10", + "source": { + "type": "git", + "url": "https://github.com/qiniu/php-sdk.git", + "reference": "d89987163f560ebf9dfa5bb25de9bd9b1a3b2bd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/qiniu/php-sdk/zipball/d89987163f560ebf9dfa5bb25de9bd9b1a3b2bd8", + "reference": "d89987163f560ebf9dfa5bb25de9bd9b1a3b2bd8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Qiniu\\": "src/Qiniu" + }, + "files": [ + "src/Qiniu/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Qiniu", + "email": "sdk@qiniu.com", + "homepage": "http://www.qiniu.com" + } + ], + "description": "Qiniu Resource (Cloud) Storage SDK for PHP", + "homepage": "http://developer.qiniu.com/", + "keywords": [ + "cloud", + "qiniu", + "sdk", + "storage" + ], + "time": "2019-10-28T10:23:23+00:00" + }, + { + "name": "riverslei/payment", + "version": "v5.1.0", + "source": { + "type": "git", + "url": "https://github.com/helei112g/payment.git", + "reference": "77f671b68b0285a6af77dc7c5afa36eabcae35aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/helei112g/payment/zipball/77f671b68b0285a6af77dc7c5afa36eabcae35aa", + "reference": "77f671b68b0285a6af77dc7c5afa36eabcae35aa", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-bcmath": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "guzzlehttp/guzzle": "~6.0", + "php": ">=7.0" + }, + "require-dev": { + "codeception/codeception": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Payment\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Leo", + "email": "dayugog@gmail.com", + "homepage": "https://dayutalk.cn" + } + ], + "description": "支付宝支付、微信支付、招商一网通支付php SDK。方便快速接入,最完整的开源支付 php sdk", + "homepage": "http://helei112g.github.io/payment", + "keywords": [ + "alipay", + "weixin", + "一网通", + "微信支付", + "招商一网通", + "支付宝支付", + "集成支付接口SDK" + ], + "time": "2020-05-04T03:07:17+00:00" + }, + { + "name": "swoole/ide-helper", + "version": "4.8.7", + "source": { + "type": "git", + "url": "https://github.com/swoole/ide-helper.git", + "reference": "62d306dcfdb7c2cd21768386955af9de387163f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/62d306dcfdb7c2cd21768386955af9de387163f9", + "reference": "62d306dcfdb7c2cd21768386955af9de387163f9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Team Swoole", + "email": "team@swoole.com" + } + ], + "description": "IDE help files for Swoole.", + "time": "2022-02-23T01:04:01+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337", + "reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "time": "2020-05-27T08:34:37+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.52", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0", + "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2018-11-21T14:20:20+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2020-02-14T07:42:58+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v3.4.38", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "4d440be93adcfd5e4ee0bdc7acd1c3260625728f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4d440be93adcfd5e4ee0bdc7acd1c3260625728f", + "reference": "4d440be93adcfd5e4ee0bdc7acd1c3260625728f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php70": "~1.6" + }, + "require-dev": { + "symfony/expression-language": "~2.8|~3.0|~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2020-02-06T08:18:51+00:00" + }, + { + "name": "symfony/inflector", + "version": "v5.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/inflector.git", + "reference": "fddb4262dd136b34db993a2a3488713df91e4856" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/inflector/zipball/fddb4262dd136b34db993a2a3488713df91e4856", + "reference": "fddb4262dd136b34db993a2a3488713df91e4856", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/string": "^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Inflector Component", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "abandoned": "EnglishInflector from the String component", + "time": "2020-05-20T17:43:50+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "663f5dd5e14057d1954fe721f9709d35837f2447" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/663f5dd5e14057d1954fe721f9709d35837f2447", + "reference": "663f5dd5e14057d1954fe721f9709d35837f2447", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony OptionsResolver Component", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "time": "2020-05-23T13:08:13+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-05-12T16:14:59+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "e094b0770f7833fdf257e6ba4775be4e258230b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e094b0770f7833fdf257e6ba4775be4e258230b2", + "reference": "e094b0770f7833fdf257e6ba4775be4e258230b2", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2020-05-12T16:47:27+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.24.0" + }, + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0" + }, + "time": "2021-11-30T18:21:41+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "type": "metapackage", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0" + }, + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/5e30b2799bc1ad68f7feb62b60a73743589438dd", + "reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-05-12T16:47:27+00:00" + }, + { + "name": "symfony/process", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/bf9166bac906c9e69fb7a11d94875e7ced97bcd7", + "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2020-02-07T20:06:44+00:00" + }, + { + "name": "symfony/property-access", + "version": "v5.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "638b96246da68810484a5a46ff397e9326f42afc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/638b96246da68810484a5a46ff397e9326f42afc", + "reference": "638b96246da68810484a5a46ff397e9326f42afc", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/inflector": "^4.4|^5.0", + "symfony/polyfill-php80": "^1.15", + "symfony/property-info": "^5.1.1" + }, + "require-dev": { + "symfony/cache": "^4.4|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony PropertyAccess Component", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "time": "2020-06-04T09:56:18+00:00" + }, + { + "name": "symfony/property-info", + "version": "v5.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "75d79faca45092829b55eb83f73068e34c6567c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/75d79faca45092829b55eb83f73068e34c6567c5", + "reference": "75d79faca45092829b55eb83f73068e34c6567c5", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15", + "symfony/string": "^5.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0", + "symfony/dependency-injection": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "~1.7", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/cache": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "suggest": { + "phpdocumentor/reflection-docblock": "To use the PHPDoc", + "psr/cache-implementation": "To cache results", + "symfony/doctrine-bridge": "To use Doctrine metadata", + "symfony/serializer": "To use Serializer metadata" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Property Info Component", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "time": "2020-06-15T11:50:15+00:00" + }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad", + "reference": "9ab9d71f97d5c7d35a121a7fb69f74fee95cd0ad", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^3.4 || ^4.0" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "symfony/phpunit-bridge": "^3.4.20 || ^4.0", + "zendframework/zend-diactoros": "^1.4.1 || ^2.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "http://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "time": "2019-03-11T18:22:33+00:00" + }, + { + "name": "symfony/string", + "version": "v5.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "ac70459db781108db7c6d8981dd31ce0e29e3298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/ac70459db781108db7c6d8981dd31ce0e29e3298", + "reference": "ac70459db781108db7c6d8981dd31ce0e29e3298", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony String component", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "time": "2020-06-11T12:16:36+00:00" + }, + { + "name": "symfony/translation", + "version": "v5.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "e9b93f42a1fd6aec6a0872d59ee5c8219a7d584b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/e9b93f42a1fd6aec6a0872d59ee5c8219a7d584b", + "reference": "e9b93f42a1fd6aec6a0872d59ee5c8219a7d584b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2" + }, + "conflict": { + "symfony/config": "<4.4", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" + }, + "provide": { + "symfony/translation-implementation": "2.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/http-kernel": "^5.0", + "symfony/intl": "^4.4|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2020-02-04T07:41:34+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/8cc682ac458d75557203b2f2f14b0b92e1c744ed", + "reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2.5" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "topthink/framework", + "version": "v6.0.7", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "db8fe22520a9660dd5e4c87e304034ac49e39270" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/db8fe22520a9660dd5e4c87e304034ac49e39270", + "reference": "db8fe22520a9660dd5e4c87e304034ac49e39270", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.1.0", + "psr/container": "~1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "time": "2021-01-25T14:48:29+00:00" + }, + { + "name": "topthink/think-factory", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-factory.git", + "reference": "b8080a6472aae1cff47ceb8c30feec3c2835364b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-factory/zipball/b8080a6472aae1cff47ceb8c30feec3c2835364b", + "reference": "b8080a6472aae1cff47ceb8c30feec3c2835364b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "topthink/framework": "^6.0.0", + "topthink/think-helper": "^3.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "abandoned": true, + "time": "2019-04-15T06:55:28+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.3", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "4d85dfd3778623bbb1de3648f1dcd0c82f4439f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/4d85dfd3778623bbb1de3648f1dcd0c82f4439f4", + "reference": "4d85dfd3778623bbb1de3648f1dcd0c82f4439f4", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "time": "2019-09-30T02:36:48+00:00" + }, + { + "name": "topthink/think-image", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-image.git", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-image/zipball/8586cf47f117481c6d415b20f7dedf62e79d5512", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-gd": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "topthink/framework": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP5 Image Package", + "time": "2016-09-29T06:05:43+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.39", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "39a9d0a0e52d9b8bad9d98484d8484cdf5b683a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/39a9d0a0e52d9b8bad9d98484d8484cdf5b683a7", + "reference": "39a9d0a0e52d9b8bad9d98484d8484cdf5b683a7", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "stubs/load_stubs.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "time": "2021-02-26T10:20:00+00:00" + }, + { + "name": "topthink/think-queue", + "version": "v3.0.4", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-queue.git", + "reference": "a993295b68a483dc3cb2c0fee05683908fa2572e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-queue/zipball/a993295b68a483dc3cb2c0fee05683908fa2572e", + "reference": "a993295b68a483dc3cb2c0fee05683908fa2572e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "nesbot/carbon": "^2.16", + "symfony/process": "^4.2", + "topthink/framework": "^6.0.0", + "topthink/think-factory": "^1.0.0", + "topthink/think-helper": "^3.0.4" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^6.2", + "topthink/think-migration": "^3.0.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\queue\\Service" + ], + "config": { + "queue": "src/config.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/common.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP5 Queue Package", + "time": "2019-10-13T03:51:32+00:00" + }, + { + "name": "topthink/think-swoole", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-swoole.git", + "reference": "eb7f78b7eb53dde79257f4254fe61f9514f3c7d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-swoole/zipball/eb7f78b7eb53dde79257f4254fe61f9514f3c7d8", + "reference": "eb7f78b7eb53dde79257f4254fe61f9514f3c7d8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "ext-swoole": ">=4.4.8", + "nette/php-generator": "^3.2", + "open-smf/connection-pool": "~1.0", + "php": ">7.1", + "swoole/ide-helper": "^4.3", + "symfony/finder": "^4.3.2|^5.1", + "topthink/framework": "^6.0" + }, + "require-dev": { + "symfony/var-dumper": "^4.3|^5.1", + "topthink/think-tracing": "^1.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\swoole\\Service" + ], + "config": { + "swoole": "src/config/swoole.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\swoole\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "Swoole extend for thinkphp", + "time": "2021-02-02T07:26:09+00:00" + }, + { + "name": "ucloud/ufile-php-sdk", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/yufeiminds/Ufile-php-sdk.git", + "reference": "42f739ecd55dec488e9b2185795cdc5ea7be12d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yufeiminds/Ufile-php-sdk/zipball/42f739ecd55dec488e9b2185795cdc5ea7be12d0", + "reference": "42f739ecd55dec488e9b2185795cdc5ea7be12d0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.6.0", + "ucloud/ufile-php-sdk": "1.0.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "UCloud\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "MadScientist", + "email": "superdinghh@gmail.com" + } + ], + "description": "UCloud Resource (Cloud) Storage SDK for PHP", + "keywords": [ + "cloud", + "sdk", + "storage", + "ucloud" + ], + "support": { + "source": "https://github.com/yufeiminds/Ufile-php-sdk/tree/1.0.1" + }, + "time": "2018-05-08T02:37:11+00:00" + }, + { + "name": "xaboy/form-builder", + "version": "2.0.15", + "source": { + "type": "git", + "url": "https://github.com/xaboy/form-builder.git", + "reference": "20cf96927c7aed273dd0db5b2c7c83f56e535bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/xaboy/form-builder/zipball/20cf96927c7aed273dd0db5b2c7c83f56e535bf1", + "reference": "20cf96927c7aed273dd0db5b2c7c83f56e535bf1", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "doctrine/annotations": "1.2.7", + "ext-json": "*", + "php": ">=5.4.0", + "symfony/http-foundation": "~2.6|~2.7|~2.8|~3.0|~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "FormBuilder\\": "./src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "xaboy", + "email": "xaboy2005@qq.com" + } + ], + "description": "PHP表单生成器,快速生成现代化的form表单。包含复选框、单选框、输入框、下拉选择框等元素以及,省市区三级联动,时间选择,日期选择,颜色选择,文件/图片上传等功能。", + "homepage": "https://github.com/xaboy/form-builder", + "keywords": [ + "dynamic-form", + "element-ui", + "form", + "form-create", + "form-generator", + "iview" + ], + "time": "2020-04-15T09:57:04+00:00" + } + ], + "packages-dev": [ + { + "name": "symfony/polyfill-php72", + "version": "v1.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.24.0" + }, + "time": "2021-05-27T09:17:38+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "2572839911702b0405479410ea7a1334bfab0b96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2572839911702b0405479410ea7a1334bfab0b96", + "reference": "2572839911702b0405479410ea7a1334bfab0b96", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2020-02-24T13:10:00+00:00" + }, + { + "name": "topthink/think-trace", + "version": "v1.2", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "4589d06a07945d57478cc2236f4b23d51ff919cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/4589d06a07945d57478cc2236f4b23d51ff919cc", + "reference": "4589d06a07945d57478cc2236f4b23d51ff919cc", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "time": "2019-10-17T02:14:09+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.0", + "ext-json": "*", + "ext-openssl": "*", + "ext-gd": "*", + "ext-redis": "*", + "ext-zip": "*", + "ext-pdo": "*", + "ext-curl": "*", + "ext-bcmath": "*", + "ext-mbstring": "*", + "ext-swoole": "^4.4.0" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/config/admin.php b/config/admin.php new file mode 100644 index 00000000..5b4054e1 --- /dev/null +++ b/config/admin.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +return [ + //token 有效期 + 'token_exp' => 6, //6小时 + //token超时多久可自动续期(后台) + 'token_valid_exp' => 30, //30分钟 + //token超时多久可自动续期(用户) + 'user_token_valid_exp' => 7, //7天 + //登录验证码有效期 + 'captcha_exp' => 30, //30分钟 + 'admin_prefix' => 'admin', + 'merchant_prefix' => 'merchant', + 'service_prefix' => 'kefu', + 'api_admin_prefix' => 'sys', + 'api_merchant_prefix' => 'mer', + 'api_service_prefix' => 'ser', + 'vic_word_status' => 0, +]; diff --git a/config/ajcaptcha.php b/config/ajcaptcha.php new file mode 100644 index 00000000..ad91bcde --- /dev/null +++ b/config/ajcaptcha.php @@ -0,0 +1,56 @@ + '', //自定义字体包路径, 不填使用默认值 + //文字验证码 + 'click_world' => [ + 'backgrounds' => [] + ], + //滑动验证码 + 'block_puzzle' => [ + /*背景图片路径, 不填使用默认值, 支持string与array两种数据结构。string为默认图片的目录,array索引数组则为具体图片的地址*/ + 'backgrounds' => [ + public_path().'static/ajcaptcha/1.jpg', + public_path().'static/ajcaptcha/2.jpg', + public_path().'static/ajcaptcha/3.jpg', + public_path().'static/ajcaptcha/4.jpg', + public_path().'static/ajcaptcha/5.jpg', + public_path().'static/ajcaptcha/6.jpg', + ], + /*模板图,格式同上支持string与array*/ + 'templates' => [], + + 'offset' => 10, //容错偏移量 + + 'is_cache_pixel' => true, //是否开启缓存图片像素值,开启后能提升服务端响应性能(但要注意更换图片时,需要清除缓存) + + 'is_interfere' => true, //开启干扰图 + ], + //水印 + 'watermark' => [ + 'fontsize' => 12, + 'color' => '#000000', + 'text' => '' + ], + 'cache' => [ + //若您使用了框架,并且想使用类似于redis这样的缓存驱动,则应换成框架的中的缓存驱动 + 'constructor' => \Fastknife\Utils\CacheUtils::class, + 'method' => [ + //遵守PSR-16规范不需要设置此项(tp6, laravel,hyperf)。如tp5就不支持(tp5缓存方法是rm,所以要配置为"delete" => "rm") + /** + 'get' => 'get', //获取 + 'set' => 'set', //设置 + 'delete' => 'delete',//删除 + 'has' => 'has' //key是否存在 + */ + ], + 'options' => [ + //如果您依然使用\Fastknife\Utils\CacheUtils做为您的缓存驱动,那么您可以自定义缓存配置。 + 'expire' => 300,//缓存有效期 (默认为0 表示永久缓存) + 'prefix' => '', //缓存前缀 + 'path' => '', //缓存目录 + 'serialize' => [], //缓存序列化和反序列化方法 + ] + ] +]; diff --git a/config/app.php b/config/app.php new file mode 100644 index 00000000..5126c3ba --- /dev/null +++ b/config/app.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 应用设置 +// +---------------------------------------------------------------------- + +return [ + 'app_key' => env('app_key', 'VliwSuvne'), + // 应用地址 + 'app_host' => env('app.host', ''), + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 是否启用事件 + 'with_event' => true, + // 默认应用 + 'default_app' => 'index', + // 默认时区 + 'default_timezone' => 'Asia/Shanghai', + + // 应用映射(自动多应用模式有效) + 'app_map' => [], + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => [ + 'common', 'websocket' + ], + + // 异常页面的模板文件 + 'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl', + + // 错误显示信息,非调试模式有效 + 'error_message' => '页面错误!请稍后再试~', + // 显示错误信息 + 'show_error_msg' => false, +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 00000000..15796fa0 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,62 @@ + +// +---------------------------------------------------------------------- + + +// +---------------------------------------------------------------------- +// | 缓存设置 +// +---------------------------------------------------------------------- + +return [ + // 默认缓存驱动 + 'default' => env('INSTALLED', false) ? env('cache.driver', 'redis') : 'file', + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + 'redis' => [ + // 驱动方式 + 'type' => 'Redis', + // 服务器地址 + 'host' => env('redis.redis_hostname', '127.0.0.1'), + // 端口 + 'port' => env('redis.port', '6379'), + // 密码 + 'password' => env('redis.redis_password', ''), + // 数据库 0号数据库 + 'select' => (int)env('redis.select', 0), + ], + // 更多的缓存连接 + ], + + //缓存key名前缀 + 'crmeb_key' => [ + 'category' => 'category_', + 'product' => 'product_', + 'brand' => 'brand_', + 'community' => 'community_', + 'topic' => 'topic_', + 'system' => 'system_', + 'group_data' => 'group_data_', + ], +]; diff --git a/config/console.php b/config/console.php new file mode 100644 index 00000000..28d5d0dd --- /dev/null +++ b/config/console.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 控制台配置 +// +---------------------------------------------------------------------- +return [ + // 指令定义 + 'commands' => [ + //自动同步路由权限 + 'menu' => 'app\command\updateAuth', + //将所有商品加入到spu表 + 'spu' => 'app\command\updateSpu', + //整理路由权限 + 'menu:format' => 'app\command\FormatMenuPath', + //清除缓存素材 + 'clear:attachment' => 'app\command\ClearCacheAttachment', + //版本更新 + 'version:update' => 'app\command\VersionUpdate', + //清除所有 除配置相关之外的数据 + 'clear:merchant' => 'app\command\ClearMerchantData', + //清除所有已删除的商户的商品相关数据 + 'clear:redundancy' => 'app\command\ClearRedundancy', + //重制平台管理员的密码 + 'reset:password' => 'app\command\resetPassword', + //修改图片地址前缀 + 'reset:imagePath' => 'app\command\resetImagePath', + //清除登录限制 + 'clear:cache' => 'app\command\clearCache', + //更新热卖榜单 + 'change:hotTop' => 'app\command\changeHotTop', + ], +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 00000000..4aba5c1d --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | Cookie设置 +// +---------------------------------------------------------------------- +return [ + // cookie 保存时间 + 'expire' => 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, +]; diff --git a/config/crmeb.php b/config/crmeb.php new file mode 100644 index 0000000000000000000000000000000000000000..971975394e146f8bf6dc242333eda7fab2dec5c9 GIT binary patch literal 4560 zcmdT{d2HL|8BUY9ZJf*T5!*kXu@gISV#jHkCUI`tX?(>=ocq4))Hxj6u^k^t>;W3E z0RtgAM79>#80Fpy72TMsZGxeV9S9XFD2$CX&4AHTP%Bzi*xoO{&x>7EL;G`oCQ4pC z-}64t^FF`&CXdr2c7*(nMc=G@aeTo&X?NI*<-VZXz2G2!T#}cF-AiKotfN@oz5RQ! z1^w9)`akia+b^D7^!XbdI-nSW4=e8ad6q-Lk4$t{| zw5kfLk4vYS=^|=xD^JI2C%mS-U^8t`W}D%k3K3CUJT){hJh4)uk=iH2LVcc)YcX=U zIsv!d^6RF#AD{{EFu24VA@bHqx>ynQkj%i;3e3D*o7Sq;=JAU7w4(gHG%8)d^YggT zsKb^?b(F2u1uOT)EOZ0GH(M-R`W~3jv{t)4fhZ&=xPRpQsHfq-O;FLLF;|R|w2jOI`wo z#0fgUup4;T3p{*v<-*2|Jk;Fu6%qCMcTfH!k;%dvn6&?gN%9rf^&}4pj>wC6(A@MD zadcoH4hZ``L%8?QPadqLb|As{W=GrB|h2Xee(iRrzNlv4CkN zR9&|mE1~%p8HS9?C0AA&ZH&V2&MpWl_Af{qlXj8F!#C;Sf7wN%qSj#->!)vh<<398 z{;d}-oIHQ-#PJulE^M7YeEx6Wd-X5Ref;g$5tFAjPHbL!_SErHr!H=uJ@@I^k1irj zZr-)IC0ir)-~%4egxl{;+dBRW#)sE9NY%BHPEhp-X!7nmdtSVB%y5DiSG9GdUb^bf zn^l=uy9=ipQh5B_T`lSDjcc*;pj}fi+c4*%1bobymc|fuaJfZeE(jIQ&&>D~Vo$(t z^U91tr+vD?6WzT(lEp|-7e%s1+A{QPTY@h@)tp1YWM3p|GLeT?tcL(-QV*K6Ta)$h z+RN(O#^w_hmF&$}+?(}C)ucDkgeUnV4+nvV6yU)|knV29Jg8VVb9dr|9d9P;;bRk- z5BWGBUiOgrkd5=9CPHE`U`4V0BoBO?5AuFeQBv#+Er)d0H0B}K&3b#tMS2tE!#r#= z2EO>|Jx?p|eyQWRahy?0vxe|e*zfU7ds_xs&ef*OJPpdIxGzSpe{i&ZInl^Ke>`c`F)QeS2^ocW@BxN3Q1#L3?U6G$93eI25RrxM_*o)LNUd9&&*PRYKYafCo7!%CMdGRttF3af#r0cFWPd*ug-@ zS)BoTXrj`&171=O!&nb-MfC%QRN)*U1aGoof{XKeX{l-QBm-ZZh)%`~MrT4rB_6iR zW8~Q?n^xJJ4kIU>!bFNfSv?LsjDGT#SAEabPunpDyL(FFYN%31gUvdhX=QS5Cg|3) zqsuw$u4%Wk-$1tzlo4T7prFdDs-KQb_+xwbySYXQ1u*bHlWq9w>41l6*v09MO_tt} z@~;5CdZyj|75!XVQ@yX$yH-}Zusxx5iD_=B^)vOf^eN#~_5ARn{D4fUu9((GVp3^{}#i^(^!! z7^EIV*cV|DxlKLhL1G|pHw|C^yBOrfnZ~}j%t6=RY7xOMP{IrrlX|em`$KDTKJa46 z`4I9a=Yu1n`yv&17zJ;p7jKOb z$KO5Y#XN9Z^*I@pql%tk*3_K1@l_x8MO*h!fAf5;)iP8vIT2J06b@!| z$NR$&U^pgQs&B72{PR-Wf}TCPadq>^N3Z<$scV<7{P>P*Cmu-7hY#xhZ2G?Ru`^9L zABYsIexSQ>zg-qyVGISgHJJ{(I6S0i{ZcY^ISc1xq@%OI)HT&6&g@e}t37r``jAB_ zEAy`v$->U&5n@U=rtfr6`@0f&NCzJ76~B4sLt`giEya2eWbLhn;PzIT#a9xxG$dm`&EN)`RosOVPB*O*;e7`SXMM#7WTt9}f>)=5^m3#}_fQMGHSyso|==-=;)^hK5hvZ$tJy4=r;w_-c^ zq5?2HE^RX{ni@SAo;T~$GE>)k=lWIeKvL7^gi2I;yZnWn39^9*ETn>dQ zY9pkRjD6wiFgL7J+UHdRPS3$CBVrO|6w*Uz@#SzStL|hi) zvOgdU5xk2Wa27N%yPr=hjCU9_>;iRK!~^mLbh)C(V4K%i$^C(Y^T7x_D0xMkuM5Zt zX5gVQ-eF)u9r(g7Vanb-owr=P9f&e|N0EQWi0s3UhIl6&IrW}{h zKt?ryH&?JPpijEGtUB#y{Nx^`!WdAW%!*m^9|a7E2P0_mSAgLS-~lDA1$I%`r?tk~ zb}+C31Ny!|Jj??RmD`t>%t<5Y!37vo1rsnVa?QNAagS1BJ;cA%<^Y32N$vtoNQYO10mC%L0KIxxz|`{N-+C>e zNdmly^njA~mRr_c8?enIH}pxw1Io!}z#uC$(4GMdC~4`Cla2%oRCtB4FO&Lw35lT% z_Xl#DA}`9xstTeokQYxFtyTaS)Hok<0fPpZ{4ksR-i-H$gTMn)R3>0>;a#8!a=;(~ z45fepb-4>0o0%qVG)7)Mvcu?be?Sx9`@&iXJ!<`i9));7mzM=RpdNK!gq)xRJ$P_d zBR%8-hDzvBE&-_r8(>K6_PYQ>27l*ku^04!dej)^0rjXlLgaa;2yJtxM@hgJNKrX} r0rjY5+@t0}4~u|d0x(!1qdEaYs&Jk&ihH#Qdozxq4qlPXNTdE6`S`AT literal 0 HcmV?d00001 diff --git a/config/database.php b/config/database.php new file mode 100644 index 00000000..2634d53e --- /dev/null +++ b/config/database.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- + + +return [ + // 默认使用的数据库连接配置 + 'default' => env('database.driver', 'mysql'), + + // 自定义时间查询规则 + 'time_query_rule' => [], + + // 自动写入时间戳字段 + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + + // 时间字段取出后的默认时间格式 + 'datetime_format' => 'Y-m-d H:i:s', + + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', '127.0.0.1'), + // 数据库名 + 'database' => env('database.database', ''), + // 用户名 + 'username' => env('database.username', 'root'), + // 密码 + 'password' => env('database.password', ''), + // 端口 + 'hostport' => env('database.hostport', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 +// 'charset' => env('database.charset', 'utf8'), + 'charset' => 'utf8mb4', + // 数据库表前缀 + 'prefix' => env('database.prefix', ''), + + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => true, + // 监听SQL + 'trigger_sql' => env('app_debug', true), + // 开启字段缓存 + 'fields_cache' => false, + // 字段缓存路径 + 'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, + ], + + // 更多的数据库配置信息 + ], +]; diff --git a/config/delivery.php b/config/delivery.php new file mode 100644 index 00000000..956ffc4c --- /dev/null +++ b/config/delivery.php @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 同城配送 +// +---------------------------------------------------------------------- + +return [ + 'default' => 'uupt', + 'stores' => [ + //达达 + 'dada' => [], + //uu跑腿 + 'uupt' => [], + ] +]; diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 00000000..5977d47f --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + + +return [ + // 默认磁盘 + 'default' => env('filesystem.driver', 'public'), + // 磁盘列表 + 'disks' => [ + 'local' => [ + 'type' => 'local', + 'root' => app()->getRuntimePath() . 'storage', + ], + 'public' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/uploads', + // 磁盘路径对应的外部URL路径 + 'url' => '/uploads', + // 可见性 + 'visibility' => 'public', + ], + // 更多的磁盘配置信息 + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 00000000..5f51c84b --- /dev/null +++ b/config/lang.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 多语言设置 +// +---------------------------------------------------------------------- + +return [ + // 默认语言 + 'default_lang' => env('lang.default_lang', 'zh-cn'), + // 允许的语言列表 + 'allow_lang_list' => [], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录 + 'use_cookie' => true, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 00000000..1c7215f6 --- /dev/null +++ b/config/log.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + + +// +---------------------------------------------------------------------- +// | 日志设置 +// +---------------------------------------------------------------------- +return [ + // 默认日志记录通道 + 'default' => env('log.channel', 'file'), + // 日志记录级别 + 'level' => ['error', 'warning', 'info', 'fail', 'success'], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => ['error','warning','info', 'fail', 'success','sql'], + // 最大日志文件数量 + 'max_files' => 30, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => true, + 'file_size' => 1024*1024*10, + ], + // 其它日志通道配置 + ], + +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 00000000..c584659d --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,18 @@ + +// +---------------------------------------------------------------------- + +// 中间件配置 +return [ + // 别名或分组 + 'alias' => [], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], +]; diff --git a/config/notice.php b/config/notice.php new file mode 100644 index 00000000..12032058 --- /dev/null +++ b/config/notice.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 模板消息配置 +// +---------------------------------------------------------------------- + +return [ + //短信模板id + 'sms' => [ + //验证码 + 'VERIFICATION_CODE' => 538393, + //发货提醒 + 'DELIVER_GOODS_CODE' => 520269, + //确认收货提醒 + 'TAKE_DELIVERY_CODE' => 520271, + //支付成功 + 'PAY_SUCCESS_CODE' => 520268, + //改价提醒 + 'PRICE_REVISION_CODE' => 528288, + //订单未支付 + 'ORDER_PAY_FALSE' => 528116, + //商家同意退款提醒 + 'REFUND_SUCCESS_CODE' => 536113, + //商家拒绝退款提醒 + 'REFUND_FAIL_CODE' => 536112, + //退款确认提醒 + 'REFUND_CONFORM_CODE' => 536111, + //管理员支付成功提醒 + 'ADMIN_PAY_SUCCESS_CODE' => 520273, + //管理员退货提醒 + 'ADMIN_RETURN_GOODS_CODE' => 520274, + //管理员确认收货 + 'ADMIN_TAKE_DELIVERY_CODE' => 520422, + //退货信息提醒 + 'ADMIN_DELIVERY_CODE' => 536114, + //直播通过通知 + 'BROADCAST_ROOM_CODE' => 549311, + //直播未通过通知 + 'BROADCAST_ROOM_FAIL' => 549038, + //预售订单尾款支付 + 'PAY_PRESELL_CODE' => 543128, + //商户申请入驻通过 + 'APPLY_MER_SUCCESS' => 544837, + //商户申请入驻未通过 + 'APPLY_MER_FAIL' => 544838, + //到货通知 + 'PRODUCT_INCREASE' => 549146, + //积分即将到期提醒 + 'INTEGRAL_INVALID' => 550529, + //商户申请分账通过 + 'APPLYMENTS_SUCCESS' => 550526, + //商户申请分账未通过 + 'APPLYMENTS_FAIL' => 550523, + //商户申请分账待验证 + 'APPLYMENTS_SIGN' => 550525, + //商户申请退回保证金通过 + 'REFUND_MARGIN_SUCCESS' => 710327, + //商户申请退回保证金未通过 + 'REFUND_MARGIN_FAIL' => 710328, + ], + //微信 + 'wechat' => [ + //订单生成通知 + 'ORDER_CREATE' => 'OPENTM205213550', + //支付成功 + 'ORDER_PAY_SUCCESS' => 'OPENTM207791277', + //订单发货提醒(快递) + 'ORDER_POSTAGE_SUCCESS' => 'OPENTM200565259', + //订单发货提醒(送货) + 'ORDER_DELIVER_SUCCESS' => 'OPENTM207707249', + //提现结果 + 'EXTRACT_NOTICE' => 'OPENTM207601150', + //订单收货通知 + 'ORDER_TAKE_SUCCESS' => 'OPENTM413386489', + //帐户资金变动提醒 + 'USER_BALANCE_CHANGE' => 'OPENTM405847076', + //退款申请通知 + 'ORDER_REFUND_STATUS' => 'OPENTM407277862', + //退款进度提醒 + 'ORDER_REFUND_NOTICE' => 'OPENTM401479948', + //退货确认提醒 + 'ORDER_REFUND_END' => 'OPENTM406292353', + //拼团成功 + 'GROUP_BUYING_SUCCESS'=>'OPENTM417762951', + //预订商品到货通知 + 'PRODUCT_INCREASE' => 'OPENTM200443061', + //访客消息通知 + 'SERVER_NOTICE' => 'OPENTM417984821', + ], + //订阅消息 + 'subscribe' => [ + //订单发货提醒(快递) + 'ORDER_POSTAGE_SUCCESS' => 1458, + //提现成功通知 + 'USER_EXTRACT' => 1470, + //订单发货提醒(配送) + 'ORDER_DELIVER_SUCCESS' => 1128, + //退款通知 + 'ORDER_REFUND_NOTICE' => 1451, + //充值成功 + 'RECHARGE_SUCCESS' => 755, + //订单支付成功 + 'ORDER_PAY_SUCCESS' => 1927, + //商品到货通知 + 'PRODUCT_INCREASE' => 5019 + ], + + +]; + diff --git a/config/qrcode.php b/config/qrcode.php new file mode 100644 index 00000000..01b9c6a2 --- /dev/null +++ b/config/qrcode.php @@ -0,0 +1,15 @@ + +// +---------------------------------------------------------------------- + +return [ + 'cache_dir' => 'uploads/qrcode', //本地缓存地址 + 'background'=> 'statics/qrcode/background.png' //背景图 +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 00000000..dbbcaab5 --- /dev/null +++ b/config/queue.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +return [ + 'default' => 'redis', + 'connections' => [ + 'sync' => [ + 'type' => 'sync', + ], + 'database' => [ + 'type' => 'database', + 'queue' => env('queue_name', 'default'), + 'table' => 'jobs', + ], + 'redis' => [ + 'type' => 'redis', + 'queue' => env('queue_name', 'default'), + 'host' => env('redis.redis_hostname','127.0.0.1'), + 'port' => env('redis.port', '6379'), + 'password' => env('redis.redis_password', ''), + 'select' => (int)env('redis.select', 0), + 'timeout' => 0, + 'persistent' => false, + ], + ], + 'failed' => [ + 'type' => 'none', + 'table' => 'failed_jobs', + ], +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 00000000..5351cdb6 --- /dev/null +++ b/config/route.php @@ -0,0 +1,55 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 路由设置 +// +---------------------------------------------------------------------- + +return [ + // pathinfo分隔符 + 'pathinfo_depr' => '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => true, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => true, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 00000000..0a6eb47c --- /dev/null +++ b/config/session.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 会话设置 +// +---------------------------------------------------------------------- + +return [ + // session name + 'name' => 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 10440, + // 前缀 + 'prefix' => '', +]; diff --git a/config/sms.php b/config/sms.php new file mode 100644 index 00000000..c263063e --- /dev/null +++ b/config/sms.php @@ -0,0 +1,144 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 短信配置 +// +---------------------------------------------------------------------- + +return [ + //默认支付模式 + 'default' => 'yunxin', + //单个手机每日发送上限 + 'maxPhoneCount' => 10, + //验证码每分钟发送上线 + 'maxMinuteCount' => 20, + //单个IP每日发送上限 + 'maxIpCount' => 50, + 'stores' => [ + 'yunxin' => [ + //短信模板id + 'template_id' => [ + //验证码 + 'VERIFICATION_CODE' => 538393, + //发货提醒 2.1 + 'DELIVER_GOODS_CODE' => 520269, + //确认收货提醒 2.1 + 'ORDER_TAKE_SUCCESS' => 520271, + //支付成功 2.1 + 'ORDER_PAY_SUCCESS' => 520268, + //改价提醒 2.1 + 'PRICE_REVISION_CODE' => 528288, + //提醒付款通知 -2.1 + 'ORDER_PAY_FALSE' => 528116, + //商家同意退款提醒 2.1 + 'REFUND_SUCCESS_CODE' => 536113, + //商家拒绝退款提醒 2.1 + 'REFUND_FAIL_CODE' => 536112, + //退款确认提醒 2.1 + 'REFUND_CONFORM_CODE' => 536111, + //管理员支付成功提醒 2.1 + 'ADMIN_PAY_SUCCESS_CODE' => 520273, + //管理员退款单提醒 -2.1 + 'ADMIN_RETURN_GOODS_CODE' => 520274, + //管理员确认收货 2.1 + 'ADMIN_TAKE_DELIVERY_CODE' => 520422, + //退货信息提醒 2.1 + 'ADMIN_DELIVERY_CODE' => 440415, + //直播通过通知 2.1 + 'BROADCAST_ROOM_CODE' => 549311, + //直播未通过通知 2.1 + 'BROADCAST_ROOM_FAIL' => 549038, + //预售订单尾款支付 2.1 + 'PAY_PRESELL_CODE' => 543128, + //商户申请入驻通过 2.1 + 'APPLY_MER_SUCCESS' => 544837, + //商户申请入驻未通过 2.1 + 'APPLY_MER_FAIL' => 544838, + //到货通知 2.1 + 'PRODUCT_INCREASE' => 549146, + //积分即将到期提醒 2.1 + 'INTEGRAL_INVALID' => 550529, + //商户申请分账通过 2.1 + 'APPLYMENTS_SUCCESS' => 550526, + //商户申请分账待验证 2.1 + 'APPLYMENTS_SIGN' => 550525, + //商户申请分账未通过 2.1 + 'APPLYMENTS_FAIL' => 550523, + //商户申请退回保证金通过 2.1 + 'REFUND_MARGIN_SUCCESS' => 710327, + //商户申请退回保证金未通过 2.1 + 'REFUND_MARGIN_FAIL' => 710328, + //付费会员充值成功提醒 2.1 + 'SVIP_PAY_SUCCESS' => 856046 + ], + ], + //阿里云 + 'aliyun' => [ + //短信模板id + 'template_id' => [ + //验证码 + 'VERIFICATION_CODE' => '', + //发货提醒 + 'DELIVER_GOODS_CODE' => '', + //确认收货提醒 + 'TAKE_DELIVERY_CODE' => '', + //支付成功 + 'PAY_SUCCESS_CODE' => '', + //改价提醒 + 'PRICE_REVISION_CODE' => '', + //订单未支付 + 'ORDER_PAY_FALSE' => '', + //商家同意退款提醒 + 'REFUND_SUCCESS_CODE' => '', + //商家拒绝退款提醒 + 'REFUND_FAIL_CODE' => '', + //退款确认提醒 + 'REFUND_CONFORM_CODE' => '', + //管理员支付成功提醒 + 'ADMIN_PAY_SUCCESS_CODE' => '', + //管理员退货提醒 + 'ADMIN_RETURN_GOODS_CODE' => '', + //管理员确认收货 + 'ADMIN_TAKE_DELIVERY_CODE' => '', + //退货信息提醒 + 'ADMIN_DELIVERY_CODE' => '', + //直播通过通知 + 'BROADCAST_ROOM_CODE' => '', + //直播未通过通知 + 'BROADCAST_ROOM_FAIL' => '', + //预售订单尾款支付 + 'PAY_PRESELL_CODE' => '', + //商户申请入驻通过 + 'APPLY_MER_SUCCESS' => '', + //商户申请入驻未通过 + 'APPLY_MER_FAIL' => '', + //到货通知 + 'ARRIVAL_CODE' => '', + //积分即将到期提醒 + 'INTEGRAL_INVALID' => '', + //商户申请分账通过 + 'APPLYMENTS_SUCCESS' => '', + //商户申请分账未通过 + 'APPLYMENTS_FAIL' => '', + //商户申请分账待验证 + 'APPLYMENTS_SIGN' => '', + //商户申请退回保证金通过 + 'REFUND_MARGIN_SUCCESS' => '', + //商户申请退回保证金未通过 + 'REFUND_MARGIN_FAIL' => '', + ], + ] + ], + + + + +]; diff --git a/config/swoole.php b/config/swoole.php new file mode 100644 index 00000000..8429e475 --- /dev/null +++ b/config/swoole.php @@ -0,0 +1,116 @@ + +// +---------------------------------------------------------------------- + + +use app\webscoket\Manager; +use Swoole\Table; +use think\swoole\websocket\socketio\Parser; + +return [ + 'server' => [ + 'host' => env('SWOOLE_HOST', '0.0.0.0'), // 监听地址 + 'port' => env('SWOOLE_PORT', 8324), // 监听端口 + 'mode' => SWOOLE_PROCESS, // 运行模式 默认为SWOOLE_PROCESS + 'sock_type' => SWOOLE_SOCK_TCP, // sock type 默认为SWOOLE_SOCK_TCP + 'options' => [ + 'pid_file' => runtime_path() . 'swoole.pid', + 'log_file' => runtime_path() . 'swoole.log', + 'daemonize' => false, + // Normally this value should be 1~4 times larger according to your cpu cores. + 'reactor_num' => swoole_cpu_num(), + 'worker_num' => swoole_cpu_num(), + 'task_worker_num' => swoole_cpu_num(), + 'task_enable_coroutine' => false, + 'task_max_request' => 2000, + 'enable_static_handler' => true, + 'document_root' => root_path('public'), + 'package_max_length' => 50 * 1024 * 1024, + 'buffer_output_size' => 10 * 1024 * 1024, + 'socket_buffer_size' => 128 * 1024 * 1024, + 'max_request' => 3000, + 'send_yield' => true, + 'reload_async' => true, + ], + ], + 'websocket' => [ + 'enable' => true, + 'handler' => Manager::class, + 'parser' => Parser::class, + 'ping_interval' => 25000, //1000 = 1秒 + 'ping_timeout' => 60000, //1000 = 1秒 + 'room' => [ + 'type' => 'table', + 'table' => [ + 'room_rows' => 4096, + 'room_size' => 2048, + 'client_rows' => 8192, + 'client_size' => 2048, + ], + 'redis' => [ + + ], + ], + 'listen' => [], + 'subscribe' => [], + ], + 'rpc' => [ + 'server' => [ + 'enable' => false, + 'port' => 9000, + 'services' => [ + ], + ], + 'client' => [ + ], + ], + 'hot_update' => [ + 'enable' => env('APP_DEBUG', false), + 'name' => ['*.php'], + 'include' => [app_path(),root_path().'crmeb'], + 'exclude' => [], + ], + //连接池 + 'pool' => [ + 'db' => [ + 'enable' => true, + 'max_active' => 3, + 'max_wait_time' => 5, + ], + 'cache' => [ + 'enable' => true, + 'max_active' => 3, + 'max_wait_time' => 5, + ], + ], + 'coroutine' => [ + 'enable' => false, + 'flags' => SWOOLE_HOOK_ALL, + ], + 'tables' => [ + 'user' => [ + 'size' => 204800, + 'columns' => [ + ['name' => 'fd', 'type' => Table::TYPE_INT], + ['name' => 'type', 'type' => Table::TYPE_INT], + ['name' => 'uid', 'type' => Table::TYPE_INT] + ] + ] + ], + //每个worker里需要预加载以共用的实例 + 'concretes' => [], + //重置器 + 'resetters' => [], + //每次请求前需要清空的实例 + 'instances' => [], + //每次请求前需要重新执行的服务 + 'services' => [], + 'locks' => ['group_buying'], +]; diff --git a/config/template.php b/config/template.php new file mode 100644 index 00000000..3851133d --- /dev/null +++ b/config/template.php @@ -0,0 +1,76 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 模板消息配置 +// +---------------------------------------------------------------------- + +return [ + //默认驱动模式 + 'default' => 'wechat', + //记录发送日志 + 'isLog' => true, + //驱动模式 + 'stores' => [ +// //微信 +// 'wechat' => [ +// //短信模板id +// 'template_id' => [ +// //订单生成通知 +// 'ORDER_CREATE' => 'OPENTM205213550', +// //支付成功 +// 'ORDER_PAY_SUCCESS' => 'OPENTM207791277', +// //订单发货提醒(快递) +// 'ORDER_POSTAGE_SUCCESS' => 'OPENTM200565259', +// //订单发货提醒(送货) +// 'ORDER_DELIVER_SUCCESS' => 'OPENTM207707249', +// //提现结果 +// 'EXTRACT_NOTICE' => 'OPENTM207601150', +// //订单收货通知 +// 'ORDER_TAKE_SUCCESS' => 'OPENTM413386489', +// //帐户资金变动提醒 +// 'USER_BALANCE_CHANGE' => 'OPENTM405847076', +// //退款申请通知 +// 'ORDER_REFUND_STATUS' => 'OPENTM407277862', +// //退款进度提醒 +// 'ORDER_REFUND_NOTICE' => 'OPENTM401479948', +// //退货确认提醒 +// 'ORDER_REFUND_END' => 'OPENTM406292353', +// //拼团成功 +// 'GROUP_BUYING_SUCCESS'=>'OPENTM417762951', +// //预订商品到货通知 +// 'PRODUCT_INCREASE' => 'OPENTM200443061', +// //访客消息通知 +// 'SERVER_NOTICE' => 'OPENTM417984821', +// ], +// ], +// //订阅消息 +// 'subscribe' => [ +// 'template_id' => [ +// //订单发货提醒(快递) +// 'ORDER_POSTAGE_SUCCESS' => 1458, +// //提现成功通知 +// 'USER_EXTRACT' => 1470, +// //订单发货提醒(配送) +// 'ORDER_DELIVER_SUCCESS' => 1128, +// //退款通知 +// 'ORDER_REFUND_NOTICE' => 1451, +// //充值成功 +// 'RECHARGE_SUCCESS' => 755, +// //订单支付成功 +// 'ORDER_PAY_SUCCESS' => 1927, +// //商品到货通知 +// 'PRODUCT_INCREASE' => 5019 +// ], +// ], + ] +]; + diff --git a/config/trace.php b/config/trace.php new file mode 100644 index 00000000..b23b2e74 --- /dev/null +++ b/config/trace.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | Trace设置 开启调试模式后有效 +// +---------------------------------------------------------------------- +return [ + // 内置Html和Console两种方式 支持扩展 + 'type' => 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/config/upload.php b/config/upload.php new file mode 100644 index 00000000..881867b5 --- /dev/null +++ b/config/upload.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 上传配置 +// +---------------------------------------------------------------------- + +return [ + //默认上传模式 + 'default' => 'local', + //上传文件大小 + 'filesize' => 52428800, + //上传文件后缀类型 + 'fileExt' => ['jpg', 'jpeg', 'png', 'gif', 'pem', 'mp3', 'wma', 'wav', 'amr', 'mp4', 'key','xlsx','xls','ico'], + //上传文件类型 + 'fileMime' => ['image/jpeg', 'image/gif', 'image/png', 'text/plain', 'audio/mpeg', 'image/vnd.microsoft.icon'], + //驱动模式 + 'stores' => [ + //本地上传配置 + 'local' => [], + //七牛云上传配置 + 'qiniu' => [], + //oss上传配置 + 'oss' => [], + //cos上传配置 + 'cos' => [], + //obs华为储存 + 'obs' => [], + //ucloud存储 + 'us3' => [], + ] +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 00000000..b5fb94b2 --- /dev/null +++ b/config/view.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | 模板设置 +// +---------------------------------------------------------------------- + +return [ + // 模板引擎类型使用Think + 'type' => 'php', + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', + // 模板后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 模板引擎普通标签开始标记 + 'tpl_begin' => '{', + // 模板引擎普通标签结束标记 + 'tpl_end' => '}', + // 标签库标签开始标记 + 'taglib_begin' => '{', + // 标签库标签结束标记 + 'taglib_end' => '}', +]; diff --git a/crmeb/basic/BaseAuth.php b/crmeb/basic/BaseAuth.php new file mode 100644 index 0000000000000000000000000000000000000000..b9dae03a4c83c7fac28c7f82e7cce8dea9622d43 GIT binary patch literal 89208 zcmdSCcXX3i_BQHnx!baAt5|Zk+y(gp) zAPMQDlU|uHNl5QyLb!YDoMY>Cm|yw6weGt2Pgro)e)oCyv-?qAp>fa{+-I8Z8=D#$ zAL}%XclY-7M#-n<#>WkP)+O?Mj% zeZBJFgy1S=Ri{F)jm|AB5Ej+fMmASZ4F}u##`J2!e0}|7V)01!+)RYrl%R+*DMMD$ z3&J8y%7sOVxHWk&*-;qi?(goYSqPqA(0gn2ngDU&a3J661in}#ZgZ*73Ch($AwsFi zN9WjD-_LkT}eW6<&=o;t>Fi` z)+;2Xeme1l+GnoF+u5x`dBuuM92M2m($w0u7@ZT=+dVHU^O1?PDv_vED$3JNKbpmF zgA?8fQt3x^;<+(-wQpit`=r#*PbboO*c1x|B|@=DA~h-aO`R2bkx8SSkM64L@al_+ zDl`s^nk6M-txTj7OJr&|Atip)a)Q)IP8cm3KWvx(U!BlrbpnyW04J#rz-uc(5rXoauXc+388(mn7i`piD?6$1DQH`$sD)+ZE! z9=t#g9-xN<*B-p{EhEuGC+H!1ogS=DICRzARdAM4^?m%$x}p=_q!2(aLh?R<(^9T0Z({k5mC*(i*tQNQWIgA zPPolztGgHhJm3k=1^;(?s0A6~jM9MPokS0HMO=MWD`Baf(%mN2QgsM1TxfR zlCL=KP4wW>o^#5x&m=iCLu~V+5iX(zD9fe0AgYmRi5_%I1P|H3vDbs{*MWK!yt72PMc53NpBO5lr5vCVFsp%s4dGyJi>Pk29tvdO(&7vUojmn@>0p zJ?N-i*nnMZlB~(Vqki)%5z)iBzv92Q3ngH(8+dZCn0o^A7wm)(@S6&dp(}4q2K3$8 zv1`7YozMn)_;qLvlW1A>dZGtrn_v17mfNHGvmUsJ`k&!pJ*w|M_3=md-+B4nr!KtW z&D+0t={e>%zdQTrC!ZhszY`y=Tko*MRTded3KHmtD1c)5qX1 zIwS;>8vv7dLe486eiV4U@Q+^=1P{njt-w*b2OoN0_;mT%Q5wT&bW%I#(D|^Th-F3M z;^1ObjwpiJMJwpx$TtVdp1ECniw(8S$gcF92;W6fR)lyaG(CPeytA#*INohW89w^g zxxV7`-4Yr{{im;p#rR=?_{~zd3)BPuzza9O9IyL9y1?}pvtXO3hoUz(?tJskmriY` zJb9pp+@?3>sNo}*F9E|`ArB@z`Id(0!5{R1n!I2!@gEwq=K0SG2_9Jdz`x>=E02fI zzh6Q*%2TUtow6Sq=t>y1e8qJ5Wfsdqe!yt(@p6KP4VGxI&wP)P_zNjzxqIUY9waoL zRQVD_Nof3FkQ8di8<3-jUGxG!w1I7wPDw+~UNd@JO8H^j&(LKo7}dE0Pu9R)xNNwG zH*0FTw2ty*l8#zc3iK0H`ILbsReA&9AqM>VdBqm@N)d`qe0jU10oxmgPtF&M63g`h z9x_0N#)9_ZzXaU>Y%A46X>HyHn~LF}$$2AxA+*aFH9e73F)y7S^_d9E%b$sz^@?2Z zQ;JeEgL(QEZ@!a%fN8WTessxwe0+AG&@o@ULj2}VY8QwH#!;w;zm<{<1>?yukYUF| zQ^uGQ@$(YO)ddj=MJ;d_3805oz@+T$E5Cf@<3rm7mfKYDoo&JsW&~MT!giNT)Z`k& z{3q-F*WJibD8sopirpsO1)gxU@YZAMn{9p;#1Oj(1Q|NvF7{-9`*h)%o;`jP4@Q5G zp~617!?Q1DIMXM^-56IpuG0g{)IMz?c$l?B#bWIZ0fZ-6 z9Q9NV;fElKhwa|PUvyZkTce$bBzQ=mcnB>eY_F$wksU}pjxWs?uhtPnl~TL-ODUHh zd~3M;;8B}pOw>q?s0Xwx%(FV+E*{TzcxEuY;%ZmwH$BzKi}R(aC=M94+^WK<7P9ja)-n8fTYC=vKNGz}M&>Maa20eWbMyXcF3?VbZK zs9qcfyFg9OO)o}QH#g}p-*g5UhI(EfN#HAvYN#Hf4QY;EQ;}{fy|HeQ!2)qzS%3vm z7(cYZ3BeD=z)%AzREt;!N)(?vCL@kILt2mVgsiRJfqtkNbMqV zLR399ptR@#@i2Tz_K*BSCtuH}c+h4Ci4yC>W?bqD$`|^2B7Ka0&TYOXL)d)TO0HX> zhuG`}UqNEIT96^~3d0?;Q=8vtqWr-3)Wu7aa(J0ujvF$KIcA5Uk=%CaQnqn{zc|z) z@ftlgZ_xv@i*Nr{I-q{<{JY($UGSXw0kiR-L--EP2}o5 zRx$`dh72D+UAdCR4>X>9lj5NgWDtAxCHUu%c#>sF8fq8)pob8U;YAup^#VWq0(VhP z?P3Y^u-Mi@yuTH!%UiV;#WSg3-%RzDIP+=E)>ySReRkD!}!5nV9u)o zJz&m@F|AsXkR}2d@Pw`F_+f?k3(H;L2~CtAM4$%|$N-TT&s$#2uTLiYFhu#`D!>DB zR5$tyqo(pS^%o|}54%AIWEdmJaN&v}f<=Q0Dg*PI5W{rs)k{oL6~Tie$bdd;k?J87 zWbjjn=PnFpClEaxrEDJ#GW2#=Pf6&cv4pTZmQ6vd48E{vb;lT zhbKrt4{jjC-P>nPs{XP``N;@SumgC;=Hh1We9=9=bt>d#VYd zUiBdP#d&F5fANoFcG_sMX^)WNLG8V=h?vAUY7FjT%RfA{v0B+KCCGp$sDhfjhd>7O z7swBvz1Qd;Q6k*EO!+||kJnFv49suNo&ItL^zc09ym*3b=(5GKZlv)f^B328a{a}Q ze6GLXH*@{Pyc5@72zs(Cc@~Q&)gVJ8=wZ5Sa{p5EMfbQ-JdDop z1IS&h`HQ%1L6_Eb-?G_-`iqzW_p;Ir{!UIoEAsN-3A3);Y|#Vr7tjB2{t)=h<1Q2r zk=oKkj33J3E<8YnyIy*73b^|4G{r+vrLPY4z~af;S3cPI{u5_D3!rvU`uk5;{QK0C zKmY#K{zAMk*AH`qmRvtBrV7Gyw8Vy+i# zWfu`3!>pD+L%hG#r~~W9SPuOr@+8Fe@tdK{E~j=uP;DH*xEc{P1-FSZv`&%}gcQ}t za+qgTfD9eJYkC-X>vaduD1)ylOO};Sy#UBVi`nY&o5BBP-p`N zrfel8!!2w60{!M~FJ$LH9cHIDU=mNLh=~hTf((cUTeyoW2YrsE)O1|N@{2O*eEj5$ zPW+Awv5R4g*OM9}JP1EjP(9q%MdIopiicT$!jl`Q9=^0EcERcoj>7~|ZWIrn+LE{$ zYaqxEgL-Zp6=}zfqvjI1anyyjT)Q}$!nKRv8o74ymWXQ?fgQx_u{dh6iW^5sdU7mv z7_3KO=8ko_A>gPb-D71BedTaSO!Xj@WUl1rOX5v#p@|VS_F2hG-c7oaPG6p9TJmVv z#7vaJG!b6t5VGQ!T9&rd*&bayKPQi#&FRXBpC65wNcS_3H_E4CGs3%CMOo2VZGt@G zibo6IMOj*B(InPD+Chfsdml5ucwW=((~Kt*Rz|}Yl)>{uKBi*(NONXfO8$~#ZHHy(SyBMp@)^w-%e-uaULbgyiXI}D)cQ2R{B(^lP4|6eHiE%^x z_?n1C+p-xOd3e}T{yf?R`pp8ci&}Y-q_k0fLjdK6K2=MNpJR65Lh@8%Nl(J;^k`l_ zFDc#Lw$a?x)H)exQqP7?=l2@IhczL~GrY-YRfusoH!5qoQXX$p>9UwQ9N?(#u=jMT zZVnrY?lfdirjLabHZFx0EBV!iHGk0*oZaT#68S_p$Y8OoxDmgEgb0nTJkyX}t*H$X zc)Obm)3c_AdWH-WkzqXkywJ8WYeijN;%i#y3y)tK>X}+vOrMDpEc6D&<)`PQcUh_^ zPOOU35#Zq&VoX@fNkq$HakWcJy-_q6_MD3HgCJyhPC8#K4)0FRlcX&O!VBG79it}} zc`eRbXPztHES(RV8Va8^8~o#Vp~JE!|MUrI)ugjAY(B0lrZ+KexqozF(QVS)=sXph zy?)<5R~k>6g{E1vyCJ);EPSy)cW}&fZ{`QJ zR(N=0v+db8ev3LhNAWPfl-)Wu9J1;!W`1f6`TlQ$?Kae3%#XWIO}fSnX2&K3&*dc~ zx>b1xOP6_iHI1WK{IKhl=l&@W8ZKyK@k7>VMCEvLcYo~4q`MVQdfXgit80uuGY(Uml2*MUty5%r+TOcJowudi=U@;`*iRZ z4}c69KOocQfF4H12h5Q)zhFFhHSi?%l9n*P(0bVI5);3ParFU^K}`L{I}k^uW=;+? z%@V(G03nR^x&x#=}*{^$ox~di~B%^5~_#aK?ZYZOrdU^#FH$J+6#J^ z1{t=23{C<+{ZT#fn+L&fehD&k(){9i_zH#dK#U*c{&<3n#t#ny+vk7`pMwle6VSh) z`Neg>4;O+AT95&A|3^U&i*0RQO|%{*qjA*dz>^A)VGqcVmM)z<7C`*wCcwj|AcH@# zZoMt^^?E{j>NYrY{pKOi!#v2~47DINKQZGNt!TXm9Q85CFhlv_iAtzPl`TepP*40O z#xQ{(!&fw(JgtR#RAQCSlS#yHeg=48u{|=(2OSmq6sSktm_Ym{qWT#1-H528m7}_j zxnB90Kk=L7D~Jq;sN)dBEb2u|JeptZq;^4WQzyOx`rWfC@!YG>-^3Fzj`9H+?xJ>a z<-CGl+E}jpW{Kn%w*wvyP}{^f>IsQN)}tHMJz->#nAGoj#!;Y$@1Un<3mq|&n#2$6 zD>hPoxKgMS%VjD}f|A5hA5gm>QIMeIa_Aj6Eh+e)fFAIKXuv}w$nYkWVTVp8YT%0l zuZ0{3Pe8jkWEIO@Qz{hKilnAJv~G`IaVKDs+-9HoZ>3^wi%229*q>OIJKzEJ&<=V) z8ID8G{Se}6#EL)1K!1FE0U5(txW0}MB*s43+tG6lWnokt6V64iuM)*;46wj zhV4{_GyQ#L8?~hJXDQ(aw2LpSPPkGFH4w1PC#8fR5Y=x{+r+Q9p};s00$th&T7Ov2 z4|}vCU9wGaU?Z(Rpl!067~aL_vA_?I`(FooK!(wPT|irF4*3D~aJc~M5AJpcXrC8t zljZ)%FfT)0&OYBb@bElCltlK7B@!cg*g7Hgs|G}+I1+wfUx6HjckvC_1=b%@Y2BXL z1?$2bP6vK~`oj&N2RuOuw&?>hAV=W|pGF}+^hO=cCH!z2zT!*DQHX~l{KT{ju+8Ua zKMPq7If~upTe|t^@VW-CA1FU8QhsQqanv7R7Z>MAjiI!^$-V;hfSSAn_yOw=Qdfe9 zomRGqcX1)|LqKBM-$4(EsCM`Y5#=a6;WZ0Cm|`!gBA7(Gc!$b>i24Kgp#rK0-=?y> z+ruWA+9rO*^I#Y4rc&*vA;hwj)Gk^mPre8Ia2RUE|A`-7{%`ozdyrh+1+%O}c<>&ROZ9YLVcf+Joq!OG5B4IY|8G(Gh~EUo#0$zBfb|=J$S* zU+6N4U2GU4ev`%3|GLJ#BvGW>Eu(lS)c3{8z%E$5`tYCY57QW#v-n~6pX(1nJz!a^ z{^0TcpXv`qD_|F_{xI?2pX&DdX0T0GpOjo7@iYnrk4fP!5D#vdQ*()67g!q z>K}p(<*^`&2eG_)CLZhp``y^T@VUaPG|#5^Dj&ckp5VV=7{Hnst3P!8P>@_a(Dw)P zo66bcxjNtnmS@>KXI~nn^VnEM@1oLsB6bk$qWLz%=hpqKh+Fb3^ABXIXH?hncg@BM z8dsxTc!6DD-c57=|JdJL-+jQ_JbC)`-FK-8Kd`=DLq@Ujjsu$KzYQaJ_$7&Kd zKF+^?ndTkYF?*wJI>E!2lpn;P2kc)Qi#r|$HIQHaJ

    }qx3Qx-`>&7ohTkSd6t)9 zD!jQn!zgw&8$5!$<3JBk6Vn#LU3_tHY5cplhCg9*VsX&NaSe8fB3^F|4=;{C8R*;= z_1AvJQP%mzpi1i(>FqjIvY0(Q;W@LixK@X`!}UUUz~pf$*adRb;!L0!@qnFT3CO@Y z#n@vdo#OSHB)#U-cauI2;^AC<9PBk?Y%c}d#1ni$53E~_m=u6*;t41N_IZz05uOa7 zG8{>}^3nZeuiW`#1MwI2$;5980F&77-qOBz|K*Nn54{&dm{u7>xLO66#D2G}`$bMq zUKFzVP9upY|EM7R!1~=I$B)fFdVkB(ExXWarNI?9lcuuT7S4oPVlh% zO~MZqz|}I4p;Mr=LJ@X zx-m8`>~=>l5yFy^G@HWZrUe$Hg!B5tds{BHc;W?~c65e?z^S&*@_uNGAyG z0{guG3jX4Y=ZAi~aGd&0`^eN`=UGd}8d@fujEbHzFD5R?6YL`rom^`N!%8{_OU%6+ zB3K+HM(bWsct1U7?fuu77V|8$&Fntrc?l-5r{)PVI1Ca!%!mn3E=DwNn~h!L>U#!> z9>{GnRIm9ga+@$OH%;*14tVGWyI?113h@R;P`zd4*G_)lJODp(e+HtFiBYuW0WR zyW77%l+5^H(9gUQZmDSbmdhg}-I|-bhP$1>oT1k&TwaI?lgH*kQ<}w-I41^O`+#Eu z3{eCR__3_a=H!M3byeyCss?Cacr7`w~5{ zI_((~!2^q<2GfZqS)Dd`f#`wtyT>vKPqKdZVKK4I)&4~q;Yrr-#yK%O0sRGPQb_fH zv(1(~>jvHxZeFD4j+$h3Irm6$`qc$#8_TF3(z=(%<&wxwt*AJ-vZmBBHy8^iMELs7 z|DZ^^kWcNxyS9k0@6XLqhsn%5foj!nW>tR~0-F4!pT^aq+8RLAT0Gh2x>E+4JdPZN zv3*2oBUsj2eKI70TemMQcD7^(tbd_Bc<;NTWglNEpms4b8ZbQ}9qG=GPmUP@eqeD_ zbH)1s4Fbsy7pe!5Yj&WF8NO0vDaf`IgO(_5DE0#JIARW!j#3G-c8Xt zof9M~X7S{e+fx$n`q$j2lQe#amX>DoTk|_2YW{1x0PpX0*3VCShQ?9ME_jqDdjStU z(B~znmXz>84^q%1;sIlO@ZFl9jUvbviCrL1Vo#0rv%q)zn;WHn@J#4d1d5D~@ZVIYo5Dm7_zd#&m)Xcr3< z4-Ftg3AULHw#oWg5YvX7fhubR?PoF1i}@zn#Q@yJJin>cf!1M?Ry{A_ zNn6l^jaa3Rqji{kst3mQ*&u@x4G6hsdi3(Jk_PHKrBBvcRa zc|;Fp$`1om1X2AI58kar536z11i6c7iic+=h+W7m*&;A)57%$o-q@bN%MAO0M5Dg>(I8*9g~d zMn-b|W~Un$4;v%S?Kc@7-ku_M!REyF$8qtHX2->Yy*n2VwRT)Qd@;bq!>>(TJbatQ z#lvzT7Y{WVTs+JabMf$rCl?PdMRM_QpF0;1E?!(b2&G&+Fg>vNA=`tChx@#^c-UFR z#lzk~E*}2b#>GQK0~Zf{xm-N_q~+p)^)E!=FHn=mQn`3Ac5?C1T5L zI=FbaX_UlKY;N!*kBbLOTn)DAPyJ?^GZzmM7cL(5ICJsvL=P7apS5%G@N51$JY=oI zLoyc+m~Y|AKA|V$KI0u3!us)6pkBf&sS1uk-)pPN1 z+b9;MdN@Lwyn#50Mq;#)FXJ;l3;`9;uzL0IAKOzpZ`roZlg8D#y^e|nWkg?78z8m8x z8N_mpNvA!Z{xaYV?5Uv)nR!*BS;y)mjO|gAtZsk&N$f1AHtq|4o2NdHF5zKRIsr$D-vnrABp4u|%C*8RB26Pf*uQw+tEE%k2|W zSMx0AqT6o`zsT*zF^Y%4j;gYd!07qv^kB;gEYEuI_tTqBRdwCdOz{w&KP`>+mMDGm z^J^nl7N!a_lS7&URKn`IpiZ^MJusW>b@3EzNaH??iuVuj1khiPL&(w+r|hbdKL zCB=hpgV5f<@6wm^k}Z3zh=<_*TVAPoP)>FoQj zz0Z~E!Fn$#%+|d$W?`u-I4UEi-L2E6MXfu9xgORZY!7zE4ZNVf$)469LWk$&3+3X4 zF`vlF+?e#RSze*9OSx}wR=-WTR%^V9&BI*a_16Tyz9;YFQGV!%&^Nb8b^LZcUt8nW z-jJsxdr7P=cku<=a{S6%_Vif1o>;qVD4d-h%lDRs4%xd_rmbiyq?e(`VfD%IlHK!L zlJcI^)4V%jEX~e?&f8}u1=x?3IqCd|$5;7bRCByxOIGhuJH`)=T5YT~Ka_PZ=Z43u z@VEgJGgiy;kTU=E8p0`U7*Lw$C;cBmOT_% zvq)QSr`8usoq~Dwp;;WeXxR}y{lM>;J2srdE}S}BYJ&oNLdIj~q9+X57KUMU7|Dc4 zxpl*#6aF;sZq>&$)oD(ryX{>Y)5ACT(Y!k*Cn#jbS!jw_D5;)w z9J1_yXaJK@;@?dFtnIzE2J%hxIDu~QE2&Y^gp`S?+R*5s!f~~oP%)IfT92w)xo6_u zrQYjYDIWYgiv${4k8<_Vc#axtg`v%Y)xKU{@=H(n|JL_bIps-Bs(d-SXvC%=rP^`= zn+w|Hv$6L9)4}hs{(zdauG=>SC~c}$B1NrQ8Wh26O^u#e>+9K^_hm@M10{Q${tJHa za2-#Xj9yue8eH=i@;Ia1`Hp+Pbf$P{3{W>@YE*KMa(6E;*QPvA*}P?Ekok+PhY!{z z<%~Y+Lh;~L6Sh)RHk3Hi-JL%XW#|nbCVd>{FCv0(N;ugq+Nh%bA|+cdP$jiziHnOS zCAQt}V=L2Bt{Ylc`y!S!_Pz6Qiu3Pvw0hvwq-f#iTK4_DnQgkoO-bxk zY2EFuxQdbXdIQ}S{YK<%1<$k zmj~)wMed^tzdG??m!%ejbH%;R*T-*8O1Wx`#t$o|@Z=1;rVY9P#Y|9LKxcl%jHuXI zxZ3B{+P(6e?fp5cduoCPU&qA2cCC$PdNl5kGCX|sO6g$w17UY(Gd$Gi&FThMe8!e$ zeOiQ_T2Ez>RNWa@sn75!68Q*R+F~@8EmYR;{>J5@qr2u_{CS+(#k`|!Nvd8~KPED( zX0t{@dW`86{c^*&>&%dA_)=_kXg;wEriab%ZVR&aID8Y2>LEd>%nh4!)Gkk`BJ{1r zK~44@m zo{HZ3__v~CJ?G#_7C+QFxAIywB(7#W`O|@!&wO|fUS&^ta?z@fv*3{(?B6VK%NTa3 z)ai^Xm}jy1$rabbZsl(R`(9FB|9$~y1Mr4BK4d4 zcBi5#oyTINSA*pQ7DrWe9RA|q?LE7k&%u+@mdyU{iHxY6j1Kz_7j3znUcc%$vt+XD z2j#u62TSscxulsDam9)#V=>o0JZD4@8X8nyn3p?dt8eKF;;+S%%g=oOgYL}qg)20U z>L{wPt+LnXWmVPoZJjY?HSs=te4B;!{oj1Q?WdFDwolK}crsypXfim&EmRTY0vjCd zBj~eyKnCV7F8Sosw-%DZAA!Adi@!+nb?r!|`@GE_{yr@}Ix)_oFg(2b^rtU}W)9u% zM)9C*k5jAYK5uJgg-<@r1z~Lv^KN_><@BbljK30$NZRlMp3L||S^qcSfZ0QvL z!s_`=TWc=`4)}^7ge>CpKzCT9h4z&>*+B{P_r72mby;9cpP(p%lG(H|sum|5H z!T7;NnY^?}_ZF3Q{HAQay_#PrTFo#1xA9~}!BnT-uGGv(FuHD1Lw zEr3b3my}~VbLGPsH{9OJ_`zz=-BYisaSF=jtHOg#&JD}Utrx z`qJok2VWZcFZ_k9U^Yrz61Jeyjry4e{EjEVU9dQ+B*w+<={tMB_M&<~Ob(2PXJy1U zO0_Q9Dz{QitGje9&wA{`58tx$J$iuUS(34FK}=7aO?*fei=%WNuU$WpkOsvjHPR@{H~@8|cdU#Haf}WKQZZ zOb>V1Ioed-&9WRx=K}j=*0r6hxu&7 zOz7}3BmgFv-+a5^JeylCT$?jjrpuS|8^Gt%_<`}mx6zZW z#g)H3(n4|TpSe2!fcxFsS9-z}W%uv5p*-m&_7#>o z@J16RbFGC$C?cTOmJ!rpM+bI?0CO0?aF1fBOFZd)6c{td0M6KDywj;^y(bt<#GP`i8OkOfu z^MjphwP(zlU3lDC{Fmngh7LQ^d^4u8AuOia&*&}W#t*MG{`7q9*GKR2r13+(XQe!k z#!*deb{>T7*ZAT0@z>5&pV)pEzMF)IGA)H?rqeizSL@!PqHl4qd~^EM3zFe3uJUGi zce9IY10`c zR3`$m^?tNF>C&hk|IqNZzEzWMaok2m{C9$EF9vrBPi z*a69N$Xv1P9WcM?rOLV3oHMxJmEwUX^p)u-9-LanCwijDoEVEAIyEg%MbvvgQA*|k49yB0tEebC86uw~&d zN*X`RxF`2G=S9UXS)$@=ZV}RXTI2_uBW3ld4&a9|-^9F@8B(WZ^=cuFqwE2bZdy}_ zoc4KfUk^EIjN&00{6(C+N-{|Id2wE@6lA!H>LC!UyV;~JE3kV10cQ^`run7^c)gan z(Le1iA|BY@Vy<2^&-Qt7E(ke_&BJtn-#pho?+&VmCXDT2pSP3F+i#+ zeO}lICiO`_$`7v8XTi*#b0oj1!-w{HZK&_Yy#uT+Vl8L`%(`EsW+#w(^)obnz&8g% zObY+aFq?#yB?7xZ8Q2^MzDd%+XWQ9i2Lw+D0)D_544C2Udq^Uk_YELC`8oJajP2Qc zR4vHR4>3%zh{O*|Fkc-Cx!!T$D6EmXfFA6{^DwbbYNYcZ!%ZLqzFCC+0%jMNgS3Gn z37xlJ06o+ICP%3r6d;2^EfntwWG4`Q=(AXNRACnAK@KwPhrI)=aC!h9%;2-m(tNWP zWN7jBEBaPO>T(wX9)6{^iTuz5GE`bNdPv=V$Pxt^{c#3knBt)kWWas@uh#ARW6vE=hygvoygl`LVr>Goi&>Ci9Av;bkTRG9(bIkZ zgMbIj{n;EyI>-e(oQ#2Vo2FPe4R&z=Y!lx-Kt$mj zNG{xFDxCwl1nvTNg4nwUSY>U5dHX-s?fVB%Jk-Niz`T8380;P3SDXS=X9Fhp(tNWH zWPpADj34OxFu0HN1LbN&lncnvW!dl|@k0`|iyV+a2zbDK|94^Ef1dKggMbI*YTP?O zMES#4bie_o`C!Qc~<-Wr{F7) zqeegvh^TtX50}w-d%|)aHd@LLwIBoV1HDanPmJ1y3S_`{4`2?Y`-py2tEF=whX4;a zyU6B1qCkdxnBiPf5jHN% zY{d`2)sgiO1>LMPh$xuxuDDmrrh1|Zy}>T@U>AX) z2lN-f56S~jReR2A9|t?6zfgX#0X;;RG|JCmF9{juX~1L>d!1FJ_BgA5QqP`1}-Uj{s&9_By>jH7@b`p<|ZK|yL_S>FOCv8Se>n5=}a zu<@0e%yeI`6=wGA;Dq}?h9jVdVvxa6q!p6xqxum zO^l;p|Dx#EfxZ=81+j~V0h3q@%ClIv)L0C7=!W-#t`A~}B6smC$bj*K9o&VW(753X z`d-j&7F3Vwo~8Uy3^H7x647m3q4-W}7tx>xjO~#hPW%`AFh%)c{T%5*%99Zw1J04| zr|$**2AD*hYtX?Q!@V%<@Nu2c`e4}F)*RFzd${6IEY z$Q(#H@PiY`u(O%OFb@JA!T^)MfF3YIDFYc`pI3Zd#hP7M^Me}nU=t)Y?YG+JMNOVh zc~Sv-2o>pM#q=HTO92nnfJxK?#t%Vo7xuDw(GRdwj1kB)a2MIsHjy84L55^_8^@Wwq zhK)=~D*7eS%ds)(F})BKUo=BbVDnMrHYKuVKG6f#AD9fN$?zb8C|0K>)(v^q9Pt;3 zNn%;VE&>WOXA72K%xgnEsZDn$Z{QCr>2P>9u6dWc&CWyfz8`D z6z@s~yV!_t!{Q0Bw-|vZu)00J^)t@=gKRP}5^F)M4pSArgY#}u>{N6yB8t^vW-e0N z*1>y0GZs{fwXly98w<9{>h{^6xtZf&UoQ|ai43Ee)W*btU9kS<*blQU<6eC?v-c-e z;W1Gwl%w#yAl0AW3yRf%ZL;@*YIZ<2SJ!b_7qtszOu}*u@B{ASz*bTEt=ADeu>4{z z0wH$6B9Pkw519MoepWvq%43Z9%^LdtWW?90miZ|16+&^=HH>M=35bUQkYVG;r2bH_ zm+)kMG086~0o7Mg+e8_r;4bilt1Q(;hH8RIa)LFgiSM?yi{5a82R2{*c?`h=o3DN@ zoZx}YSDzP7^dO=#e6)}3>xn=H#KSSV*UVn1V|!}2cYvBa=|f~-b`dc^G|A?xgQAEY z*nBn5hI|E^ul_NH=z-Y<%d;d@45U6zFI*y{@A=+{sOTJ zwwH9ggxCeE%RN3z?1JqjEl+K>yrh9SuSJtSL=S8)siU9V1=~yVm?C;$dr5mm1W{}+ z>FG&=2ey~AF`sxGwwL5NMexA(lEyp8ZL+;2qmkfY{k%P^M}^7>9#}ss+eG+*&D&oZ z&BendaxNaekLKcGNkj0!=Itk@i5}RzeX)RGlFi$n;*Uleg5n4K>Y=q6FV`@#ls017Y`d}xOfoeaPjcuG#3wEtz0}b%@91WJvC7|@tbVE z`tC3;9(FBp@gSpdRI$anMW%2#k&B1qK`tIxU5@$9GoD;L#KdsXpx0W+L<0^P>*^Me-8yM%h=P9hlpbHll5N>xu@ME-&YElM5av~OtW#M z^OGq_ZtjW>_r}PT4RblUP~d|TSYNN{L0(Jv%VAe~QGW2Pb$1J-bH$nB%Ho`?oC%4Y zG+;1e$P!nxKJOO)-)5eOdtoQrWA&>m6*Sjor1vK}YQ)~^)p+u!yRJWT=>wmw&J~B7 zXNvQKQ?kZ<>MWT%n=9V()L(CrH(z$ndAa^;P*Ce&=-fzDdhEC&YC`PvutX0esbfcJMTRD)8@@SG&|snbHbam_%$6t2P_#1 z<`?*GbIti1cJ2M9^oas$7YnYD(UKXv^!R?K+2U#kx14~LxJBPVQ{mKtG2dI5JyhCa zdH;dwVfk3lD^F$$Z((zTp0>I)fn)wah#RjmbHmU?cve!3ayD*N5AO}vKQg;5;3cL9 zc<0U_n=r=BD?As*eZrUGY*KQEwacq|*m>x)8xmje|JIZ0LFAAfsHFS6iio^sZJDD0 znU>kbFWZmq^EfMbu9NaZdiT;;DBb5R*BTm10_y#dX<2^p$rZl^6x#@2VVL9>!1-^rEVF8yX*GI*Lom`&8 zJc}?bu?x1>oU$n@Z~Aw`QD3SD({js(nC3Q@E}CyLJna73Kkm}khX2jpRg;H_mF{`T zOFq%4l@~3v8OVzCASxM5+g7eMFSL7D2Cn?c5t5sq;52McOS>=Z*-yP+EhpPf8 zKlrrzSQv)&yYKnHCS~yO=Z|_*zgekvh)uWC4@7s{Vo&WdW*3c4-EZg~|LGm}zMMAB zi5JqJ-YZd&4k_cw52g;C^7}6CGkg~XJ&xILyjz_x5IHM=nMD%vhs={Z7@XHYLlbnceaQMi)wAOg2jo|dAXxE+!*}!$z7LD(mKr0Lat|U zu6nFfT8b6UeQYnOb0OO8mTRRu`If3$v9M84)fBE&uGSwE5i9<$pVx6&59Nm@L5*h# z)Xf+kat=1_dS4UvPAbj2qYYgtq3MkagYNOmF&X(WnUd^~Kuu*%?xI@L)X?c|6POk@ zo;8~hvoc;B9J@9bH0!g8Q-|SAkGW$+%IYxfr`@M6<{em_hgp~nUYs=ghqwo?SS*X# z#UrK@Ue@nur4>ZP%)qX9E-;n7=4` z-_dzgx#iY2Y8NS^OG9DQUnr{En#XOc-7}(BR{cfc>$S<7vu{13X8t0_SDhrWH`FBf zTTWneVsYQ^=uoL;yI8(CWbaWM-nI6ARG~?TC+uc>Y6-C-c=c#Y1Dmg2|DJi8q>Q5n z*^%?zAVYbK)gNqKM3y*;>EZ43@?JQ+6#2C~(}QQWL`(J165}(_S}Cy8Ot10712+kN z+N%pc(a!WRvNRM)_0U{eJXkL+vx&`K^P7{eha756Ft5JL+7j%!;Nk4wr7s|PH`Bw@ z3B4}uKlr>_MfpLSk~L*R`Jp7p&2ipMrCkY`n|3!(xo246;kZLcS?J~RA4h3jPT3}^ zRQI@!<@gs%a%W0gTMPZdXJ;3}Mx!=Nr+_9|ee#tI(M^wS`uC-S)Gn6$A~Ng~^t0Vk zRRyoitpfXc*70Q9e5?HR3B!l*B7nv73Yy)$ylFg{6jZf3Pg^tF6nSj0>!iSvC5h+q z4UVNIy052lvR|DeU5q>~f;{U**5`FCkK@GEd%jNft^V6TxB5_jp$xB@fQMb%mF1)} zi2Y6E$?9sum$IEdukvI>YE(|ChkmKGlT28#`s5GKe>w2G(BXnxX?~&AWHe3|cc51fZ(+qFyEZ<1D4;2De%u^AlkS>ZXs*m_pLDKhE7iM3lqzgzy+V^? z2MzKigMY&`FDcktK06z4YfAJqX9mR;d5({H2Sh~XbQojgs^##}mIi51h)YSTqj|7x zc|&!CKCH@RHcDOXzciP$Sd~3J>h8Zdo}B7A2v4WM)NW3GN5;6RzbwVmZ8|4Tq>F>H zby(j@`*KW0TR^vOqUGJBTHvV0$J|uE9T7d%O`{;beO;)JEZH}L?^TskpE?oUHyC3` znu}htybgDN64S$d>W^)o8S8(Py;rPjNH4C4@raU&{JqQNRd&EdHZE506_ad{#BwA< zA+rZK7X-b<)nD-RgS#jL%fk2pGgj#9+1$MPng{v4B+PNF`~HCt1+DMvT?9D}o{$Ir z0{eP)baDWH@8B)KIv2$B@C>z!6o_HqcR=XtF7Tch*agaeSb?|k5muHZwLCv_iGBa=@J0qYR=FTsP3`b}3j0q3LE_x*7m#=5U( z0zF{gpXCE&dXg3GStKSv{;8(0zIU|+#s_ok~K?>&Y%aZnM2*aJs*R_WhYAFQ)u312Vu|km?|{3w$HD z2V{7PA`0gp%n8x((l4n`V!wM2jjJ(3fgDFK^b63f@B5<+h)Ex~3+($pN#E&3+w@qy zO@lle^pFfQdv)}8< zje0;t89@eH`bI7y$`SC80Wz?CfB4NN;q5SK_Ujy}Pa-C<(#zfoPJpkN)6U1|P#Hc1 z88SeIeHayk3=SZ}T-e$>-e?#5Ehmt?I~ioacf5&plUX&?BxXt2OM>4zOnGw-e`T1| zVQ?M>-etAKlXwEo4R%_xW^#ff*k%dHAfkEzelT7RlV)r#2>C$_G9*(O<|sd`@B5zu z8IYsoAcJ+^Uk7;D2{H(&9{9))R(*fu2V~k(Dg*2L=hFA1a2^J8UVOs}H8~A;(MR97 zLp+E84})+5dmjep27d>(zir*z;Q5pvOmG)4H@Fl8^Kyu&cR-W)+f~R>hzIOeJ4&^} z@8At9^cQFsFVfr}873ZNfFCG=uON8nrgqT}GGH$W=7RFC(8}mkF!}wgVQQP`^>A+R z1q-6c337r5^4qu|1I`WJ40D5QE(qu4aGti4$}kNwoNF%VSIUzLkOAj{j?mww6~R}a z?^aSgm_P=99_v<1O~(M$7(cMtMVt%r0e)Z}2j5kz0U59!g@}STawlyqRTR>{SOz@^ zL6fXrjdO!vK$VqG`2nLr9+jaLPA~u-JQYIy1bxRl2Q=wq#SeVAi=SiH_+gCl!x+fG z_(28y5J~5XS>Da~!Hx36ca&ik0F%c-hI-1AVIYH(N#yq{EZHEUrjZ|{>^4QFLcoKj zjbIY-a0#`GPAh)6!HOS301wvuU^oXq;O`7t^MmU-_yJ=WL{tjphld)74BjBa9+1I? z@&f=1-ubWheVo4YKM!AF3%?;gNHLj!`~Y*s@6owpCEy_*Y!i7B8Kw~Q0CPdBbAxD` zw*lMt(%*eZ1sQN|@M}63g#3_AWxx|gK@a#I>G@#<4|~Bj-%;5CFPkYOw32b_=U@NRCu9cGh|<ei%i55bA_KTJgiznZ$P^qB22-G%J4C1Yhxs*{;q9 zWWbpm3Krs010<`%w@-OwK~K_zj&aCM+j1 zJxBGx2N|>jeG9&HZjkwIHa9p7chL=aSOH8j+eA&KTE3#IE*fNj{K9e<=r3S~6A(43 z(^DDXcZ!Fv)`{pV{X+2(Y8OFN4>&h?0n80v*+uZc>eU!WA)*>V4rM0m(1W zcU$KdnXA#DhYj)r&Z=4cF74FQP*pp$?ssW7P(Ad34Dh?O^ft-N|09njACiL%EWfxO z<_5`alKf%;Fp2eQ)FkE???HayP4^DSSFG(Ng~C^0e(?`FyNLXNzB`8UL#l-z2IT^p zU(8TFu-nW9J+xJbOkR{9oBmaZ)Y(u=aaub6^+fH;Hu%#lIszfbX`adk2mdR0BVN4Bvqa*MJN*L8=P& z{-knMljMZm$Pe)Tq=@Dh7*DRTy`*Fx@&o+V0IN?LPP^o_U%U2hlJ$OfUffJTR<@f~ z3fnY4gC6j07JHBZ@n8>nfDr^s{4fYI)KiWM20bi*3>~0{5Q<5R#1g}yp8o^U1MBnlJn1$&4gF2_`#7n2!v$4f-K@Xq_(ZE92Kt+W)Gn6VqKji8J7E1y zho{E;U{37vb}BEo8n>T`N;Ox z3`2O5dz;8G#4gxZ;5%BVNj4vKWG{*3*c`~vesThv1Np!0``128WMFe*fp-v1vbz0S z+sRk3xuE^u5IwNDphG_qyI^(NlV=GY*qoT(MMMv5PE21*^uXrCiWUh^vN{arICw%F z)kDY=#4gwzNYd+sC)u3Xo%a*2W^-cSK1npm`Z&j*Ab4PNL5KDbo@8@k%hwV-usJa@ zH@H@hs=tQdVRbI(JK}NJ9LP`S6FjgvvAx@gU9jIVU;drg1)CFl^KT@MTAdSnlUO&K z6LY$f;DOD7j6X>5z~;o*Mo%lXi(Ox-zgHTG??z3sewOc6dEgH}j{e5t>LS~^fW{h^ z&}s*jLf-3?5$Ij-mXr@~c~QT~-aXiq_s{%idkQ|Yvv@u6T=qzyYNo$l-Beq~FX#JL z3dJISJ-)>O{D7KdbELx0GVC1l>{s7y_G;0pVvxa*_TX@K@yP1C&5mA` zaXewRG}({nf$@X4Q4?{S)$cVM`r4EA$>FQ>57%FKY5-<>FJ}|ld3|XvcmjL>;l}s> z(g(eyee8W&LFeKSYLfM{?*6Cw^s~=Ne<`7UQz}lY$`XlJ>(%d#_dIf|)$cXuOa!Xu z=9^dF$+`REkNzpoa`?rI>OoZ)B#o!P*F0=o$_b&rBgXn!pIx$R%UE*l8(x$j+AI82 zMQi;mJA3e1Xj!a(vGL}gdX#12=b2q3@~R7yr`O(13J7;A{P}6YV?n^xh$xAtv!|wQ zVYTnS{nB3yfQQF$R}K;7;*e#rEH(#n+aKIMuVb@^1yQWe`^8Nu4_=w@+Pzqp!xPd* zlk!ASb4|7-VaAI3DTfs5_1J#*wZFalD*tQs?;bRc@+?bUTwuT7Eh?-R_&Qf$9L45} zul?@4*E-J#{t#KBVxc&yN);Wze!pAP)R)~}(twu5@bK|9e=o}Wwf4n6$`5nni;>M0 z_0!DrqFty#4_f$&PoNVt^moFOalq9$vxo0^qaGL@n7@E{((-%m=RHHXn$6P^mRs|@ zuRg=&NtSOi@BiQxT%Kh4COe`2J1$SMcUf6v&irQHfx9}K0&cpXlg5+2@$ri`6@4vs z4jw@>8O;TYrtFpWiCjAUxQ2(JrC!NO!5?SX?{~*WrsXdAIYqmvdFe@ukxjY|2Rmzi z_-&>A4a3%J&Z=lE*Pk|=Jvi#V+#h0G^dDF9LZ;$!Y=cMqP!Bk>$M~Vlqtzw2@W$)C zC_e;sgbt{itNg}im*eKLn~V|jU2@bUo3~%MyzvUVOZ~rI0oz2T_3@vKoA6%jPFNWk z4i2{W(fZp|rcbt3H}TBIzHDRY28svP$NAXtkGmc)zIInJje;D!+`Wymm9*uh{ISUi zxvwN{R>mujm{n`dexuz>p>s46WBn|5+oL}y|6=}*{RYR8?N4p~@Tc$3Y`X67&I6b2 z{q5Tmmpp#?j&E0|#2G)-T&GE?7mi(wb$j$UF764-_BOKIv=QPj*c{06$9LryRSuos zZ^;&=#?JZ@QHw~I=G`nf<=JPFw9q;&@+8JltWJ9pFxjFFva0kN@}IK!&eDhLQfh+2cjTE*1d~=(AWK=dZvI z@Ox@Dx6$8I!}{b^7EKa8yb51o4>K717KmNMgKa(oGO#-B6~L38inaZ$E?_y2*Bm>G zs9j*56$E*fp7wFbSE%&I=~wIrJz$>YZ?)fzJoz-0;b*uDghET9ChmfWKXJLN^M(3P<9}oqz|dk+M21zW)%-Z|PY7dy81FMnqi*dcfaX?4xyBvR~hB0qe9Gv`+gu*o6u7@S}z0`pjEF2CUPv zI?V6D4_|`}`LwtA2IygZ9R@X7L1n-?%rw+t*!vH=K@aG=v0jau+yj`z_a7KP$N>+H zAVZH8KgfU|ep|QS&G_Lm$`9=Q2egX^K@a3M`(hpiJXC^hmec*sI>5t2AOqH;FqYd4 zGN^2esdYO3llqWBSuYf*|jT7D9WOhNKpsu=SKo6O{E$WC2gVQ2B0oTHk@<`0hYR>w&#k?iWIadf=HTKpm^m1|0Wf*VR&s)M{7?^H z!Q!ZnvL)#d%s&LuyT~7~QI*17d<&?~2N`-PKVTfiava2iJ>Y@8k!xX?cZeQ}ju3`P z`kvT@c`HUiYja{L=h)AR0FGk&Sp(S{7{x=@v+RWbE^}Y2iQx$j?{MQu`xC^n*nSr4XW?5M z=yASyl$&>dyNMf5{`wKIO_q0)uaJpUR(QY@M3f)cJnfPtJAnRXV5kLAZ2!V^hMd6i zi~2W+WwHINi8qKISl<28F`@^ScVBfqH}BqYg7{5_$uHmF=H2ZVk=tZ>cl%x3yu0*# zq6fC0b=x+A2lhKbGaqyF?kBGx@g&Q;&)-7u!1gcph9KLEbS`igsLAaYaPw~CGsG@f z-W_=!!2`>?-?*KdcNbkin3mOHZ13gPVK%=^A`rHpwP_o{1KYnydzavW<(q8(qM!PU z$KU1V7lwmeJPcjH#luG@xp;{Gh?`$be#))GoPQ0s4)gO%#Ijf&=D;spJnUSDhmT(2 z;-Tm)7Z2XoaPg4+H5U)}eaXec&bzsI*n2S-54nfAcsO+#!2_$qw7S2%iKCl)~jp3=Z>0Wd3Vh9iHScRk?e4$aa5LVV|>PpD0+BOn^-dJXLkHN(PQXP3moGO9Pa(;qESZd_~mU5YH#HOO0>+0VYwCY<}{o zYr~~(|7qU7`p@(B*W5VdRe#3jo_bnc)TR2Ay3#$AknUokv(x+(YLd-Ye|PIM$GQ*9 z9p}?HN|CWxS{>9pjWXa{JuJ`KuDJMF`;Y$qnvup2!QsgX8aiLyp>1&{x4D*YzEH96 zZkPLBJj|m!$qV!iQqgzSB<-_3Aj2m;pa)iudN1?)Wbj!x)&obOWi?2(-X8EfgG>+q zZ~va!=En0l^R)cINz29`o2T7(o8RGAe~UVdzX6Jt)z%qMS)r4x?lr%Byy3_#$NY}V zXav&I7OF3f4OsP?Kk)6hP^FJ17L2X4V!Zxi|pe0R|e z{Kek8PhD8{FyV*)hrRcHud-_1#ZyS{J=w`l0;G}xsSrYXA#G?EP%!{&rGig#>C{^UjdfE#KU%VIf&hyXNavbGj zpQJ6|dfLhfj>YKUG1s>;+eD@z5n%&{aXJG}~{OXIi2OqpY=O$SIOY*-Urxc{oJf9zp?IP=L5e|-JnmUph2 zefJj!-~8#=p7rk>+VbeSBPUYwo$4I_-2L8PtG8}B_1nEq|9R~LM}B>D_pisEJonU_ z)08T7o(8I2iTkrhzE#WU@9M#8mA@ALiAE*c9pAbb~ko$T636t`jm*1Md&N5%M z2po0h+$!NOWPUQX<(Vwx2G7g>&4HE_r9)imVfOerp)bw|JVSfs$nzG(xnw#qPlhjO zH}qdb7F313kP>%1ljEqu8Pj?#xxPBb(#z0~15avvT(It8}*uI%@Z4=M1Z2t?+qKmPQOdAM&rF5}7S zO6MZdq`_Y-E8hL!ZG#`totN}*%eN=jU-iOYA8k1I+xF9s{Jib+k57N`>!I_{$f#Jp z>zOp14{&YEQdM zPoFlWGi7pINROw8f=2U`|F+J2c9B)z<~pWmw^k4(^>EeKH>l=;j8BW7ME*kdXKg>R$_|)ZD=TvIJgR3?BqsBdu2wZq*W8-? zY?qQnX`D2?Fhx5hDt}>>udpn6&r1HHcx%}mZC}ee(oFyI^r$?2m1U0cEs3*9TZ@iJ z8K|Ci7v^Y*Xi&_Tqqjx6Z<1Xg4->T&T_hp=-pyZVx|ezKN7%*Kdb#(&la#NfFMJG4 zQoY=RTn{q^c(B0C!yB0&o`TPsf;pU$AJP=>FKYHk26&u?3w=3mj{M#o4n0usLm&Ii zXMxECSKo{39KNLZR zoopBHK@TSBzIiY6q&|qE%)ks~Jv@WInCtAEnZ|Rp*26AbAOp<;rL$NKJq)kV80zI- zgC=Q)71gRy9JLdApnAC;p2K-1`wM9o&%-vIke8G1o15S-8X&`V&ci%SJ}bxGYy;Ov zQ67e5@L;<*0~z9`lJ^()i*n{kXO1UjJ^SWGD$O^=jpMm?H|Rg>6zS zcM5-D#xrsW56)~CPOJy2r#*vu+FiVlRos#?yx)ZkbYuMqdKlFEtZ3mlit>{?ahh+y zE{I_s!C&;`_;;r;9%z0P&8NK-dY~`th74IXxw;p)ruRH#_y#giKQDdZYv^ItO!;ar zYSl;vcj$q97UgM^FsE1C7W>1AANtvE(if=S{!?U=#?I-LdUy;nP`$mxLk#e+88Re5 z2FeA|oV|sbfPieHIeTOm#1C}$e-1J%bkh#}!g!#4D0f1JU66s!Vkcy<@YZ`j#CUiH zdT;_JB|m&e{NO!0rhyor+ zh7==yxIw2aisgD*nXg{S{BRI55I@B6JC3vq=`SuNelT>?ppH~Qb&hK%^gyva)yqvm zKaMy}F$1$6GLYXSh7of({XG7|bM~ZVNuK-@e^EWV)=r#eY(-;3!{BRyJQ2gM^ zb9#>glaw=;b9&zZN2S2J$G+o`41~!Ykb&NDqWK-?C*VPz1^J5yp$AL6+-%R6uN%ig~c@q}Zl+I^Z$O zH0^s&Sk~%CgunRX6OP0_5q}Z2UBpq-c8i;P=ojLCA@fmrPjz)n%GA8+tDI)OJ~cQx zrxvy;@7;kn`Z^l-^V&`A8kz*VkoRua&lfe%Mjc21<3STzH4+U>$~utf8=bPyf3e<$ z_246#>4$v)OdK{CN&=Zcjt+j zpI75S)`7@*#d3a>oHscBWi=igUR2}ZvNr@z%6pc4&yxF^y}AV+nwV+F&J+7}%sjCl zl`60A_saa_hxRKJt{!5p{^oKu9-cg{#zVp>VHdKFR9Lr9pI(WAYMp{_RpX)MZZ#hE z-mk{P(S2%uc<50zKeXMW#)Ev%lJ{;IN6Gn7f!_&_BlFedyXgyZew3^$rad5JSu)cr z>nA14QN0}5#UvNOlkz>QdAr~T`JN@`vdVh7h|_9*cxkd44_~fV^TVZE)%2RU!>*N@eB*!PHGW z@nHJ28V~aQLcVujW~Ii%t{2pJ7+IypgY!LVJe;^*jfdl7-n&oTrpCi(f2r{xth+T- zzGtmYQS-yOF?d-0tr`z@AF25v_$@UaPJFJ$gXJ4)en>c`#>01j zF4NI_)|zY7{2=RsiZ7W}c*_RAd#gE~^f!s`nr`Wt5ZKy3f3o-Rl+1K5@8*`kk$!MB zeL=ootZeyV#(~7))0G@o=fzv+nK?LhSEp*+LV5-@Rt}4YM`*_%xSA|W=I!se!gTcw zzb8B{=c=Vl=?n{67B)%x3;DkJ`BxKk;TwZjH7IP4x$d)k3iEkBO#IT0x}Fr%aAFvl zx8HdGxT@0qd0VKynlu@{Al|~B=MAPLPIt`8F-s?gk@@N$?>+ZZ!mU>8v>ZpO$@i1jb=GAsA9u-3Z{HpaCKMfLEVm-c{c zA2v7h46oRi#d(;xWW8r0@8=D0X-bQB~ZOWn%t5bKCDpw z0`E9xZVhRD4VpyTh=@vC2giBrH|1QE@io4B<9FV9h12HhtCt(@o0<=P4?`|!o8-wH zO?kPo9%4`K$wR%|IvH0Nx|dbZS;+h5o}H_%uIribLoeG!p+&K_pwTh8D93f;WHZl6 zVZ4Eh-g#->;QzGm;Jc?TBpc5&*XP)l@rL_mqyE=Iw}h8(al%;;!#H`n`4sTGKjx}cc8(v4n4%pvy!#)1V)cY0C!hU# zF5fR^Th9v0%W;k`b<0t{@c;Cn*290BC$^w?PUMC!wWl<|19=>?;%bxZ{3t`c{WVz~ zsSARB+19~!LA$d97sm8WYsWaf5U;R!cmIO;PSd%4<6@UL1|>%JEf1gB8@i-Dbjf1v z)RxhCViD77SG;Xh|FC#PS~KeH4fPL`&ZLJ;b-i|jBgd2ann+zS&t=V=GS|r=vCqq* z#l-O59dJojMw9l6*K0X1XE}RtK{3B?R^*k;n_pv6HF2cRU>D6dq?P{}c;Qex+eH?} zxAoN6B$edR=7>?Ad_CZ*3#FgEf3B2yQkU$KY0dAvGX}f-WE>^yVKzEnz1{TlCwAH@ z`3Ka~#^vYa@P6J>XS-QrdGeRY=etlh_}p^l$(nrcndEsTKcv|_(UqB%{fjm0A#Yw} zK`!f|Ah6Uri0>D&FUhuZm&UcIU~47o!F1MOV=n8VwsKx|{+N7JNOVnz@qGJq?_6h$ z4pI7fBcO+;qh8$7wBeQ24vYtvdFifsynj>cFxyJ{P0CldBes8Z`PHXp9pCq5jdDA{ z{D=5yy{7!$T@qkxA-vuwKfE(_rRse%Zt9eY$_*NXUo?iVz@ zLC#H*eQNT4A?KM>e$u!W1$o;4kIDgLSy69KIglLA^wPUORkO&rT6lldSMyvHl7a3x zvaea{A=O62Q507j*Tcw6&R(92LU9z;!$>>`uQysJc6`nFo0BeSJLJXw!hTwNKwNfe zZvp2grQiJQ&P6**_aFRZHv3KQYWHN*R@?0Ax&Cexk;?k0F9TdHYYr_uNwa!LlUdd} zpK9JaIXT~HN{mm5U1VgBXIi*djT`hJ`*EIdZM3S|l6lyY=BEM^Y#T(#nWfV>1Z zKhLgyukL1T#G(kJyxhBslHWZ2%JW;7bNt|)UaX%SkknrvlHBjEOKZzfvTCD#GiGv~ z>*j^sTl3g&#st{b#q!+dLK}C(d-uPcM;g%kO&x4=o5Vx0#T-SGGJaV3l~t0({cGRz z=lCJRvwS#kcHUx>+4KT38b5T!*K7-ZRyB{*4)aK7(mYbqr1YCN?ocvXn`GWTf!{Br zUHscRkbkQOJGYxw0F!HFAFFO$wsP;5@Ba7QXMe$X56F`KNpVS0`35}fej?=D_N}d3 zD;N)R?6Q1H%iIigAeMuNXG0HXs3(XbbJN07<>oH?l4eb^3w~n8)EgG^eY2=GLt7kE zJl-=)ADvg)WAGOxMK&RKRqD2vvcHH=(7Wn5j`A6|(9o|p7`@IP9_Ik|Ow#B#s&$$qy`Ou4paxtY~#9 z(-`VNQcVwKgQMOYV1Kcqho+j0^22|_!_(ip{q&zZe9lnq0pTIEby-Vf{8VLUQzb0x z|KZ{PUpzdwyRzosJ!Ts_l&H9}&da_!WXkeN2XSj2trPpVcyMX42!7FK(c?XghyLY3 zQ)78wv$oX3aL<~m+nNS{vCfluGTp9J6<6=t6}!QBK5f;wbnnc907Lw6(=pB6#_^4{h!dFB20VGq`*%F}%4@=JQXEA-D~Ihu`c2{emA=KV|E`V{{Wz!a)~r;b zQv9H=}1B8wvSfZ%QMq|4g}$_j=H-+bXGp-CA>mA!DYg}&zcBk@o{K{7y!56f=Rf=o889~~bft@k9~yxNdP|aXysv}| z)ib^OwsOB7P2t`N83wsu?<4$0u2H|91;>-re?dM=_Uq}nPK^3k=`5%ohVl=qfQJ~& zEIQ9~7bPB|c<1Aju#0}z%6SiPome_5YJwqyGv4*+3!j3crlLmcwtRu85sHFL#2tt9 za0D{MV6K`ocDgC~2eu1q?4_kId*RPZ#4y1{0#Wb7XD#&cTXBc8 z$kV<7o-Bb3VrxU=@Da#h;gYYJ!TXwvFrh98GDLA@(dCcV zYAa+g&DQuV;eCtK@nT*Bj}yg+I)t-uO84=4CoRKJXA@lHqrdCoj>S z!6tNHX0yMz4`W9BAV0h96_hvp_tRbK4{9{PcYYG6{%13?`~$5CX}Ci6b`Z(y6W zhm?A0NroGshXv@B8(RlL97T7W%OL~RiLK$C(f0xmB{)q7#kzHxqu>YBiScP_JBFAa z>R1NiheY)AN`BZph99nEevtlR2$+nA9^|_o?PGO8R_$({n1bqi0$8o9u^t4sfszAq{&3cAoscN$3Ayq-C~b< zE-34RS#M8s)jmK~@Is?H(iWDX9bb4r;fID5P2A5*^-)=nfq0S_<}hTq zuE^f(EuO2k1N_hn+f2gVYKlm2gbYtj?PTlr_elXBnv2_Xvi^bi;Vr||BQZ0%8<>>u zn}{E#Jg0aZ;V-C;6!W9>a()!eWj%t*qOo%qiKB>No`4KAmsQSPEC3$JcT-<8VRAG6 z!g%f?)se1;T}V7^!e1EAUEIWW5e^yTT-F0da~H?XWql1YjGfCm88XN^5UL}!_?x+l zc^V-D)zkK(-#>)o2Wc0nJjrt}{-Sqcsf+CQuj2SYShv_)P5u7S!2%Ed%54$#wAgD; z{ICIfK)-+RHOx^tunY3t@tluZhqI`j>Dza-K-@1VewYbN%6|XX6@KvT{(ii`1NFI& zhYZA%B*UA~B-N2#j@gg&g?3C%SPU76Cn_W}>(yD5gDzj#c<4=Y@l zAEe(TexNt^Hz0$V-oa3bs^j=U&PAcQtQ*os>&&BohxegLSr1sI@@#V0Ep-t_k9um+YcSv8;UkYQ)u#0}t5O+~LRh$$HpD2{0MO z9_M+;uppwoVkgHB}D60s|}gy(@IAg;~@CW9DJ zJBS~2-UEC1enEC|BhSEmHbAF2P5gju?0+yn(A;L4dm#DY72=0Exw_56qx{ea+YDxY zxJBWIR{bU1?_UGISq@C5a721H@q=?^jT7H5oY}G@PwrFrAz!ykZiI(zQfxn&dGaNS zA3A2b9^|>K)Q92>pGA5ghIvKd2aVsseBm$Z5m(QGZI<)>Vn5CT_lto~HR66@2fGM_ z43ZySg>72+>b#3w1wY6>6nVe6o%q4G&u1UsFKoaMbiZie_~A*&V45vo?Zqq(Vp`+5 ztc#821^uLWJ-lzS9?$`5+Jt@XW9NYoM-kJ$3_Z}iAn7l@0Up93L$nb;*bE0`1@k-* z@fWS3E_}b(&-}23?ZN_f;SU)kKkOlXSlGZ@8$_Ks*`{%w`B6lJS3(aYg9Gfs3^G)4 z{BSw+5Qq5T6NT+DQ=RVJh#w|#W%Bd*3rD?+VV}D<@X!qza##<<4{u?*%i1w>S)-UI ze-`|}Y%lsyh-qmqtE@BsU`(C48!%~HXP%F2^Vm9bl7S+Sb>Ii%I`emchiLfjY}kdY zGdD$@`7rZCAoMW6{7``}yh{8KR$p;Y)|taD`hm$I&Of{iet5|@IV90-zMS*woPJ~y}$!m))4eSGEkj4hG7}%%!wa5fJx&%HFNZ-jh*XGJV`P<3>m1- zT;4Cv0S_cY6Z9baP{LiSYl8~JebXK?SVIQl2N!(dFXD%QJl#32GyfEL=zVwlsA;STF`Lk5H91@$6+kaa<{7v=?Y^aPEW7bNxYCuE?#4-@%* zA@ALEnsmq60~zMPcZaagl6E2S@F($uVd}ECri0_^G}r~n0DkDO#JnJJny7~X9%xoD z*(OD#@_sRP@55rgU#x`;biWX&_RX|KTum}0Ko7D{Ew01Iy@%t6CBTCfbCeD;Y@zs} zyw2fQ^iGlt-vbYuA%l#gu7V7EXZRT=lF|KwY|}VDxgXP?#`d8|J)FW{P=0d6D1MN( zNi`TdAVWOv{u8-RP5MoVhn3I+?iWCm@D~(6P$aeic0n@yT_4JE*oAQ)%89?}Ly_^r z{g8q34+7P-PCCR7B*SLtLGpt=`cRxE2pKj44{JDnaD@z~D1NBT)m_8+$%lXknsF!j z;ZE?w$C&Fb@j!F5h#zDe!x!XxH{rp;WpwWY#nlfR z$?yndFy8wxp8e)~(1YZMZDaU>X51O`!_vRu2g=hDKU_M7AEMy9NrpR(_#xSdA6^4L z(2P6E!<66)N0=XEMA{GE{l&uA&=(@2~5iT!w)~zY(VW#~9GEfWyesKEK!-Jzik)K=%Oj2JGaTM~CEf&ZojolkXIS|6+UC@K^ z-lzt|)g;3)*af|@(%vY$F?*vf2PS3x1KuwpXX7--&Ks0G`5k1Sd4pPxALPAT+z#4w z-$I50FM$V|gE8f7lk@DGKEA#U97Q>hpcKpscJ|G4OGzp7&(AI~clGjJ1WZ!?fp)s} z@mY8P54dM3dASL|4cZu7?aSLl2ZQzaBEI zfn5+kd<7Xkf(+y@euQ1Tg0rBw`a@vyQOH1X)Z>uhC}bdiaXVyqh-Ekj8MZP*bgY*U0j=;_^BRyo?Ta#(Le>2f@ za%Tj`a!&ABS=*4k#M}dK*adx|c5!z^2sld4J<#6d)H6`j|3D-3K>RS#sZzGs5uRy@I2l!8zHpW#6J5@Zf&aU{(a?1z>A^WAejB1_c_h#58eW7@0{4nLC zh^uR%hoO7R{EX-9IW(2}xZpHpomj%F4$gi0wgUmcBz>XSJA8aF^dRdKa}1{u?iMx+we()$Zc(qHV_ zAn+jj)OP+X_(9Gyzk090gX}x-JT2^kX7$itG#wLmA^X&BJSFTx&Q*KiC1Dq`PwmC~ zgbebX_tN_X9%LWNGf~1WWZ%K%6UAT1J~fK%=?ejT7PsYzvygpiRrd%z$Ue2>H;D+O zlKDZmPTVhKpIYW^;w)reQc8_D3)!dk>OJCqA^X(sw-xzG*{4?HEc77zP%cdorz!hT zE{PTVAp6wh{lZ`Q3t#`^_lUEQeQNve6Nr+1Nqf(V)0BNEL$3&ql6`6ue-@aOeQG&p z1wY6>wY@isjJNDt-24SucSn=#Tio%RK(*{sbGTiNhxFgncrbZVjfc&@sPS;a5j7st ze^cY($(Pl5_+yJ252fb>9^`)BRk3P3$oqxtJBZsM@F4pZgZ8WO5dOOw58;_=JRDdf z@F44gu3f3d!+}$3JnVi>jfZc%)OZk+xE}gJ&WAC5MvaHXW@8V{D|)ObkvMvaG)k!n1A_N^KZAKs_N!&l#{ z@!<5T8V@Dks_}5?V`@AsdrpmqBcG}H!LL@0hrtpxKRot`8V}FBtH#5V->dO3cJAWP zwQ7EtaJd=}<-e%$@aofQJbbuTjfbIM(+&?*ivDiWq^u+L>>3U-o+mcFFVMq2Vzv_7 zPsIJA|Iuqy`wkp)8v00+vJa*AnH!WjTC$(lT@%|#nv`{|2hgEaLP|y ztXk%u(bSRBliIL6ddW~|ORn95cC08L=NA&$sr3oB$#qMaG~cUiv|g^@?Ze8vLD|RJ z(pnZ}Y!^jusrP`SbVjT8fP6f1_F&1nch6QKrX|lCyP{6F)MsF*-gQY*>+<*(ahjw3 zIA(pxSx*Od{l0`_`vRL{zkKe;NwIV{^k@Cs`EurgYxBV{8))|>F>P^buo6$wy_@b? z4~=}>fS7ipoYSlIDo`v-+QmEG7t9dTzNuk6O!dg0L<}S6KfGAi+i^@DxhZujo z0S|5~+?G9jyTc`NUU6--L&-RMSHpgs%Wge$`DYeezRO}g1h+43pWdChpgF*N&PYd1 zRiA6zU`JA7(s;uVB0AX-itN zIB3y)|KM(`%4ref86W+XCw+hxK%X&X0Fq+TlJrCuixv6D6iq@oSS<4+Rbd zd7g_Z)BN2N$5&08zmU$tIDRm5Ip`m%D|%rz`wL%(sJ`SdZFFpBS6N(G^Yj|F3&JGj z9|G$9&5iR9w&k_{fg7GBUM)+QfkgOBS>ShFK)d@O8+EA91yas%YsLOj{DPpnV1GLgpX- zZGE+OXj|9_KaA%YX;-<#)y-GC%LldeF}?Q9KUi25C;t z7eCaVGv?8J#5H0o{Y@4e)IULAAj^x zP_5~`;(@PzyYsFy?`}W0bEx_PO7Nv!J?S5f$UToAXhWf1sLw+7mS0 z=-uCoeK+BOEQ|I8=?$+isOg0s8i7eU4+LzVh9qI;QhwK??kYM9l7aH}??MkWUv3e< z>tzDfo{)iNU=kj_fed$;rfaU?ynQhEp#U;ay&U0T6J+>&>FB$E3-Ca-YP2(&zCiQk zUcw8=Fu&``)1-Pi`of)%f#%CS$CU$AH@E>Z$o+a>KnBMgIn~5lGmZ1r`OMYyuJ<0^ z^+I^QTs!;C6vo43yrDE|Jucekel^Drw8_-CZjkC}Z-)%&ign{O@xDoQgHIKT_@M!K zXod__FXu!u;GK7{y3S!=r0|XP~fW8A^-N;V@52Q&C=1H1AxfSy#$JQ0!$$nFV zw*z|DlV7-l`N51iiumDlUk1O*iFbdRIUw_L^zL7dNNnu8|321(Gu|)g-Cy#zy5bG63(6IzLIy%qJ?bB*uDC0J z<7(yy8`gsj>Z4FstegeOKy{>KSsA1JVA}ULbwL*t>-Nz3;hopGE{N*H$Tn*r1Nm;M z8>G4*It#*s4=_0cGRS#iR99R9wvS+bkb02(Fdy$Yw69sPy{Ho-ekg<<=#B$^h@GmV zzYsSysvDHEABi8RZjko5kA2sBo%P_2wy`}G>}zBxQ0GA+JA#MM++ z90R+c-MGZn;ot{Lt-DS#Oq@ZJoRr&CS-LvRjPcyp~Ul9CI2-}3%!g&syT9x^*atn3ZOVBdUc?XRI|vIB{$e%kA_{gveFubU zXYd2WdAb9<&zbs!bq zzJC5$0uL?hHzhx4Aj3k<=zQ7^=7%d84<3-gcs}haU=n>ON(@8%poa`JpSE&PSk^Vr zgB~(uupU~#52o1xhCM;jE(F_SZxk%c2|Ym%abME!z+?|(pxy^U)Cg)YObTQbN4`FR z-;!J)1NA;oUC?CI6&D-D5A^0v^-=VNX{e~t@-9^3hj8%2JXn@--$51lVeCG4$q(Jk z4=?bZL7GoX{E!VjQ2gM48cwqu8$;dT4)B97IO;6pp$L{`TsOFbIZEom3H(5HgL~Lt zkX@LR)B>@lQH%%aeeD_Zp!w(f>_+b$IaMo4$3(1o*esDniV7zD0 z0eB!8#z7C10|7r&eu_PVg%GelUoCW^gdk8QtL#0 z2Z8tkXm$2g)x9J*;7Vume9d)Xg+h9=;DekZs082I`%}42t?NeKVt4 z?AOZ$KN!~qQD2h0Uz`CR?u86Nj0fB=8hiaSif3_Mkcf%}Kad_A!4EXQI*jiZ#1CW_ zBm;HZp{9xIg1Bp-H8cjOHojk=?;!Xtu>Ann4GNYUonP$$exSYsSvN@YtECLY4|9kg zP&X*^FhQ5LWhb4z`}soV2TS{&&_3rCeW_i2nX!?k6PnHZGb33Bn!RAcr#XVN@CGKO z9zLrOH}}JhBC~hQSG;$x)>8%pGE5bfMM=d%la)SnnmMl1stMJj`N>%q&!_DV!xv;8 zrv2jiv@Of=1(}EOxp+S9U={d5-n-{tJfAkC4Szu#Me}I`FP=|3X#{p5^Dql`*!c!w z?twMyA)+h1Xc^n419xz%hr6>q?q4&`RKn7>nMI(IHy;B7ylVO{LsJ+cr>lb-TuZMjHcy7N9zO4i-y8yrWKBs2B-%LSscU>6U9tJlQ~%et21hk-8Aq%oq5t$P#?0@Wgh zp;*q3`9aQ?yAUMsAm9BzvlV!d@BUTOgdXI(|J)kNaQgbocmE_ap$GZye?=K(ayMO)?@lq_`{ZF`xh*ZA&FK85cknjHY zx{A!6eD}YjMpT-~cYl*t#aYOA{{tsEo>WfLLwCGR*oDm7>;Dv%CFhZvMAGK#(fPD4 z)uIwrzWd)^D>4}J-9O<`aTfC3f8Vv@EabcYV-5lj^4;I=5y6u*Cx`H`uSMWNzWY1+ ziq1#*?!V7bM5OZF|7e4_p~yNA>!-!dUDkm-|BHwpWF5$l4uT(K9mw<>MFb+_>M2fY zJdB^A#=}ijYCN2^RO8{3IchvSR;9*6+-x--{8kE7OFSIkBlKXvL%SLeLmvq|$oZ4k z)~oSwz*CKf-BoHltlz4}gS>CbcYm3WlJjZD)`3h5Q{%y=QjLekxoSKdwGjLu@o;a7 zxUot+oVHQp!NY-GiXBX39Z1xCH6ARz)ObiRQ{$m=u^JEi&B^0b)=4~ET_pU4#Dk@Y z8V^lTYJQk+rpAM5j2aKyW~=e=q@5ZM_Vd(um{_jH!*%o2c-Wq*=7&d2)%;+yK#hl* z2Emh(9|qdgcv!7bZDy`Ib=uA-KVPMiV%7z_-*BcN%OZp4<2oYCHe_MONl@Gwh_hx-TAcxWtB;~}O@jR)rp zH6BXFtNG!0shS^-mZ|w+hrOB~nh?_xqU8I9?1YthS`S+_9%`D@cnEP;<3YPj34dH)<&89yYYiwH!<4;zC;K1#+9 z$H(AdMzxwB7PhMSA!~t}AHK9w^TU6p2|UR8Q8a^s5LLr*^@%z)9=27e`QhYvH6CWR zsqrAAL7DjPlWTaua|bY*HhoSCM^gWOXr=PvputNGyuFEu~xPg3(kzk`||G>CkZj3?XOD4R4|N2*Ozj=`Xw8ilb-StsCKn+cMB-y`LvGNErxozf4gsSVv%~zUd+OJg(u0nD{(_P@O^z| z_qv;RH}NegFQYO%!>rPITy3^uS@aiF|KPMJ^+@EYA8(fPf~HKWu*@_s47aYPjMnIV zGw`*6fVfW<9GCCBzQarHH4CCrB0>f#lB3-J$M3wQ(bGF$v041x9Ob@QSQNG(ew+=@ zZB9t=Fx1OUb~%v?yVyF5TbPtPrAZ#wN6up8|Q_EO=+*i zbWmbiI!$`_A4m$iYT)GBowN&;5anJ}WtmtQ$rm{mSaZJ!8!TwPghRUH}kI-Z@F-I!|6x%KltwV=MNox z@z=WqKM>0mLWU2%4SFH3Q~O|r@)wv7V-wXE!}Skgld}`5%FR@Icz9LY{(xHT-HxmW zmzs39e4fi{;zD3r8iys(Yx=9`vpbC)PGUBc7ELAw512S_`c~AJ<=95 zkQdnB?9!KE9x^;NGB#y}MZ+}rDt&19eA`?d>Z7b3mqm}HW(PMcV;Y_P_KJTI|*BI1Y1zom6Pe|hkc zf1F1;&i-%bkuG^U-Rrk|z3=J6otK!_w@zOm@nD&evZA@wB4aqZXJUWjZ+SReRb1wr;YP4)$kXKZ}z<;R-=8zQbBcwceYhg zVK~=;xY>IpIhEBbc^IjO3HzeY#B}LivsSDd?|KU?GUZ%Wouhe%g_XUE9}YRadhm_2 z^WUxF_#q}?mQRuOT&1^~>S1y$5{O|QmwV-=qzHc@^|0?;<8-UPmTz3ndI*e+nVipa zyt676o5yEcMpIr+^5muqotX~z`~1hA^X*n}{QDx;BjMLT8yh z&#St`P#09QR^t^n^6vU}Txg_*MG~-1B|T$ozvxT|t@8 zxY7Qso|xi$(x>eHrAs+YZO3p^U)Z3F!Z7~TWs_=aBW=@7P26qslYAVa7LCqj-9Piy z-k+b$-7$;vll>N^nQ?kudArYWerHfiSUc*9+q5ks)&om@VumIe>gB%MTDmKydiDB+ z;3#64xg`O0l?9gCc-Q>c8H>zk4G!v+S6aFyQGL|gU*8tsdaK9lh3q%A>8>#;gSM5W z^UcjX0-7hbPi$2*Nl_5-!-4Xy2OqjqyH56@3`MrI`}B4i=9zzJIn}@&$?~t6`hh zKN7mHKe%nPjdGfJzevc>&gOaMMYc($)9o#kJPh3qC|_-||MmOcH=667TNP1QILpD1 zul_$>XMSLJY=-3vFMZ_9Jekzx*V{XoH@~usCQyymiP4M$%2K-NDrw8yq~M=wus>29|V8jkOb2pn*un;P8?s9x@| zH>>WA2-Do*z;=;hT^y3a^>R5i@s{)Eib@i?EzW}`H~lhrbGU2a9ZQ%W`UZj$dYO?eEo7WM&EH7->B~>dbt0fDb9izCcrVtCxiPA3Q`^B71Y_8FKSHcY)WiV7>2S3 zrjWsM&*IelD`#9j%yywOFZRyidi&|-wn=dbSvA?EjXv%5i&S{{J^#n$kIlS!o7~@R zn-#mFxhFN>KYX5VrMa8IZ?4(-^vw&b_k3onShtUE?o5y3nW^)VC#UDSYjt^1-t&^9 z>?UOx@bKrIj~)oCTD{(e@i5)Cczl|~LxDwFZq?*+)8R;izc_V#<@&v+-d?qg@zAv- z)G;KcvA4im=t1(s-S24k>wC28WIn2M`rv>*t5m3vx z`v2CPf9W^xI-^YDS}U@w9=bS%?MLfr!$ZGKoAeKM;h627Yc-R$PLICpH6-j#NnMih zh85d|#~gb{PxhM=ZA<4wOc<}aXLXi`uLjryT!ELmlbxRd2T=gKv$75N9r4+l>C^<3%CUKea7Pg)j-q)NL;k2g)vcBvwUkvw_g=&|d| z_UB$`lRUXRC~>OfN&WO$&bgiL#(4PYjo-W`eLZizpXAB>R2y?`6&Ob3VJJTt3g1n& zi=UyU_xn_lf1o{sRLknY_pB`To8mP}+0Tp35qCV;9<9zti6}_KFqG-dDOKkmL^f&k zeN*aT$&r*`+vi93K2(oHRaM*6r=Zqd6+hgvyC>?~-LY#*IezfSHBX3bvaPCCP(2z~ zKlRx9AA-xBU(VvVI>%P$SH*iDrq6Z>HsyI@lue>Olw00Ex>=v&bGr@Wp|DEppTu}* z8+3`P;yO~wF4h8*CwIN?Xje7!kj%sQ6+|!SZXLA?kMyTicCo~2NwTqBJT~+5BLh={ zo+)R$nBrzz8^d-{WpC-4;Vd*M@7-T6{`{>8Q=1>MV}8i1i7d$HKDBv?b6i6LMV?m1 zlW*5wuA1ZRHfQz1uFTFP`t+vEluJ*@fb!CV6t};6sl( zd)BXYlK1YqbhjeDcWYecx#V^VM9F*ij$0K7X z&p{itoNSZqLf*43Jnitv!SvwW?R?L2cGN{{Sq~FBf^?}3i(_gM#jGC6Kiu(K#jz)X zTc1s0JrvtlRd}%;=1$0;?^#`7QfEIJKg|3q`_@qH;+@VMKR9}Y1nVcKSX-5=^Dr4- zWuBbUI{Ain#>0+-Zyo&O@SaOgzPam}b!YzAblsr~$8P%17x(^r&DYz0e*41L$6xw( z^Bb#fU%zonyefWp@7ET`@X8-3=Psl9lQNDP z$-f)%PUN$u%#)kft=s(Jn!SJiwspr*<9M?7JM}#)-Zxw2FZ`ds(hfZNqA&XkQyU+} zvLqfBG%Z;>eoc!(4*_n0Q}scqmaf@qJq$nEe@)^qZP)5q4_fE=t^_Ol=#U}tj#JHZ zw8$=q<>b6U6V%I9>FljVG$?W)5)Z_*G{?I$tz*%p{UQ$|d2$KQ$)S10R8K3bylCG+ z0%|yo=Ja;hOo~j^bG^NYg7Wnzxx$L(Cea+u?aUABQ6EKb?qR4CBacJ#f^zH{40AXK zfQJ;+iOIY@%}uiGlT(*7yhRp8+n33DpnBTJQ7?CCl+c6xix!^atwX&%&G8mh;tnSD z;K{|1!ArR%DgGjEOL#;1*g0AUxI#M_dZ0O4_j5eC8ugRjuuW^87qp1#?eqE~_Ed=X zO{%wVL5-FV`^_Tgp?7kb+e=e~zvzb^jzflTAOrcV0q7x?XXMfsyxCuP@f`>I++)x5 zwuV^ooV{+2VMMlB+t-A%NSo=?_i&-`nl-7$yz% za?3G8JBR0J6+;GR$l!sxL3%@JhaMb?N9XL(94#xBf$kSHN9zuwdN~vLtRDDoIoTEU za=|a4@~~`7y_^TjkSyxuTmvcv9&CUIp-J%~mL%%s{O{$8{qf+ay^sO^N%=wy>L<(G zr1$sfv*Y-o6Ee_?7}eWjq>itS=j{1`s ziu|>AW0n_L7TLub_TA(+!+?irn4%fvFJveIs?8yTGwKE@hN(b3ZC%#roIUD8>1G)S zlhlthU8%qnc$kLx!5nrW_p#C(?-;Os(3m-#=`2GW>L)R$*Sjo7_zSX4p-F*;<9{H6?65PuUgwFOu0d2@h0nf1QFT!7yz&i$usU zzuIHRr?V!LAOp=3Cw|BR zKZw)RdQcW60y2o#Nu{24z8k6^wfW);zp`x(ay%Ibe(=D&;<5F#F|Z4gA%yE`Um6g0 zaUT3oiMqjIjvso!53^>LEz*gXa@G=b!jtGh~o#9|C@;hi!WBoV`I{vJo;g!Y-)CJRJNmLo?cs z;|tp?Vj1WxXwLsfO7?(GQ_T4{gI!3EL;W~Kczu{Sq~-@%Z(k|+!N->8{7b(n{sME= zsNUW%Ww)~KRkn*_$Uyu+b9xV%k9k$(@FNy>r0iYp~5!jwdG&KcHW4DbLxHep50`9r!^5+w@o}@Bpq>7)HzS zL%Y(CY#}T&!Z3p$^kS6;f z1AT$^fULqEkg;=mDSn{8u!SCs=k#95wwVY$&=-gwqA{m;>>SQhkb%BX#r=98Dr_%i zU$nirn@Gu|zum^T=0AHw~_(7xbyTEuLyI2iO%D#g#=wYExz`!Z? z7i1R`VVfSX3*v`r>c{ad@($#F-W9+@3+!Sw?BW6F!IJ9jHT^yhG9H?Nhi@UnF^(T5 zKo6$He!gcERJZ9i0uQvAt_?DfCJTrk(tW(|L`dF#5NcQ8*|1bPd!~F0Ea}>o7TbZLM5{rT!su4ek)6{7`R#1&y zB+L)gua~ZKFuj-gL0HyIJ?Viwju-Sm{k-xEv=@eacLDPQ=KL?YL8mPmyC+EQI|v6q z(4L@u>@PM05BZQm^1~wH2N!q!3p@#&`dG<#FN7Y5AEw|ea;#*vn{Vcez$7t@26&*m z9_C;a?EXYrg~>Qkd!kf>hp=`+Ducvsgt{nPy-6nLQf#c3B|7vwiTR4hyQi&@Y^ zIcDse@f^-LXz~xpK>Sb$87hDW57)_jJMhub90Nf(~;FIg^>WpGFQfH~epsnH^?Cf_a3g7jd4voP&y4PC;z^q0?T9(v(|Jzs0br8e)M#EY@k1HTA`rcD|HKdG%nu>U1jF3U zb|LSZiMVHtU<&u`ya(hGw#``nixS|$#8aoA&b!Qhf?cFDKhTWaIm8c`<1P0DQT&h! ze{nVMjVcE}81D%pemDw_DuiuXz&2^OU7e3d|8`FiSCeg~;@cmNpE$Um$!I-Mc9_DDw|G@MOIqdm#K~8pkm77u3&N zhMQU~=O1c-hw-orilcmR7CMR_bl!$J|JJZg;wa-iAR95~f9xI*$qyr(e+cIL1?3+k zM-e}S0}l@5nP-VVuAqAK3%)puL16NA?)U!~cF_g9*aSVK zz;~yDAL22`TlV|E0Dh=sjv_=Af**|g{q2}(W&Dr_Js9` z>i4I!AUx2$n`Cf@43|L$+8Olf7+zz`ShKYh@WozadzHk_rBt4k19;jdM z5H?4Qy)ro<1L;?>L#M>&3|gI&-UGN6Zd zoZZu}<9^;f>^F%g=`T9qFMjXwO|Rtq1Nm;_o0^XJ!7zne+jkClpwmoIPP5htbNz)HlUZrYIT{pu24kT~$x*Z? z$Qd4IZ2UkxNr;-x@q^qm=m<;_MOlNpR2v8+uq))Nj}WazAVG4t#-jB_n>Yz8+Ie`Z<2E z0UqcrDUag^E1X5WQGPNHn4~%XG9pF(VOc#gIZNCHKUe?{S2IVghYT9vp<3^4h#x$F zNxEOiz5~(E>-~@UhfL^!`gwynKPlsC8N;}Oqq<<5&tn$}A<6+~K^)Zz8HgW3Aw#XE zx^5!l;YOhPCzgR?+7Tsw$kScUn?%Sij>0akDG-|M2OeU0M-L%t4ci6HGjD<(Fb`zW zM2&Ai0OubvfCqX*5!Eai-rc~1iBWzs0+{>}GRTOO@(%^bKa8ChL_A5cTp;*?<^}!2 z6GbSlPJ&%Xh8YJu#9#)6JB)1p!@@Nq3ZIOA8vIvwH@R4x{P(a6`F@e3@Pk%=`?Hx>>1Rf|7yB23b`AN(JiQ5!DzucPd7waGc)o^MR@872D0Y8NM zinAa@wZSf~#}|zAlQ)2AuPBp<5|(v6^g!{0Db9lW{hK*{xQ6|vjHBYg59s$V-pqT% zh##bF(ieg$et;fMu+O47{}jVq!FUKKekgVsaO6E=zw*6%6ZAkV*Gut(Ueo;z-!E=w zyO86hM))H2S?z+)UA?VANs>9`JML|WFS4z{h}N93om}(r28h>CfzS|&_g@U z!m=aB`3;^2(#-LL1dc&Oq0!`S=9Lhz&~Y%`Df z;XmL9ygw`P1EE?Aeu!T*I!}!9_8)T$Bl$sRnC>F-4?n@OWdA1RA8tebVV=?MOJe)= z96vOIA5j0GE3gvr8+fR4_h9Q5arIW%rs%#D zdxAC^PSZDY037uj&Vq7-6h9z8Y4-p!y%8Kg$Vlu3<#yoHHw9;bJ%dgYxc-6e-NLej z&+?-D1AMo9-=zIGc{ok^zS#tR82i3?556F}FU9-jLx$HV5kEZmH}S*R_s#Xp4{joU z_{aCn5D`BZ<^_Gj{4fB!a7RaQB5c!mUJ%}{bh;Z_o_ilMP@b0N1?@1J7vvEZmgWqO z`cz?ik)O2Gx%QNC{2=|Nj2~|2`-Kbh1LYs6RxN@31=WGXp!Oh$`9VfvS29P@J*yvQ z;mCW;P1tYBDCiF5ela>9#`QpQU(LSvkJz)n7+mZzJQ5Vz6_FU^w!k-ZqHVQn%tTn$ zXFZ~yS9B#)Bqs16>&&k>zd8oBtm|bzZ|Km}IPw>1z(W`C&;{EZ2R+bSwN#wNQt)Ih z5S0l`&I2ZCrWx+tCZvZd#1ECgB*nBD@L7SdP0~Xb^pFHSwBsyr$MK&=b^*UR0UXr= zj-q?kAoQ>hXYmL0@G|sp5He6~|1D&od)8-=;d01u1!N$f^(JIE1Q~WfhV78yA(r7` z$Z#*q@D60S1~N>74DUdOh2W@-kYOiecmguCLxw7FlqYPn9x|AKqsDYk3$jDf_eTx_E!qa^wA3 z_g%a{E82K})*lz|&&o62pY_hg`?C^__h)^5@&2q*Am~JWHJ9C24~R;JXC|D>~IziQDW{vf~(-DC16Stda!yWep?dDYbBhE&$T=A6aTb(^sa9?Wg+*Jkg&yP_jJx~= zKgc;44`hfA4%vqi>7t&4p-g25SIc~qf(I~+oCgwl+w#Yg3P6 z(}4$y%Q=E1D;ExU9 zDEdM|fL&QE*O}+om^$UUR5#XjM<&Kj8ZnQn*X9o_u2te{*{^rsBEOWYUi)&Tp7k)H zb%u>!by&iRMN!dq6HI*DXL`=_=;|}@L*rIko0q=pe&3q;A=9d;SoZTeYwf0_mDCT} zO^vB{(dQPL!!Bff_2g}>%O3k++2ft?S%j#=Nls59QTm#J(X-(a~x*{>q_inWF4vG$>aqVX46MD?Og#GD26GrDfX57 zP*T0T(mEG+%^9Av%)L)J&C!0nwu+=Av*nkaGhsZ~WXB9iJmh=2m6ntz&Gn8n3m@UQ zTGp9AKR@-?-G7=qCg)ds`Ibc#Ra!ZWx3HNP0~yHc(XIha(Q=o+tRH_uuXw#uw}H;Q z$eFzNA)w63G~Knip~@k2IA(@-#EK|KhbhXoBN59{AFIDlsOvWSufA@(^7X8?cf+v zQ0=1&LJSj;>Fqk%YxHfA?82GxFc)!@Nfy?JE8bs5g8~n-4rD*-K*X&%$F+p*g67K+ zCh48`5xnyj@jFg9`);b?B(_gQ9Mz2~@qe1jT8w)Z&24t$I`cQ!cguI)MC9e@op)>= zhGs{TCc6>KQ66R@Pkxs3%r`O~5-AUp?}JKIanD+;uv}$bI{1M&isrie7-jY>Sr1Jd z!;GyXrS}WtI?{67yZ^3^lxE8l9)=K4QXQ%GAL>Aw5Yu`asz4iu2Z2d9Bc7ypoaKM> zjw9!?Cg7e$?>OFe;@-WB?-xgz9}*GMVjt^_{YG zKFu-h$B3)b;Wv9HR=J%`6uz5kll1W2&dd)zbkFJ#Gir!otT~RNy-_qfn(9c`8r7Na z0#6cGOMX~_xSHzBWgRJI>?<|iqzA%eJY=9cQdtLbJNQ9Eu{~rUOvd7#^>=k3SF#=! z;GRWwV)7m5C@}deWUyj9%t35#{El-c?4lPk+z35TW{>jrCZ2h^EBGDf5KukD97Tu< zLmnm(S(HmTPfPm_WKN7C^9bB8V)4dm&3TwiLj)q?hhUrq<~H{|>LM~2$-v}ce1YCr z`yfLYnzaO zELq^(4O|aX1ZhXzmV)$Hf4f23lXZ}DlWct;?I=b^$janeMMyhprXnOw!s^ZCi+O#3 z?dq8x(0t)3A0e0tj0;$Oaqe!om@4r8tXgQk5K-6l1I};4_w%maRa~G2Joi8vT0YpR z>N&(9)tg5rNb?l{_v6Sy^98qgaRu;RTJT&mXn)pM%=2lhkk6+*joHu2Kt7*#7iK@J zA`)6gf%g0V#q4LPg3hOnJeTu2KMb)hs8t=(u7>SXlTz>mx2qwoLBx5*u=Ar}{jA@W z_jW%@I(I$-nlHS9B-}ldxbm#T9Hp6@okGg&BU5Cn%S!aEfoCsxdOHcYCUWTHNw~ts zK^;<_p;P1E_qEL|SJKN!5rH1ssQY0Gik1g03@1zDEo=M*6f7SU!{i%P0Vu C;Nijm literal 0 HcmV?d00001 diff --git a/crmeb/basic/BaseController.php b/crmeb/basic/BaseController.php new file mode 100644 index 0000000000000000000000000000000000000000..18cf31c207f2b9061ba4f36022931fb9588899bc GIT binary patch literal 27824 zcmdUYd3e*+)-|0c+9qw&rfHI<^E{;UJfuUKwn;kBiFBazoDS)jwuxRYPB?%H3W9=) zfQpLqgd(V@2)ydWSrHYzil7Jzh`_gZ&N(#c#rxg+et&&`>Z9k`S!eCF_gQD3U$b(D zdxj;QQ)8W4UGI>#Wnieaqq8GCOgA|+G|)-@aWpJKGBhgb=gBTN!2sVJ#vDN>h5Waj4Z^J=O?8!B~u5^K-MjIc4fHAAzt>=wY^khrn0R z=pV_H>K#)eV}?SL`lp0Ef#3iCE0lUw)ebvpru%eD zWU*3}&ewxe=Hc&LQ{-2`Qwl~(xs!Pu2N!wCXKH^zczD~=dd;$#h>W0))@gAeSL|D^ z@bxVa`DT?jw+;2+3O93={#s7i@X(}#JTj&Ew8%?d?pfyIz!h@+l!9Q9YMSd|t105D zCe%Xxn6$d3CD9O*t?Mc>DhfEIe6dhm&S`)ZT=;{g6~rTCh5obYFFADlyA?X=3L;p6 z#DFU-jV3F2Kn%OhV(_6cWN_wVxcUl_DJ%x_U%`Q2Q3b!E4t~XlOEzhZucLbDjm zSKvSlO96*wz~Rh;FP^;BNN{Kd9HIe-!K?m?$dseEetp~=$&dv|#$Q2_#PIPL!6DY8 zY#4FqlV0stkiA&?`dAIy3ydKMVu(Fl*zrUB!}q(Gc5`qtJW*aOweFhn(!1q%7+W}mW)dN zrt7_icKsOQ5DbiJ@9H$Z@bb^k+~7r4=m$>r01kmy-A%5C9q^$6IN1lBe0d2I5C;rpS`l}Vpf5rbU23#SvmSndx;BW?Ts2nBPt%SUYuWGqvrUSFP)993s z**%ZL0PIB+;Bdf=;BX%Jpn|+8hrEb@z4)$;Ao-kzWR~5^)^F{T=U2GUZ>bMXpfI=> zN%llxjyV&B$yX4CNrV_Uuov-mBnBDq0aqB!{(r;44)`D(@n5^Ig5Xf;`=4vn5X9ix zPZ)K8OK@oTA^l}d=U?mOU+t#0pYWj$a8R2mZ6Q_KRy9-Fzgpqn<1htz(bOz`d4&tf zi;9x@y+9;wOgMvFT#P7{$545K4nGJ-j)CF z_u_eoK@9q!27NGK3^qg`zAqyZR5(r6o9&0VjPSFK%8+YL;CV!C{c* z#m#`jdB9<9BEdmV>*jr(3oDMLKK%RL)Q=^CP9_*)E+?iDKGX~6_X6{R;2fA}j_r+`KkK?hRZMOJulmh6R{r)39H2Ks<|@s^R`aPJ7M zn@N^P+EI-fNGCCT?M-kP%%wO`mE!>)6u<|cV1k1&?&|sw20Dp*aY01*@PdTswLpx`gPAVQzuK%E`$yTFNQq&=~MnXn_yp zS3LjJPfwFyf%<^E`LDm?=5>gJ7wiR3KsZ?hdx1E3KlbXneWN2QGZzy+{KJ>FWi@zL=Z#<;Y6C8H?5k4#ftwtob_zWL?;dIlxFV&H}xJ5`}a0VO@$>*gd51hCy z@zO00gb&XviB1+!K78CR`?P#gbmwypgb!G=+Td6C9(d@(H{zn7Eu>xXK!B=B#N)bV zNjgex1S0VgG2uf$&5IBL;e!wC1y&sINy3K`st;k6gb(espIpHqI4GG;8i`K2(#|~E zgWym=>xES#sTbp>E{Ibqpt(6f>!vK7@PS8r`!{$52W!fQJu@UPqD<9aQE;w^;7~^U zsIWSc7y0ybknck3rVrE$%&bF;i9RHoP6wUFAF4@Sl+wO>M>o+2KYG6Kq&O&n54gfB zU8G(#(0;N;OZrJadOFB#CH(`R_LGlz6Fvl*7-g$jvxw+JD($ORP7*$dDGtTfL?5Cd zHxbE#2EvCj%E?&;(T7=j#yJs3_~1?Tp=dFlk_IQOOe!bx>TV=_@S%B;Z%uGeP(J7e zi9V=7qY%kx8%sWHbg<;ZE4`L{7*bjC;Tcy;KD^nsfDcX!_#n6BL!L9qiyq2{hXXD7 zkTzW*s<$V7H6l3!IQYU|l(k!5O4>3e zRDi=I>_v@aO9~))xs>AIS3yoF*iR0?UU<&s>$cqEa=ka@gKKzYb**uXtA-e|AO?>| z0()(L;{Ir$c~REFFZ6DYkqVrt;g}mqthQ2TtkQgmn-D)~q^Ul;g3M)~*Bm zbCHw}Az{)ekKF2hby4xCUvpEX)Vd+Z-oqH%AR9FCf$8MdsM}_?wC*|ULh~Xvt;k8=`B6UbJwx<;J!9I?xX|gUv1wtbE+FAMP!odEv%y55&w80w-%AH(%ep$>YYSBOY5y^CHGJaGD=p zoe-T;5jfPi$R^l1I|>Lig;7{jI z{(khM?KkYbg2O$E#7C9NXP(QZI0&W!#r9Ecxr%D7-PlY7N0V!uESPTV4;-tTar0R%S#uM)mf1MmJa~oIEq7Dd<1AfJQa! z+I#nw<0bbmg&0t2-MzZwjQR2MgkX=jYA+thnXE?H;W~@w?tI{6=?ls6>5n+=x1sf- zTWOn9(pYOKl0&HxIc|99FJBzGlylU?$ImTrj-Q%GK zeR)K+?VL@1REbQcvI{kax>x0*57Q5vJaTSX{H>4Gyqrwyg@0yRWKCwTk0P>oDk5A{ zm+$GM@?g1H=)`m9HHIv6p9_;_j>Ku)eB4JNH{BtIp}-9hA@c60MyXEbHF8HvH8zGt z%K9a>s`~26MT2FI%AjTa1H*ci%d#G(lY4}m-X)-u=s%#+a+d^``VLz!Vmi5PaJVqT zfx7|wYRoKUgUZT>J66bW*xCPRa`A`Dm&+**bJ>rq{_gh=Pv7vtvzuRiMQq3P!T#gD ztABcUULVBSe#&si(NRa+9uIB1Av2&)ZqLaXzM>C}PrrKcAv1l@lou%ry4^B$#XMeB zxs$z>ZC;{U>%(Py2zyMaNqx}y9qi?>;>6@xr6#4<;2s<<&(U9KEZMnLQa$9#Vc(GmVbmz;9}owuy!o_VxB(|KHATK( zkCVJGKQ;4VFIwPN)cOx`)U=OMQGFoQUn%HJ$g+Knr02Aw=Dw_QI1d>Dbfz|OqT zLn$WJ-$DK`_Vy41hsJ=NdGCy;=Z^aMGY<0xi=bvzLk#v}B}YN~sOu>XXv#QFtrCYoSAG#qgx*>)a zA%;P~K?5;3i#WbPexzR934D-&M*Ttcp%Ze`Fjta)UPbca0N}7+M|wHzK-?h)iQW8Z zaUJlX1Y*d87?6{2#*rQF>M$^OQ3#wgLJZhH;IH`l`188A%bXqJd@VgOIn_yTz<~=f zJT*sFm;*kvKn(em4@)41#zK#>I%^U`D)8Y(h~W*00drFiF-#g`(%EV8d72k9GzK{1 zxaqv)O41E-{X~%6wZKWNo46NnQXAL=)&K1bwgSQ73(ALb_!WU8B92-?R=Ae-F!{7@ z+CmJ9x|SB#8PZQO9P(-Z5DGYW0}e|)38PliykLy7gBV(erPY4*q@SFnebgY}@GZn( z4>$;mBXfQoC;enU@Zl7AL1Z^=H7@WgI=u8_Q%gu@*#I9{49LjbLRCy4||aeF`!Q3uK;}rOrGX= zeAUQSAUN!zeN-Xf5Fjr1DiRQdxeNH<4>9;a47frO#Lx(5-Z-CmjlvZqR3}9cLondr z;zQ0CCum-f-E?s%!o3i)-7Mm+1wN!M8>*h5`T*zdteZ;t{y~0BVF(VapR9%$VjzZ2 zK4FyB#A>2Z=s!fFKFG*kI0GNL4*hWPgrf8M0KfrbD2Lkz<4|WWo-c3()=w55AB=cp z~LOj*efWWo zd8+vS3T0E6Ls`w7m$th*t1F^gJL)aX9L%sy)uy-VCNjdM?)JG^&Aj{||sc2JEX@|KPUAfj27%-iY2Ht{@W6gp`0*vp%Y5bBi*dlz%VYp&+C9{03DL<)jth zu;H~cPwlPA`e&?ZH*Gc1#xU#9Id4%}3az}MWgoX>5kBAwaXfPFp07Bjn)R(G>_yGg zJReRx`Hw$u;mU3fqkNbS9_br1N~Tlw+HgJK!1}1S2IoF|{419YzOWa_>TX?6Lcnl_ zCuTREH&3?^g;7CXpwg-+4&;7QJaR0V=p^%D3>wRGcj}zwxjTkSa9}=+knRQEU!cO2 zFYsYrSm48K0)%k|cJAJ@z=s)hCb`Lcn8*&I56p+TriauE=EFSKNswed%zF!b7`(^9 z72>Hrys*HBY3d?*!F-t4a)?frP(G+?h)!PdVH%0rGau%u1wKp=kKn+37@iH$YSuqQ z6_I+ue3*lYgb&PzxzIy&lKC*fWke^L4>K1-^nv*>gPE2-j6)B}3+BVDwjz1Ke3-pj zOCM&|%F>6Ki?`&%mra&@xNl|wADk`u@OuqWTIS1Tr4gNEzTET#$qVMo^<-M|;Ym+R zALf=^OFpcxwB!S4z>*KCt(JTk$tHPm#h1$C0W3S6iYsw&R@WXR7*Z^Y28$tvYYGi`m7}%4hSsyP?T!Pho9-a z9^*qmh9w``Yc2VZm1fC@Te2+qaH-Og57$px^5IyDB_EhRI8uGcO0wj`h~AP9%%>eR zsl9_-=5NV|Hxe!RpilBYqmYo<14PmTRBkEkMGa{6GjMk>U-d{{Fr6g7V!n@J^}_Z! zt0w6o1V^RLX8dt7pi z^Puha)j70}3X4pLaCC0&Xje4J-CFYCq*gW@1&n&bXU-7qC4bkO@_}2al?$i20@gpQ zsi|tzwj^E(r}d)Ts;W>eR(df1fwTPF%dfu1*;-BesQe1wvWZsL`eH>(s=c}(%Ef6+ zikZc5Xuf{W?iU{8?5L+WWM@@-Pf;8yc=k(cocxS!Mo8fRmx zuq`!ZH~MnShk5Y#r0!3)HUAJq`7m7T7hIr~>pe<&f`F-no*B8^HNLdC+0MO6VBm>t zs|4=KcAL_26RXD^itx@|1AWx?cLT?6JJn=R;Q?+bQN6MbO5Tvyn;G0M`8!>;sv5i&78)+O{CluQ}4NlDSE zH4P2I=E%5#ps=YijDh*Iza|G41eUp6kN3QYgGYjS}ZS} zK`V704p~5g6zWU+l7Q0V-zhiSjMfH)zPRiJbvSy-_*xO?t)wX4F`RT=PUl&RH zDCu+0m*agFuF%{(=|52-jWGreb#+e9`*JV5{qZ2g zu)#pj-8~~=nVm`UD}MDax11h;y*P{a{-`k4i{#!eGgaB_KI`j~r~c3EAua4+s z2k@a5H0s0$M;42HwX0Yk)tFSQ$7^6_%C&`%M#6ba$jTmP;lDr`{Cro9XXT_dG6)v@-}y=pfGvXKe0Wf zpgtjG+h)<7EHCyAymt561FG}hG%q0jxNaZ6EBf%_tH+LqWwl;xX8I6c?QNj?P-*M1 zw1(dEGJV)}(~G-`YL!nYsXip9i98BZG`XckKC|u>ZA$m4LC0hA$W+FM3-A1GkxZmq z&-y5bC3ZO;YW*TYWQk3QS#bIcKpvWQo{QQd?nfsSjb#sdh_dvR3+09NY?}@f{owLq~2* z_Lx~-+~>n{Z{d{vf-_pULY+$BQ)_n4+GtQ%Cu@pUmr);vXQvJ6fxTdSI4f~}?EE3^ zs&d*t$inI>{9WpM;wlhAo)`t}H z+FPX^8R_xBN#<97^HG=B2zgnJCy!#zBp@5^Frv=A}RolVtH}x zkH+irHm9DJ(Y)x6oa=VT30o?%%je0#Wo7plUktfMetEL{3FZn3?YPBtln{U*vi_q$P@G?aVBErq?X@glXGdSZKmOs8f}=_v3) z$5Hx(({mQifq*CWl#bTTFyO-o)Xjos(nn2G9GYle=z$MSVkO_1`VXiN$jN=QZq9&C zc8Jt;dSSkQkW#Hie{%H#e=-hYU_LGSlTTj7pL~_(g%j+Bxj*>`@WI@l>;@dn{mH|? z2kh-}1_KpF3^va6=xjyVD3*I1wLRe z$Nb4`h~aAfWD(U#e~7`{pFBnD1?h^5xLFJQ$x&1};N&jAVKKyz3o)4cllK50%>BuD zz`@*~{D9^KIVCCm`S2^u{Ymtz@r1I3>LmJ;F<0>?f1x^=1TmQVlUsog=Kf?4?1i~M z*$$k9%51EIU%~vz%?td=M2NxMpR~G)KiNxh=ms3j{mES5Lm0$x9DW6AR155dxj)%J z^P&P`VE$zM0)H|S^1|Go+<6s$@(ZdD{eXkHKY5nw1M?^QAcm{?lUaZR_E8CdgSkI> z3#}K-pX`IZF!v{OXuX(%yujIJ^d}AAPnJ=CG79*BUJ$#-83!DCJ(Ysp0>&t!QSVV4 zTp@<>0*>kw%;aF*ycJnJF@H)LguTdsnO?3xshhE&4=HB)Pz5mr7!>kYHDeUX3m(LP zeN-CkMJmLwpU#nPrn%V&d4cDPa=@WS+e&v+Bz_lS_!45s2OO|=gH|U_mD$+K>HS44 z%}p`I;RxVR12cOXJ;@95E3}*zzyW{7y%56;#PE|1Id{KK=c9<)>&JFN4B>PyaD^MF zKIB0R=!u~|+zI+nq#}6{19^cx%o4x>kvs>#B8>KOc-|ZaK12hOI6sN{05e)nM?vi$ zp!1XDbfB6(1vuae2LK1x>K4tXdcue85JSB``xRxwKSK;w3FOR+b@N8553>-1J*)sT zTJ2tA(ki0%x~^o1Ap~N;`3LOnVP39e7LY6%BaG^Yz3>E17Mi*sTg___Ln_=~9H#dd z#694Yo})PY2*09o(xJeW&fA}c7{VZiT~r^gff#B=Rs2m8xSNRvCGcSl#NbHv;cbYa zVybsil1KP}`j7=NpiUyA)&LI8JoV@rG2z2$*o)=B$!fp>8TA(YigCVr*qz>QUZnj4 z+09_lJAlK?mD>kt^<{_wk!*q(@azwBgG1~5wOkRszc2tFu&32P47eBfLkzuU_nVdQ zD;!}3yx&AV!2MVoV!Nyx8e8h{K)E4T)T@VAi zOTrai0Zy(wHB{XOF|2?XaBgr%3I7VCR>H49jgmkNI7bSThwX3ssp;*ct%e7DaEBPM zb|aE7d6@Ssbb~57H|R$5qSTb#^71wCD|(@~AEo+0euY|yIN%D8Knx8=g}j#DZ?d|H zI3TNEgBUnAT=CmfA6}#SFhp^924d*Zb{icE2_MQ~j`S6XVI$p(^?>BHWi~cyst>OK zA25c;s6KoQG4!VE+7{|V58cgm5CiJNd-RU=PT&LPW~(W?^<&S%uLz%r$mVGYA3mme zaVx}t{loq6E9`}G)kQVo!w%rXK^g<@pYu8D9GSJ(}F*a5kTwHwd=pbv`C5gw0A z?>FBAKA86pZvqYq&A;An_M5W1Z1`J<0s9BWs8hg)ix7h=#DF~v>cgtB^eU&NBnG_4 z!QNg;_2Es3!3Z9Rgz5wN6-vQkst<1g4myZoH{7w}3a5e95x~hF5z(kifJ467{U++e zd+(*a>Qo~L0OOO|MmxMULOmA>5 zw|J7ctSv3rKV(7-Si5lrxZjja0Fu>I9~cf9rtA(D9f26q00&a_q}B4~M8igiA)4ZV z`VipX#bw!zb#pQB0q?U=A7HMy_#_~yr{@duD`K+mp!#q##4yZJ((HDSTc?UgP@~wL z8r*NTt)1q1R?+iCB=DgbaF~M_kPm-{U(xAZ&KafW3#KrrleiZvAO^ljHCILNHy@{Y z!5H-g>I2kncFy{`w)dl3-?Kf1y*;kbJvTQRF;g*x)gR}?4EY4f0@H3{4DF_OD9>1v zdV!o|G2jZCc!EP3WshQ+dUo9N)Uq70x*C`j~zN*AHTtRi%om zng6h=bn?V;m@AH?ILyWM56(_UfYOrrsIT@rrN@nk?vzm+bo%t^a?!+_zd>#;f!%BX z91a7cJb({15W^0@Aqn=P74iaevle~@5AxzX;2?t-3Me0#|L~7Y-}_eVus+%je8759 zTGOtG?}NL=q=EC_-*Mfm@2owy@8~;!&&sLHPU`MTbm{9Doo?$H?5iEk5RP`W=BlOI z+M%q9B_lyOF;$+fjaFW^_PyO>Q3J;8bDwN_=l^go)f6jgK=a(-&{NY zU5R0)t9@=ZGrFgCHnkzy*czTP9N{_i$8X<$c=p&!Hy_#m^5+9ZExqmW%hH+$jX5Kd z+{MOVp|ZL&w7F)Y^1{vk+`jz8iCee*w)V~kpV;=>(Q|$Y!84uGj#_uE|DwVGsj+Ht zOQW;E+a)v75Yy2&)E^-j%!OOprOH%YTzx~Yb+#;2qL1s-jWzU6h4)pA1^Cbv8q~dx z{504Le5XcO%_+S*jOfF`2$ESpx)Y5$JxUcuLi)+zR+5_;Dw0`BI%mFWm@ta*A#`0< znmHe2y6GSeaFWeO4elAxFRE@il0st;LJD* zhxzMKFi+g)enV)M8Na{^X=OY)lV6O`ZGx;m5a%ixK$Pp z7mP;X83*tER}Q_fDR;zSAG_Df3(8Fih@SUhz7BrwHQ}&&1H0EV)X3{_nU=*vhwzun}X4-*t zd$_ptSZjsB**TtK*G0DS#qJehHDd+h59v!WG^V4rU*^{xsx-P+^4J-ffSe_hhx`)3yIDmMKJ2f1OcESlYC8K)W?9NeI<|Iu(b6@Y2VXTzk7J?zBEv+c@49ttfL87ifF0^ihJc>xK(jlfJN`ebmf^ z*iTTiEUw8Y%P(+R+)y=OUz(L?6A<5H&qIY_zWuMcasIRZ+EpsrN69kkR6Niq#)th` zF%uHF$H}97807QpS`F$(hQoh!ulM>BFS0&r@QH6ex%6|+fpl7V^Q_9%YI=|37`rU8 zpek603d8tN^g(CN(m$4*_oaMTTppj;BXZRz#%yl5_R zaLpgeF!^#gCl;0&V_(-)w3_Lp*nKK&R6CEuSmUs*`F&PPK&_JR@9B(lLB*ie@xX_l z;l18rst@Q_qh~%t`$=~1Pgp(wR&K8|(T7rq0bl&F^CnTbL_?F2=z|Yv6uue6{(&eA z(MhZqjSvIgZ+;4I2CXW{3OE;pF=W#I0pCuto)%YNuMU;9^YsE}n~B=bpD(btM?RpV zh3^)b55r<$d7%ipWf|1&^%9yF$5uZouI=c=@=kk?178Q$s(Bz4vEx zAf)QezZtwKWxihE+28V43{J8+^8&yDUmarqKsqsk1Dm%`efCs>4BjP`Qye7Ik_iFF zqlVpY>PGBB-^vKRET(<6e?pP0n%-}Q#-?7Gmva%gMC{K@{?3D{y&y9^tb)Ef@bl(f z$&1Hte{&Qn?`Op{FM3_XEr5F!%L_L_7TQ7H}xZ>5(T~AR4DxN99)BCxECxh z28QiFSvIHMn9K6QwOp;BdEpt-9j&a0oNn-%&kO5=>%^0Os`G3v$fqC`W(->ltX`0+ zNA?0|Fn|wfZ>5Nb*?AM^?eT6AbrO+;b9c}y;G(=l=ZZ-e#20U*IQ#?jAyXci@C%(Q zUJ0BWF?(zODd5n~*N=T)N%{x8&%&C;^5P)GFk!Tp-<3o92b=@J9_9;(p%`L#2x6$2 zREfRD2_JR=4tVFjin97=$cu{6f$@`ObHyudN$o~HJO#f(Yxbtt6F8}d7-SH`U-|Z8 zh{4>qZ@G$Z&*mRq0UXe`-$>8?cP@vHW0&UhygWf7xWK~ z-1&322kjrMX$*MoUO&zCWcq;TZme18nd4qSZU#IGYQLRtsSh7P45%cir!mn_q zckY-M<@CM+38g(E13iErtVcJi^7mTjl>%G0;Uat>gKz+bpf$t9PxyrpB`cbIW z+W`mjd%cD44vs<$SG(6MpuXH*z`^`pZ#C6PRxiGS81UTz;cs7!9Gn9M>j(FfH<(+#G3Uu;7|)OTsJ{7OA9!_y}v02 zJfW;5`p|NNFX7})KoWaecJKc%#E=A@`9k0R4pVk>{Vqcc=-V%*zT6+cNvz#-R3Gk# z7&_^jAml?g@F5yvVCPNv=0M0QQ2XC_OkqfFK1Ff3064(Cp1|3YWR?i{un08DjpFbC z;85!kA}R$=;tC7(;UlUK_4HmZlja5E!}F*QaIeSwhwryVTzBzZ{TX)7^0MK^g$Iw9 zZU7wcEezJpA0UQQh#?nZVDHqP3lHi4@Z$SxhG|~ZH2XCejWDtAQ+@0H*B-m{%Hyl< zKJ)7N-#>o*hKVETaHMZwIvX~Dd`L}TecsC_K`hu$($FIXS-eL2Ys zHebE7igcvRk1Fc4^dIuwEd7UjLoNNNxmZj8Au7Pqe~9u~;6GRqePDjn@l;Z?m>>0F zKIzPvA9Y7PIbSe8>db<9dr>s$ADADtMrFwdwb+sm5qS&v&}YeqXc^H5cFxMqv*d$! zj3plqxmfaH%>q6=WU%Ce(9@C+H#%7I;h&|Je0YUc9Om11s>$hqy}t+yAoYUf#ohjv ze0a{ok`Jd;mV8i`TJk|*lVkdB68f}=Bs*VJd{wK-Sl_$Snbu8yT2XNeJzvCR1c(+X z1LBM8UEIB0G71Wz>M@_z{_nHPV%L_uXh-X2Q*lvADSgjd+~~y<*fgdEPg{#*VbP{H zAnbhcYuvL_TOIHH180+vQ3kyttg*?dtw&haTwN`^GB0;rA8Ii#H!_i)m1-=>Xa2+e zIj$D-a()gC+y)2FEAw*pAAb1Wx0?&z(3rX)=qHn>2Lk9EsV0w8;AmH{)Eo!r|5@|q zlNaotwxc+R6N(CIDGuq8S#Ex%*_ptoZstEIKI}+JJU6zgfYytqfVyh2b-vbR5y=Zy zFD|d`wtMef>W99x0||?X5A>toe+V42vkA7X4%8M51UI%scty%etsB(7OLE-3OUQ1{ z>*Vg!e93Ds89uk8b+gb)S-|{<5U-GaWpzS_sAytR8WJ3vRVl2}__rur+!T?7)uflh zcS(h^N1X*y^#?UjH<3}HdYONEi@VG)vczk!qb}Xb%}r2aOdmHy1rK8k%#ZrNefQwO zO1CL<-@dL~Q(OT31H+-}@P(uvBEUd{uQ zwgvd`8ho?pcr?)m{2mB;q<{6@Mf^St`VZ)V;2kUW)$FTBxB{O2|LVI*_{E{>CG$Fo zD|l3V>I{AL8K*@=A3jK)*Gc?t(u>c1(f)DH2`sIhi zh(2I1hyJA8<>ofX%~kAucUMAlGp@k=sD}=C{AfN`96s%qTo{&mWv+PRx7Ri7s2lvL znCgR@e_L>VuhF)5mgpp&H_?w0d;c7G@6KoUG}DeWE45ZsJZtaani(x=OYG?r(Q_7? zw?FvPOD`&dJdfK$ABB5S)RV!jni~sDor(}=!d~E65B;0H}?f8+gJMU%RkCInbEauU9`*tU#SUwyym7H$l97eyR#qP8AUH7NM?8PNd zdeVL}ue4AWsh&vVd#UR*HuLlL*IoPRH{w6HeLDqvftl4i5n>1}aOnx>iEOmtg?+Vl zy&cv`!?82EDV@Bbw%ggWFUKK;`0b>ScNZDjM4nIWZddVRC3)GIM~HjelY$cOvxIUTuT z=Wky(Qa&VP$h~C^)sD_Cy`eop{e9Zta`@b8te@PP zWe=x=m|g7tB0iPyfz1`uGw)Lc^n7svV!*j#89iU%_XhEcWJ;=&55Zmpip$~E0O=n{ z7es0|dc|uG45XkQFN1^I%qwkuT|G>^!+kw^KKlpB%BP*N) z90YVm3-#d(;6oPp5Br6rug3EQ&Nj36Sx=hI7v+L=Jkmd)UyVKOwGab(q;EkCRWfeL z1f49xnLV5_9fdZpJ|j`^0309MEd~rWxz2 zzlPmRNgnM=r*nhoPtHLM$7ybEf*5R+o^+~5DG-{}p3EL#4Dfw9$@hksEYb~fN=rZ= z@NE=&gSZzkH>i3PRPJm!(MeV}pQd^7I{XTl6Vr#Jkrg%pAFziJQ9ir?ICOzGI8En* z7!G{Ohf@#(%ni1TO_O@@1Ff43hYuhIDa;Kv(C;4DnpBR=CKW*pw*ntp$EBL5==Vr* zF6fuCdB^)E_!ZGG7gR^T%es>4B&m9~n(JXNmcZN~QF}6zg9_tLbrSpscbH8oKDgjJ zy(ehhd<|k4olx`dq#npEzz4f4U$H3X+yFRqk1o9> z{LjGy!4-BwUZ7T^P9i5SLkuq9PcGC4_D=0Rst>JnZtxQIVNfSWVTC(TAJTOltEfKU zy93P43#ROjOnDz-Xe{(o+(y5Pf^&nYw8tn87a@ktvoTk`qKW$O(*k`c1~+M;KA=t_ zlFvd6s1I7I4^IFeNW~%bVn5(u2m0Vg^#ML}BzT$PAcqyM1suk!T4;868hwEeDX;=N zXTkl&)GsEbC4JORnis9`E6^jwxxu?(uJ{hK*=AH)oL$74wE}Pu!u>@#og2iNJfhym{}7Ecn5dWGr(Q~Mtw24|S*W&Oj+ z$<(LJ{U~|9!6=zk`d?BJg~9%TRDZI<#X^!7%&!Jko4z2y`s&)^YT5ys!T8 z_1fZ)Bk6yzdJ(G?Sv96eqw)+6>pOirjVAyHAHV@?);q8lqmY|!5W{xBAsui)pBA+m z`2g?KxIY3X)vy=-kQdtS_P92{!Oo16esKf`Z7lf}_t5W|-)Xv)gYQqOh(55s`flI5 z9``Hayu*B$>?vb@Q$Bpw1Y*GVyqA;Ce^emg-ot#Dy2KF)&Mva|db?%UKASqN*votv z@#NBgnUeXwdVAv0dm5~`8`vC(OdsDj9k%;tjpr>0|DBrpfk z>9O~)V*Y&=&&~F}C*k|m>|U?jq;l}>XsVN2nn_+I z^oR9SA57mxS>pQH#n-Mmd-BaK}#*p{GwxBfEjHliFNI%KG(_0BRz+KY1BQ`OuJu8Pc{x(bWVP=}(zyTca zyt!?Qr=$4CtbhL9Ky;GjMMT%4_aFOW^w2b|oBSlvKtyYrUeqz47bZTWoxb)%>+luR zR3D;7hWu~>b7?czDkHYouUWD7tqb>@eM^8doH}C505l7zmWfJ(dX>D%?UY!#fj)wr${fI zy>;)6-)(sH=C6(&WHER~N=9*?t*1WvNN*miSpbgDMztRvM)ZAO{LVw;Y**}75w^mt+fo|5W-5A6MB z=`erG@cAXzms6dz_Gw^KpyyWX+!zwvJty|9 z&-RwqaIt@2e$+L|U+p?{-gcigt(#I!su*JEkBX80w))yFTOJsX;*U>G%t#F(o&jgh z?ES~*ZyT!wc}qma*Y5u3met27lDV;6k=9CHPk1q%hRrIolOFq^>u!d_*7I_^{Ofa0 z4pSWRmiSmZ333A4;`jr;*YAIwoj3bpd^&Frf8@DR$P1IwN|lq!=}6vKXJ>>2a+B%9 z{lAR7v)wiOjDh0Np3%*|S+x1V)fdh`a_Y-(&z^qhY6FiKd}3YmMBZV`n-tf1Ivs33+5-ICsAR_hS~h&3LWVm*!<+Z zVxkZ1oV7KL^pouV;+Q+p2R1*6XFXiO9cnk8ahU&bt}j`XwA|~i2+(R=Avj1H?n(Vg zvAiljC8;_*-d2|ssjErPlh5C0{nFYpk^G(Ul#upOG15+3JLbcL*NRHCi;D9G)7q7y zwHn{1T@NrHCR?ydE_nIz4@9(o$Wu0ot+mc7>!y@c>?fK3aCUNLAUFB0kJvl+8!m3W zf5j8$zF+^#pMRV^z5VNFb`U>``IG<6+#uq>>cxLEH;9a4b@M-+8@x$2%-dqHx!hse zO_&=DuGh?X=1+v?>ci{mRb%7PVG%_Ukv_w-1KOm?47G8DYh@E38=)~YE1Kvz3%~#H ze$>k=zwiHHYZ284Lsw+Ph)-`<+xV#5qo{m(+A~lWpBptS5$gwqiyYe%l8Vb!<#uj_ z)${Y!|BY`ykvYp{zJ1M)i=8@Oi@ReSIEgsSPL_rg)48DHDytd~$CT<2VeiajTnhKx zL+TBzf7rM9<3+c2uYbs&_AtKH>BY|JK@GE!vWvps9-O!UZB##_wA!L!Y%F3)VF6V;2a2^vvPrx?uMB3jdTVB&lihLojJiF z7_?dnf1BoY`fgD{>n8aXYT-D@x8=(^;l%n8^&g1JkvS05hgtX)F#j-qhW>pVoR7kO@*u4jE$}NU;q2c=-z8xT zz7T^e#DH486k;eav6|=u_Vxm*52!FO|Df;!Bp0495C>Ek{01hTFJ7l_C()OyG${;0 zk_W${ZB#AXLFXR=pk}eXz!mTtn6_7@7ernyv|b2l4Cp_=H|{L_hjyA5h$OyCIs!=E zIBf3h&3~5_zh4dh18)<=fG1XWP`N>~7@Q!6R(MskfxcUGw>TXr1yb0HW|(fWrSnli TR44IQp!5GW#83x+yXyY{ub*b7 literal 0 HcmV?d00001 diff --git a/crmeb/basic/BaseManager.php b/crmeb/basic/BaseManager.php new file mode 100644 index 0000000000000000000000000000000000000000..7da06fcf77d20f6c396d633d421ccefb4e534b79 GIT binary patch literal 46408 zcmeFacX*W5);6Br%cRd_W-=jl(t9JlCo_{w`lL*H?>(6$lSBp7qlkzoQWOg+ibp_1 zMXcBX#e#BF6jW>n6)P%&erwI%J2TI`a6F#({axSp`>yX#xL{xFS^Hl1TI=3x?@7xX z=^63u)J${^jrR@@H4hB8c64?~gU6?bhX*>zAIE}2e22$;J9;~%!Iiqd_f_CO8^izS zJ2X7u+dDKq(K;~D*%9m;>04G*)|{_YgrsI>@UyBbgX+r1`+UvZLObOCZf+hv-roHw z)02V0n#g>qrfAt>LWX~!rf7Cf=-m+06JyC2Ie0oa$!C3MW|cg-Qtss~>Jzydtl;V` z@K)Ovmbe$lB+K|>jZ2ATLzYYNC||Om=_#wVNeqn`4vO#Bh&;T7|Nmb>=3Y@VV%sp& zH(r$!8B;ngaOKHeC3e;M!d#CM?@^h{bQaIrzOX3wW{I~{+E!oN&@vaY+`prB#wX9k zN1!Mc2y(@OG==ruVawI9!U-QAL7%8NsMXKXMcPsq?3U}w7b?{jSv*OBLKGm7jkx8g z)I6SeM&!MqiL)%Xi;+h4PsGZlA}@ZaQe5IHk=VfsH{9H=TR{*=R!IA?=TX~~f3-qC zT|ogW5F2m>n*y?eH`oy2qPHQB+HlWNy$u&%LE6G>F#HNv_zG+I3Jds(SI<586Zs1L z3SI^_7_N{FerNzc)Po=Hz3a@G#wp^5GVntr_@VuxUmLj>3`czMi^lT*2;8g;wb?ibpb&r7W72%n!= z;AQqlv`mGD49(3(N!r8O2Pej&#N&f*rOh4E!CLDaCo8dS@$kZ2tD`n^x?*8O<2aLQ z<0hK~JY3oahKEXuhu?w;9@uUc!B;ezhqj0)9v*mri>Q{56F#)-T+pB&f&ft+vHjBX zUwppX*^#W!3YhExKO|qmh8n{lG zRL8+y*aIHEIrH(ATvYc<-F2vDUqSW)S9rgK>}HX>9+MY~3q7I?Q7vuR?f36S)}>Z3 z{EGj~23#RFgG9F#_@S6D8>u`^zQPCMBG#h3_7z8r?tZD-1EX8-2f`16z#BV>A8v=Z zD2BKwg1B&lz3A*9p4{g|BFp}G{4S>${R%OrTz+T*hQYm9pGg=-lSB~Z=1&+#1~x3h zUR;$*Y$yXf;0h;4|9gJ020RD@T}-{Bh##8s{xwG(1sh7h4`Sd4HP{g5N)Yv20r7*) zr%4~xx9fTGgHkS{dH|CG@T4}7;Ne#n;)fJ-f`65JcNG~{bgO7 z9uIr^xsjC%cqjop*rgDT`XHM4VKkiJ;VbaNSQ>29IVgPhN^)T$~6V_CQ=*fVgTNumM-tV`G^0{{6jROe+LT@&p3M z!wn=~bO^b7!Sd$wgTxOTzy=Y-W-r91AJ|ZvL_FDFK>V=nl*3bMXMGLx4WC;-V7|Z_ z=A8npg4+F7jS@dFp1cR*;s=Nep&#MNP+A4;?jnBRW29SPhxDkK_&KM5AnkjG&Wr!HlxvoHiGK#Wa5Xdr#kl9w&?4q5l5~KrGN)HaP@|0 zQp+WJ5I;DV5InpHes~)E@Zu!#L%41?-E#eANL*YB4}XSg#H66K$;xJdtY9~$-wR|I zR!0d7^q!Q^+>KoAA}9PHawdM*@=4n<%XEF_J=A}x=;rQ4YA?aVBjATe!4D^5i60ih z23+Bo6^#q<12?k%y|{>j8fGf4w@W251YV-a)?a{#AX`W zFh)F?8$kT<)t5<+*>sV;Ks=;u-~nsewQC8>`L85?sB$NGC>AMPmqTs;{TAW} zAFu&esPrX%_}5uazZcxEfY<~~HU;KXT=gbdp)yOq7wAdgsQyXF-OsNeemDZLIRuf_ z4YAn*HeCBM;fFFY@xy`Dsh?*1>-&q3wsH}LwH)GM-$NvC?%PHDp!Fkou!S0?K3Apo zT}Axhq}$D?e#I{0hyQFhAvU23>XrIbmwicAXcFr80zHYb*$BCN_#@&6bFjf3ViW5q z2e6^;QNjOvKJyZiDZ%web(i~ z55BtH6eqB$j)RoZPqPllMQ{d;M2WZiim) z<10V;^zy3?L$~*GCNpFD|i@yNSdKFD_?eh>j3aE0u%C$Fu! zY5BJC5)v0;z{4cqVfdC6=dGR+p0|g*iHOn;j%#hQ!U}ovt`eDPU)F-3c19Z-X@UKw z9dJ~Y$p=nHV%~fXdmQv+tVUf@lH^&*&t8<*N2O^@$43`tw0xZn=f2^7g%{*3{0af= z1@7jhzv83MZu;brcROJ(xGS98rvw{}{ZI>gVd#exL-Iy<4G@aX-2F^Vn}+{6X_YSw7(h z9>s%6PxD<596P)^cACURl#KX6413`MHr!hWL}4}Z`m*~;Tv$+kZ~>ki1RI{eT7KQG zx+^}-eVfDu!$Z!_-A9hKjlJ$k@!(WlQJBp)$?}o+=nxe?akVbvU`>npVl2RhSm?$W2AoYq4mRUCL}J*VK2~=@0k)m2p~4m zljgM~F1&ToU2Z4HBzW+q{7`5^{D85ED>T#*KNJ8z;0k_y#1BG>hj)3z4};VX4_gvH zC@CJ6r4u~VQ#`CU=i=cli4h*GjPNkW#Y6b)9$jUQISW1M({6-^Y9l<@aq+O|`@XJI z!x{!x_|cS$2Mc>H9>OxXc<`ONTGzQ_O^Yi`c5?CXNj$-WjN;+DBCuVK+ZF(gqO^Lh1+d6=W|E zQDVS@Enu?Zw6jz0t6}$RC?4|73KUs!l0YwcUZ}7lUggnd>X4SwGc)8ktV0ym)x8iG zLB}0UVzx%yprU?|bSF(U4fbc3E)+%O*VvnydsZ|}_{UGG22*sNM2@P572b_MH}GEc z`89KtAB5$?yr!D6Bp12u;<7;-mk_{YHN@t?_y=(zg$e&Gqkgb44_c=6oarf6)OH28 zTb1zbvhoC?$j<4R*(vk`)^g6^hgDHeilE1N&Xe+kHbgpuen33bfDNzQdt~(I9qN67 zlphv5C&MDLBgY4(=JTcV%X9ryqceyotg9PgFRIUee5~Ywko%h`9v19J7exW(9e(W< z6D4-mD!ay>MMM<#dbMD~kFVd-(lPtx)#j8RQW8Tur=)(vo@0@2+Q?REXIGfVY>!xO z7ESg7Yub9)i>7hU)o#naKRQc!Qf)IL*GML2G?B@zBK62J65XVhYk;^=uIb&}82`bi znUp67f`Z0_OJ^45HBK`gGKYMEYEn;n1ERj|j&k!5$iDTYc*rV`_iF`?!n!&ZZ1^E@ zE_*?&Sm#Z7GP74HpEdBqsh4klKKnxDO^wtKQB}XL{qWW;D<0kQ$l>)LY+3uvkv)(6 z{@&RoKipxP@SUmTx?9tzAEW~z3lrWU9fjKE7PAp4Cbb>Cwxx@XHtK%A;fXSZlSP49 z;TZU#6fju_Hu#-C`|H4+Ki=sGHXy?c2PgD}DP}XGW~v7LCG$R+(vFs4(Qu!OXI4x6 zSVc**MBHcz9EF;g9qfhe2anzS#mz%ExKN(VsZ{znY0P7a#9kxag@q9+Rh_KzTkNdkXPV~wGu$<*8c`!MEz6rekEM2n?6+Hs8VE9sYyI5t zRA7)7s|Fb!!k^rr6u$HRY6t3veQQqswCkDsues~OcQ5{S^8Eg%cmMYF-LL}c57V$0 zGs!QNiS8MGwSeY}jEU4@_uTIJ66y!!2P@!*) zuglD5xxTWqy#&n+?>}D4pB_ro8*ci^Ud|>b$w|^yG$R19ODs6s|t7 z7vX@(ckd2wdt_zRRjD*@x;My#J}uqJ;;^E~l;m0m)u2VuJd4fr8SS!gr@W-bqEf>4 zeIl$Ma>0fn!Mce#Wy~j8G+&gC=a1w$x(%6omWDPIB}GR``08nqSRk})%0(L(9#*A? zhE(`j-Vj0kP-x-V!d6azeLae&h7=2ahJJ&B0& zPq^^x(T_j4@!ZE3&h5TI&kyz=KJfjzy?TC7s1*`%t8-jYUjAfAPTpK_l6{pSKd6qr zdiZMtekh48l80N21Xz{#{k@Osg#YN#KpKV_rSGB^P`oSUBJzKuq zIek3GMI^VI;#W&Z-ehsHxUDEc>B4`ln8rnHQ`B_kl->`Gxi4uTHeY0UGbMd~5?4SS z#tU-RccBSiHspw&x2JVfsXC*CU+-&PAsctd9*i|nINRwmFPXE{*H#XgL|v{5dp*Zz{LRLL?+XDNumUO1 zDhpOrrB;pQ@?@RB4=i8Ak8VFzBJkPB>T0?3bna|`D_<=m^#jHQu3%01Aq#A9v5WTY z86x$hH_cfKy02*WO9dP10$t^#8YDFguHXVTVD5%q&-!!Aa(kwtC?GavuouV==!Y#I zoQpgLU-5GucZGjaJT!tIax`(KPt$XpL*NIE!P$W=@I#1)wB-mrDGmpIz?v5ID4id` z25Z+v%^F9NH^(6^5R-p^4S2>H0yb#;E!+xPNxs+tyD5Xc_=@_$9sFQ5C+2U^l6vxb z;K|crjO8Q}Jl||H=>211FH~TIE7*W%tkAjpi+CaptD{ju;)i^S2PgQ7ez4)t99dx*U=njTtE+7xXIZ-Ri#+^EWZ3{7{J@6uU<1RXDpyrY zs=)<~J?$^LsSThW3~D7lpyZHxQUjQ@1g>WFBq6xlY#8o2n zgeeGIVK2pG4y~i=zz=G%Y$T$P)YZ%n$>0Y>6xJ}~;D=g1!NYU3o+RA?$yq9XfWT>* z)YVLXcmw<}1S|Lh9?X?WkJ~*-e~|(e4{5$=0~=IQk=t1r=`WrFJcI-@mUGK(1{+39 z^l_03ap3?qn9E++jZ`w9`Q zCo91QXTaoC6v4w2G%m<)76*lcAL2R$fiGl}xOg4nq90-t=N}MJO7KJH2s?$Dh!s+v z>;OMtZ4a7QquNEme&}#r&>S<<_c-XuGvEibAqD)<>}TomEZBf6 z><51ErLl>7VF5NI&WpTnr~0H4_97K*u+v4iL?QzlDkA&+-lDo3#>F()-~e%fo-BZ` zu;;T=xpKQ=8W+)E1J*FW4_(_u#lZ=bA987If>N(r!4+(Xs^al}T`)xTL@e?oqS_t4 z!cWl0zuk{uavyxf7>!L_K?^n{gC_QxD~XG{U@wrPS|KiQ1y8WS!pl?e1f2sxenT<|YXam_zq0$^|umBrgkdVmw>b|TQDcEo$_+c%4MHupfmq2y}*noIANMjTIfOyCQ zKP1Bp#-;dSg!0382K?|huz|6C3F5(kA9jErwynsW2>}}r)yNOu#P)}{xDt-K9&A8Q zz6C3UgAL99N?h^F!?0)1MWq9?_@ODO{G`_Ux6IObUDySwY_|SvdvV_ zQ5ac{lqV~}21oG2KVrxV*L&6791J#0fDJpq1{v631NyagZks^Y%7v&6rpFsVqR=t7ZKA%kx1=3BDOAQ&9maS*s-I8zp@+r=VS69JYv6|guptfn@F=Wc0e3$Mz}?pthd?=Krkn(s@< z*9NpiXATUgt2D_j3vB_?wwZCCmN^Hz3T;Gtv)WndU1?R4_WSNX?%#0g=j+$~`qX=# zy;iwqfvGmWy?L#Ei^;R;k)0{gse%4uIU^Be=U#em|KFeTs!LnmR4WK&EH?nr?P#zU zU($J)cg+Y-KH*RC5JTc3I+^eTtE=CAXyY%X26c7H#JpEEPhVH>J@VjDS5L`{OrNxf z4_Fo^)7RCPoxbwplt|GArcaiPHbpGDlGtp9$hz~EFSk0GWvylUWL9YVU{IjG@4jsN z2m4`)ay!!}71ND8HiBwsMSTAj$%CyyHG)oebBr$e>c;xQw=I=gdaQ@k4@|GVBbbYafix~2itUZ? zV8+FRJdEIhonL$&NAd;hv%W1Q`GTEaJRHl#!<99pu4d;K$*o*GRA+GUu(g+qhldlm zcsQI)@&!A;*z8C$4m-bS@g?;GJHHUW8~0?7HJN`vPxb*nU~O;unUhV@%QkB(XwFi0 z6nYhR)DGD<3$;Zy>WVr0+6+x_R6={lkS^meen@$7HZ$SH*#lLyj!J73k0m!1L@%c1 z6z4gb)#Npn%EBhQqcVF`x=IXnd((Mi^X+?w zbh#V(;X;ZgYtSNVtvBRu^rX^OY?VW6T0GzU&{olrAKSlOpsRuuuDMlJxydwlW8ZCY z)idiJ|D*iTD#{PusfBKqzLhaDzrv~Xpp04%N#>xT9~$0y^`@uq>)zQ&{ZKqq=$b|S zpyp?1w>ab_AflLF-TmrJr1D6@X)WakhZ3vmf^tO~LA9PI?|6A~`okY9PIb_{Y3`L@ z!gQF-p_%y3#etR{(e%VnutqbN=UQGR)+oCYI!0Ojfam_G)874T=kVhftlvzfd9$cI zEUN1;};@XJXp&*xeo!>1{7Y#K zgZkuVH=E!HFaB%T`(tD!s?4=9zzY+BaIjAI6+B)^T9G_TuSbn0WIE~)#q_8R-G09& z%t`my>8e4Y(jnVDyHu}7NlL99IC0@@^8MvIU*f-3MEww}j#`WwDq8YGOJvbVZtn2I z1r!hQaSKxuKK0|SV!{t>zItz9;KR?X@qfrhR}HrNRg`HHm33up`MFvCK5|8ILwS>Y zvR|)H?jCi2NXXP_Ak~0}v(3_+Ez05x zX*6$IsT}iWCI*6i$D+H9RW=tb*Efvi{SnVB_}?wp^G8Hed| z`|Jb`tr1f%xYHU&t_-g8=#BPN=FBIs+Me67>h-8bBRxt1dtsQR2+2SYsy`%NKm6w{-$z)^;J)F|u)=By)N1L{#0z)^;J)MoHQ5pYx*#X}14 zq@fusSLY zqT5i9@`SiRJqmR>)T63_A1Be%ZyM=Q z*y|bUQ9J*I9wh}o80t}#fQJRJ0d+a-yW8O_E~ZDt(AwP_SXyjL3)S)jEDyQWqtXcH{@D1>p*h10Ikk6Abua zfhX2v!EH6fqzLlG^I!w|0rjX>upv@h?6)(N8yC+|Kg5F{6l$KkQcL=aHvkWqvrrSm ziZm9!q6=oUrm0@dzM>dxz>2gU{18QJ7+m36upt|4XaE~<1>}bbi8sGmK>7<7oBcFj z!~#!Fjkpyw*OC4L;{s<77AZe;ferDX6`%8Al^9u}jryS#Y~TxI6Z^7Be{pzS)d_E~ z!5?fm1va#S4OM_BA@~7TFy@C0_zL8QD>bCQAYD?NCF=H=c~2uhlqw}oUIbAX7lxih zP0Ru&Nsy~CZyp*_K4^d9_~#ikZ@Q@@{o^wW!P17ng;}t{2W%LE6_x`(bOS$Ffgjqy zhGg(VE9}J#jSH4HL+=Xv>B%c@KN<*rKt#pFWij>O%A5C|J-qU}+YapC_s!YAJ-hwh zb?4u^AZVM`Mn@;rse6PD1=E?K9_m6fYpP(hzzTToKLa+fuXt{P^jW)tNq>R!FfL%j z&R@Sd7`_mjq-Sv`N3Kx z$(o?Kjutar;faira4{*bqN3{h_d#+izL~bNfwgD7W7{1XTd8!1~P|BmE)Y zXkPAG53c@D%qNIqcsT0A)gQjF=IRd$qj@=*9~TeuQ7#^iwHe`Igo}qqf(ag&{%|0O zi-*%%E*=D4Ts#!|a`AAZma9LUQ*!aJJAsP_MFkfRDV$*8&a zbvHOz-puml;^C;8i-$*&xp?@(iHnCpM=l;DpSA1mC9!!qHV>mco}q30#CDstj_nn$ z#Z9u37&;HL7-`$DC^xAY2@M#G>lgs0C3irOAIh$CbX46}{x=!r$@Jc$+}v1)G+}Yx zc(H1>!ZUt!U}&Puwy(TJr)c4=fnt*!aaonfO*wI2Ut zb0B}U-~9h-F6f6lWaXQG>O2rbD-au{M@b3oH|K*SS@jl{VUkD>Vg5kZu+@TJU`FE1 zT%3hOOm>shQP^j#`#ielx_g@+$9a2cZwaxw9xDY(mA)iHPk=kF~0+ zANP$2L>t&#&}#E8A3=-YZcp8Asx3qf)gm7QJbYif=%Liat*WAUNNTSskwMO4eRtEx zySHzIVmj$PswV&O0=act(Txif`Js-hxm3TUa>QQj_ zBfq)6A{+g{bbIsl$?@&CS#6rqRY5V*fz*u2*sju8!gBh#!4HRLA9Xsp`?!SG4>C{F z-dUAnU0I@)Ngl0fQIBGC<}NfYWXeiKe1(&2B4`xqqyrKIk@xyA!o5(P- zJN*4nuQcN2B=Qg`@#NipZ*lN$K_RL>IeIL_kv=Ihg|yxUQWDyT6wSD4~JG- zCSL8)^F;oVAIwHV8p6DM-Hun^zr03Otgz#$l1K%jTY=3_ zwuIXr)F@hiGo^m$j|?1B=7+nC_{XIv#>c#7#|1i1vbn*Ht!r^oeI4GFL#B;cDAMH% z=7$%$Hk1HAY%HdJPzIL6ZjxFK=SX?QHtj-j=9vOrRoo}y&ty)jmxUE&P@R_X!}R_B zw?4E^b=-^cgLo>iGq*&&G!LU{Kj`WB;JrK8{N$|1bop%LbYpvX%0&Fkh?HbK{rqH* z-!+oBvzs<%(t5Hlby;uV;_PhKtn)y+(m}y$Ii|~X1lRTi%a&ik?mm>{`$hF7RQP#X zk$l1CX=k(7egEUzSKc&6tHHRW{+@;5gz1)rk=TJ=l{S+4p@G)bSkvO&2Ub@f0zWJh z^ttORG1j4wz8mgeIM3&(8cEh$(6j?4W1%9&xgc6sN66vCe2tL1!hXsRFFQ< z^L_|>5o4q8ac+RvY=OG^WqL2E6LwP!n8f>8$S^knKV-VdM;?@syeWX)#Iu9T!3NYw z*J52QD&dXN_aE?l(--1m59No$SXcW53h$aAaq%Sd-M`PVu6ZK%bNGrlgSntysO22M z23N2F_X6(147(JRh)LE{sj~nNE|eeeE8sSb*LF}BNBOK%BYt3WgEzxhXu*a}^geGA z#3tSWVdocj03Jqs#a?-G!n7`c>KU-%ZmzGc?ZZT&FX<2X_q@SN8h&Ur}{ zq;SPKkOhbf!@e8mK(=|2x|(Ev9`El|fA|pa0DX62JDmeL4|u@X6wu22X0V}8B>XSu zyaE~*PrzQ_Id5D7!NVEK52OmRbh#Jy!luxb-%RH~>HrUDLooP34K|zsJjm>0e4iU8 zb(9A1@BrKqWBFnO_#rmJEw_Q*YaXWgg6yVv=6djhl=i&1LKWpn8@d9_i49e?2m&rO zCw48^V5rL-0z7DxWG~Q$6W|Bb?P=5Fb@LTjfRS>Kg$M`sn7D9s@sE&>0M@%xl4uO)3RHgYpB+iFHMfxaIcJ zzMFIhWL6CkwF3MAy4(^TR#87BfFF>n;ig;r-vzQ!hKKcl2Lae122A1^E8KL8`9@r_ zgec^PmQIH|(t#gVfDL$8uHPqs{|DtsjEi!>d66HwfgeVU_~B}bsH+G+K1pz^NXbhe1#70X(>ci@eSk z>oJK8gEkVMSlUfXmq);cOqc>Kq;sST5Ep0z^TS7AgNJ=gILUe< zuYUj@6sd`ig+g3>2R7iH!H{5h(}u>y2|%?A*l-uvfH`Xge1+7yY$@a594XFl8tV4r z@RCLZeFuYlMSws>@o)wB0r!thTQw1N%66c6k^&WCUAs~@+|+Br(`(B)7p4UDnLN^y?c@x(pn zzyJQ@cQ*WX;oPq~o_OHQh9cC0(ks*Iodnq(X`!_R4f3)A*V-9z^3ZVlKyozT0riJz zib?e3Csu?ft7=GG411CaBq)}|g=!he7wlZ`{*AXB7W%f|$@=c>k*I~fbp0&ri34}9 z&hZrg%Fg}UvV`@yX8O6HH@ANEO0swHJ?z{+D=a7^d_jM{x$@hO)>+o`*0OVdvo=cs zzfOPNy<*+hM--C2Elh`zl?0Ckh7pd!elu3x^Hy4v{5}&J7ga5RLsg}vKKugb`pMS$ zw58~NqU-X>MsmK1eyFE$!RkpwHQwKR2QUeFQ^(a2fXUZN-x_@-f8u&4hzsP0wh48B zHg_y>VW2rZVJxtXWq)=rY5l9+C(^uM|H>Zt0X-R)9-9Yy5u2Hi@!j)xKDhbSLr?wf znb)3tX3J+kUbS^;vZzLzVc8l!9W&FT5qrX1kXztfAYprUu6JYN^bdx9D3~4bTbK|k zSJQi}Y!2jP16PNcSeJLbU5`F*qW*yW=8VO}@$7upTbLdtXr54s{q%Kpl&I;vxkJo$ zHvdrKD5(@?!QCi2SBz%|c%PS@0&Tt3ZG! z`yK8e(XGoDDF;LW{K-j{aR^T`o%TK0i-1z4Ad=1vrodiQQ?AB*@ipYEhMYXnUV5Jw z^98OjPWj;l*o%EIS8SXwFmIv__tSjgO!EcSQDg-Y7q?+O3HgG>#k1*V-x|h6Nuee( z8s6eqv?qvSIt;5Hc6aLgizQ6LUSK_m^AFX2>phB!)hpRNOt43HXmT>iS;>IO``-?o zh`i5ycN^u&h!#!XxYnX)IrsrH4mP>|&U#^PW#FbTV6}EpZ=}O&7-|rw(f)TgrxmGv zbPgo^P-{ZIg7uqk-|*fpc(3m{rcWv&H4$zR`t$BrH?7{@YF>T~yU(j!3}4hp_4-3> zLC+VnU4pxrJ{iz96&*4ZAPDtbse3_!P2}!wAaTLYH>&`Xh$zMn#nS{)OsDPF`$HjwM!NtQsHmQQxoY->{q@HAP zaajS$I7@S4k%VE`IgWghiwDzDE*{j|hIQ{QvUyrIAGPpZmYDx*$>+nc7r25z%`eDn zZ%j@vbd|*qcr;Is+4pOL`bK+FqjVh#)8)Lkn_9) zs-4TT?KKsCxkC9=XM>JunGW;Q^yjljOgG-d?j01>ghY-hBmuI;;n>9aE?u96_nN=W znD=ZD72ktzFQ6xtHnlm$z}4*j=H2BZC0%OXT0X6#9JA-f<^fSGZ~oOev4Ce+T(hMCvgrZHQVsg6p_7%sFe44r0u7ONkgsSSH+M$!JAC#_*} z8kIhd^jxVLVr{BWpqElph!u+f>xlTPBWzrp% zOkcs$>(zGU3n6#y7p+z4x+EWg`B-M5v%Gbr-g=;DDxz!tQaUZKYv|3kmYCntbZjs3 zDzXOq}T+sN=(_J?%Hc zp^oZ_*!A#jy99T;>vmIZVOCki7Z$ba-ZaDWteUGYsFN*r|2{?ahm3;x$%(MxUjNv^ z*}*BRzHqCE>EcEki+)9CP)qW>Z)AWlVL;fngohu0w`h9s;KDEQ6c4;Cv!}BZ&H;RAg4_*if{*i1rsb z?j&CzPh#d((th)P@Ix6-G|K8plJ!WR#qK4+tlH8|H@ugGcR&yim~o)zomav%tnt01 z)3l!a8Tw7Umvk?kMcD{(F=p^~(^f!rCfrMUk={$H1V6-6EeP|)53m;&UJ}7Es(9m^ zIqt=^U<1y}eGfL2kGf{1P{sQj$QSrt&`#=ydtf(JJRkAT^u3@}5EmP1?~i`C1HQu9 z;H|$jsO?k0hIFt2HFMOX!VL7NILH^+cjNg5dJ^=gnJU=L38Vgkoo5{-{e^fFeP=HO z;=&GWVCUUizy^!b61X@@>T2vaQIFaKHsBe`Ua+ColTU9I`3Nd>-6EL-K^t&ROaOCY zB>R*5yf~|d`UB=oI6H9ULDnQP>~WQ7%g2h82$Cc3-h2~m2nIh`Q@#2i)nQnVvleWK2dy|NiqsGFRDZxeD-UdV5AXnbRN*dqH!2VC z@Bm2aI=Zv z0q^Tof(`6_80h^21L1UX*qKEZ@k18%!)4%y6tE$m-dogy4U1sIHt+-Xdhfwr)Cw2q zt>mbF5v?BvDMx``UH4Bv%cYyJa`=i)umS5R{0ewaEUF9Cq)m$i4=i6?P4%dw;D^be z_8>>f4_5#lP^V@5@GjWU<1U`@qjO^HE8J+lcpLms1AYjgdi9Oe4@{T43~W%qS<(V! z7@Q+jLToaAxE%ao>C#7U9ZFmN26#BoeqG5d*nnpT_@3BpS*pfrumL#=?=7MYKT#jZ02E+?~V~P^WzZR$%<_4)TMyWa-t!>tHX+KPk;c zy&Ca=diDLFSBD$jYrX?)Ks>w&et6F18T*{li2$|2YxU-&)N@o zKu^Yk4XBypc~+#+c^1^wob#+xfT#$nSF>~8>vX#rXSo8tBEElO>E2>E;9(8eAg6x7 zdy8Mgy~W4O8KOvRUZ&g41;=q`N_!|j+(P4msY%Dc4`y($nM8LM?-*dxX4HMem+~aOdvF@&%)2899*`d}Z{oQg za@1b1p{z#`7;dCjzegG75cmPlvj!bVWCf+=c!h!uUx6PUfEBjFSNOPubi~k{b)Lp1 z@&j_zi{J-qpDFF7^y(+T1`V7>^;5liGmQ(DFD?f^Si!w!rdKaG3l16H*PHD(?+dSL z_hWNG_B1Xq`U$DCR@J00M{#dLdeduC(^|Zd<+MXf!iZ31}U)dX%d_d{jU%$@D1qd4dOaZ_(b3@B_Q2#u%oD#zn2s zy~X23_ZFWry0`d+(K~w)M)wvA%L$^G9+kJi)gL;>x%$Hnqj&c3El^y6@x!M^bAy%9 zByTc3>Wv(({;V*RZ?WF!-eRuNJA2b91P@G)Ds&=vV0zSpx>J~T zKX!hx-00q-yqc>=y<0-~f$33RGlU=5`Nd|VclI7Knj`IXCH%nj$&Lvw9wHs?SiA<-5*JcJhXY9D!-|?}?RvVq4dBIPx|N%99E0<@w{HdW$@M@r1%u zA(NOn+62$2M^Y?WbQuSATGXrer*0~Je*E5J9W*ZZO-04cWdX6VqyBS+O@T{#_5UsR z)Xr^4OnCE`-u-PfUlhj{7qa)GvYpc+m!(xm6Q3&21g_Q)y)$ za#989=jD7`ZU~-;OnjtGx0^B2eABtuwC>tK`yx@PeO8Ui%-mn*>{?#d7bLbv8<;Nl z-+f>1ufC)8SLX(O&*eI_eQWkwA+5wh6y~kV2UPI{)p}j-KF!(IKdv}@T?4HjqEdz{ zT$EMbZBZd3hH)Wm5uZ4J^og%+X^uu=IXut8w>Xet4nW@g zFXvgbmP2h2`ppy%IL{){4fhryF6Ln`@SGP{fOjyY2cQDkZtxBUDx4d2)u2%M1k?}y z1q%K_c&i8NhqZtQEuU~TuCN|#h<4+bZln_wc91Xd4Q+hq9~tHx*wDcDDfo`Q#Zdu% zz%y3tyX(M)!(hWmh}dI_&g5V%mrd(QT;V&Y9}2CqUC-u_d~qY%;KsVea=SOdhUTSe zP~n;h{Ll_I;BT_v9a4BFr+ZP^XvwNUZ}^IOuz{W9z?;clNzl1h)A=Y?6)R{xc>!#Q z1RJiQ^ACBj7x+dl%bV{2M}_)E_Dg9!nFV-=0vrAbHsG1sYhZ&a$CY-Al7b1^XQ8Tw zHn4t^>?Y_@P|MXqEr;h>Sdqf~Lvs$O2WRPg6v=wB5$wA$+gxJqhy?G|23%H|07Qp zS^B;kb+_IoR+c_yK3MZU-A0 ze0->yWa*Mc<6=43fSMT2N5MSIl7fN#<|NpFGg|l+@Q$}%6?7=Z_mZ&h#(wi#umSHS z32DE%8t{O#&5R#@02`773fE=y{c2JL2?9m5L)i&7jDQ~;={s7t0v`0yJrTPSY%m8k z=`(jyKlBdDR{2tXz`Icof(;f0B|bapJ2}V?s0FdU`%3rRODGo=O^*L9==h-&fHIe4FL{WJYT9uF&zf| zfc3+3uop$K{o(b%QHTfjPR=J_1LEN$@Pmn5ZDmH^(K<-ug5lvV*bA7CTGFd8JU4Jd zm`0>W=4uEvA4@D zcX}j0tFOE@RJ)kkAKMu*>CrWiW|7iTRv8^D?Q9#b8y&Y2tDHweU2L4Q@va=!lWf)< z8OBXX{IDXDbgbXbbNj59FLFOCYFa;MzU?CSvx2Ae=NG@PJ#$~FXyF%DR|nTO3j%^j z&x`M}Ubpcz!Kt-J-teb*=nakP5AT|dO&G|A$b#KGpZTc0m0q9hrSAn{J&EtzBOWli z|A5^L3UrgJ=zC&Jk79T@33$LcQZ{G){x^f8FYmnaO?R*XS8yquTFCR%j`qb(>mp0) zK>Sd#gonhXcQA0y-1GKV)<$`%-xmN^;|hlJQCoKY{>;Izzr5qz;Zwiebmz`*ZZVpV z%279(c~{FF#-=92@^L07Gd?ABD7?b6tUo5-wl#~*KMW(ojFY;W>Gn7L^6cA&^Dy$D zx$p^J{k;SBuDcKA2W@=Fe3>@VY&JeN67$8wJtQvJx&Qf2Zl5(*PVm6ac{NtV5A2*5 ze+L9tV85p(%;5G}??!X`tSzo2F4(#MNh=ar3=ir+!qrRf!`Kt9M%^CkhlVs{IY|LK z_fLw#uh7p|f377w$@(mIU(ZSx-EO)6H0ra$>bZT^?gnn3wR3>mXZ;XO;)2b?$a)E) z*qm6a8>ypMpXF}P?Xz6Uxqa5eAmImAKkOLg_F3I_+&*h$n)rd8`)}zXcwl|j8V903 zuyg;lRorv`3r2l+a1*!hb{OX3LEXm1gPY0-5B6Lci-({g!Vj$P9vdcklf56cIf09Zx_Bcz^lat#pbS~JxBeb<5rCs2h=hO%! z1svrJJo(RP`LGn;GxwtWkn3nwFa=D@<_3RA6;GR4mS2NsYUs%opIH=hw;l39A3+@2PFy8k=_Dq~k+)*B&FQ z(ALZ}XP~K8o*n4k*edXxOG`?bwlb0TEkuQB{9X6J|f14Ad!5A6Nwvlb%?f4=ZY9jzZU6(*tC zP*1XXnBxJlmL}4u)A$|;MwVNRRZ$6elFd(MZacK|p&ukWoORWpq(Gz^DPs5anu1*l zmk*|Ap(nAP#5q#uYi`}}^_{K{;BTQ~WL4K|W90OG7)gCeNke5$9r}Ucq3F#Tb;-x_ zYf>m4nhPszJu7{Z$ZqQA29G}89lYhj&Ckm*XMrc}0_ubgc2yQxsoA=G!SJy9@0+Dt z&#(HRkmA91EM%^!aG)x$yHtlLc0Y@E{*AQH-`;-%o2M-tOzxCL( zpBxa{>Ej~z<&_!D2WRf9rhf1lOq#5qaZy^}V#gP@RaY*(f~CiU@Y7fPrydZT7^HaM z*YNX;=v+{y*12k6F}0;Rv~{3|`T=_!2f*Z;rK^9tuK(s;jh9=``NpB9b7}vN@1z`d#ycF|zM@fJuza=HjZXSec_` z*l1}5*46C3-b>fGA3qxS^t;(KE((GwbN$lGL)_)FIz+MgsMC*?uej3pyW=^uuFjcN zdzUuWwF~m?b%<)C=UEsR_&Y)DJZlVkJ%2BL0pkaPYLc_qdAGOGdAASL4~FO6;}<#a z#`lUb^Lh)&dG~izf53YOBXsrvGjB>rRDUg;cORs`L%ImDiN7Pp-r4ic!TT4D78mGw zmJC3!;E))-(<8Uz2UVQ_5yzs7J6P?hvEt+#kStwC41?4_j-uU8|fPq zn0b>e;Jh1ZW|H;zrNgino?rw1E-mU0@J?_2-ds2M3X(TPfQLe`0qaT3yr4fUzZR-u z7g|@7-IPd#lpk#2q!`Y-bDyU(7>f|yp9JVn1=F01GNF)MR@|=MImfY-UD#}MB#m2a)b3+%fkU<0nuAtvvl7~jvz*Rj1@P94mF;Qg!=dfvTt$&&<8Ja_@S0%lRN zss3P1^Cq4(cY+Q0dusMB;?ZxZ{(!yzdISBz3GOXs!z@ZDJ?|#3iITlQo~(tNO$vI} zjCoU_%X$;BS{>W#dYqOvL7({V%UH%C_2gGHU&Mg22l_+p@ASNT1z@rqFv;*x55KP$ zXK+6Y->0<&rnLqgF5?GVm?Q!HVMIyw2Xnw= zCD?%XH*p@u9<(5Pk%GR$T^wXj`|en)%uooTB`y1ci45s~sLn*nxX;0trX75*%syIfP3@>2gygiGHA;6^R0?|P5 zyc>RzEjq{oe#f2a54kjVvw4^>*b9f{z)?o?FzkMoE${=(!WKh^%6mhmli#lJVqw zy6kW15)W@CN9DST@ZJGd=G}lvyq~p!@_H^6VDcL9%c;gZ=Nui$-%fl8*l}4m_2}* zUQ=^A5A#061@`{?TLm%ihDm#zxZ^FuZA1HD^~n0y6d^OSpNYyezz-7oZqi1;B%Yz* zJyt}N74Snp+^vqH`XuQV$=gkc>OtTKe~FKH7oCT>8sY+NK#dev7=oM8JMo_M46e8elwc#1KQ9Ie)t72nFn~lcMtA^ z$ZCPT7^6Iib@hf%>*hmmU%xk(`XMyctS`kfu01w3_5Pz<@7{6u&QJgT?2RAK#^Jk3 z%jv7jfiAOU^`%x-*^>InnZ=?0@rcD)4^Z~fdL44xrYF=M{qnfTxt4{n8hrV=tIN|O zrLQcmM*}vX{?G?DEalDn2uG#eNaEt%dr7{yZyU)Mt5*>`9KD6a1?w-KTXola_&bB_ z++Q@Q@edBy_ZRP;JpGg5{Vd4@Pdb*Tzn``GVtQ1tzMedLk^4BJD1CqN#YOJpOo!_G z&71H1`B}sJIBuG->4^aS9LPP(mnFE&xt?gGco38fYbKII7ktMDbV^S4?Zgjkeo}M= z@dMMNdT!?G4~hV;{=nuR*m+ie9f=F3N4+E?aly|0<TQ^^G%EfB3U={~I18xtpE) zpV){jR~*F7{oglwKMH@>9(fXLTI7fO#9TdU!j9m9-AnrQF0LLGe;dIA)1$_(Ac$gk zP+D;HDE&()(+U*zJ!`fV;A zc79AMF{V#GwU&zq_6`Q-EcE1Che+OJ_mZBygNujEo49z`bC9b?F+4Dx*5xuT9=3IJ z@nBlX#e?ETE*|z@&&9*%8@PCQ`JY@oRBhnm;X$K&NjyFm5BZz8c$j{b_<{8oqQ}cm z1kRGa8$HS1MfpGVcLskP%CsMa-;FBP?WS9fy;r>qe~X08%RM9WO0SoSHsJ5MqbGAJ zd<%rMmTQLGZF&5a7cM+pa+f{DL$0m4Bh#Zs8q})E^ktETez1A}@QsHa$h(Q%tSaF)_iKrRudi7WT~jKuc%ikl|d8Qo{`3xg^{5FrN{EP#6))+TwY5 zF9`c?^h0)RO;$Lp!1Sn9)lqo71S{79;^JBb(@|#o4qrd`XQ^K zSjzk`HszNX9o#vHnHOg`@jPq(ADbUIu+HXA{M`qPEV+eEwd;VoTUfX_X&dPyaVz$z zMn5n-%-yB-^f+R*fk*MsSnS)t>xr>ueHNRCiTI_^|HRAbKX~iDLOhe3>lZlVHz}3q zsvvz_eD%rc$Eq_DUKpi)R<1=sv6AA!sZyHfMBkrec)0WI^M8Xklirx2co0>~OJ$uQ z=|1zxrG-ra>5cF<3+@He<&GYGcOWZIb)4mk(Jb$rfjRx}h?VZZU*GoGh`JnR-U;dl z?Dg<>2A@9p#$%He!*}FUJVa)8S6Na#gmm*{YO3TgJ?iY&A3PgmJ$$=~t{Q|nb5nlF zNT+Rip1>ixqS+;&7Jj1#@xadYzIyN43Xy>>x2(IgZW5-O7#_wRbf04<$ z3@jNd&MZ$+xLfzQ7Mk$glhd-j%)4U<+w1YLj^|v*dvxqa6N-mob%xxH{;r&S%t0(m zGxsu`j&CPfPhUrMDK1R-J$2>1@?$~u%w>2h`dhAy}M zPjtEHi|BIf9!k2AE{F3lhPs^3pXhS_m(b;&gxEw~uH8tN`wIMky4<@|mkTq}lm&17&LtSqC z-_YeE|3sJjewWbY@E!{4a(@4YE@wP9XspZSUSw`?pDydcdtyeq+%CxehWAip zf1=9;8tHN`(R@MJK1S+dq|2>=*u>u&z}ci;umNJj)@1dX{aD_482fT-3O|{}PP(LJq4LBc#d9xREIh#T^@9*g^^c@GTzJ}fj!WA+> zmz!OB^$32~p5}`LY6Hv-O705;y~1D~1~m}WC$SQ10zb$N-c{2=4buuXh^Zg&_cygr z1zqZ0wPw)e@E(dE_yIG{A@D;I*l?WY3wzMzd^|$hzNN}P#>FD7X|WQk0Dee#Rz-&FsN>QSUSaLe%kez2l@fgK9!_M85m<0SZ@FJO|aLC7j-eYBP!T6yI_`xPi)$}qwOWFgN z#Mor#dXB&k7G7+c#nR;qT1Q2KADC``8_W%w(s$K<2TWp3yGVJm0d%=|c;)6&bAxKa z4-@C$E-m5#=jAHF2C|#|(q`a?4wxH!mHz(bCxA&fOL~v_!2)zS73gx#^d9T2277^c zhyq>C9BMfp)#XM3)p&Oj@9SYr>kjD{f8zgFyAg}@J2Z&AF3pkTwSL`xsT|C^uau)U%?4CR64unc=3CR~}G;i{FyoBNzq2^w&Art(7zsGttV6q%A znFg_mey9OI@Zc-10zcFN9<0HJKfneX;3zlUZtCkvNucD#wW5e;N}E^sXq(nOt=G=3zCRJ(b*~Y+uwSNY%$V-)8<>_2r&rl2 z+Jx{Lm}OjVx~?+E`6%|A(TJ#5zal(&$5w)hkpI9^Kz30^Ky6Y?>c|E=;{>$+Fwjb zmyav8A)>LE0G%h@FC%zh^K$Cz$Zj${O86L8kNV#|FSq|~t{%1FMU1Tfxp}!a9wPk( z(62eR!o`E+ zGAprtSQCCI)m1^j)vMA@S#*=W8|!Lzj?;L`VJP8{=trq; zH>3Lf#xu2r{SCwX057y-!z>GX25yiv*|kJ4RoF-y+e)g*2rb zeq@;FQE6Qcb%pB2%HZklslh>kt`ft1fx6r;A-h5z72Ws~kJd1SP9}Ecb(N~_l8j}e zGWC-F@I&HU_5!?LjlX|^p3Ll3%4ccLY6PzSGd=3B&dXUJJ@Uho_m3Y6rhW*R$($*r zeo$w-Swj-k0oVoI<3EzyLEnm!oe1VbW?ohAFODfGIsMgO%-T4YUlybJ>$wb{( zwELCU&!@9FvDg+Hhw6%|(%^_?Zk=H*DZvH2q#B=rFp+0X9jhOhPJ8z)Nqs;5VzE*V zHelv0v?$c~H{Q<+TP%*ukPDss=S(!?t*owQ@49Drf9x?(V0PG2 zx0^y`;*gS8WNQ$eXvPMTsLpj~dqPCg@RN zm5bSsHyIx8N-y-B8*w{;_mVKO{NiSs&4C~O(|I}j41h2sIj1XtDuH6z2YxHx+Lt<2kb+kSMUaWN8^7}Xv< z?%A_kXi`5FIAd=^{J`+=e5>NM`FBt6!{4SsKNPq%59XT+Bg{KWz4?GicE8)I=Kh>} z#y4+L(~2}hQ=U^`ViWINP@0Rsoz3cp{R-X-U8lq!v-gV2M*V#>KJIY~9a`SlqQlZV z|BviHm%bP)`2_E0A;b7g_!ikLbS)IPYZUWAElYTqn&Y?qc<-%Os3{)8!WU+3>N;#Y zmxsV^>hH1Ud5a}`fB*VpC*4=L5!eY$KgCI|{q$ZqRRLV!!EY;l_T?{aUc$88@PlB2Sv( z9LOBW-58tB;0JsI(+zAuj>3Ct5kYNB{U*+Vl!Fa;et}F2{bsudoWdBti^6_~w3y6+ z1nu=DaWM`YyK|&3b;{(oMHzlqXB54fxLg zCZl)$k)x0&aWCNavm$oD6zHYi`FDpo5X0Zk`p~G~%))*Xro4>j#Dui2E~I)?RX)K3 zyPw7KMIQ8=sW-Oz}2@cy~;ij8x8$t9Q2!( z2Jf;GPm+4l1m{3X8Oy2EwK}$6&;-!D3GaBTKJ?-%jo(Fi3^)o`$Rm1G&YkpK6x5^U z0h26mjzGUzXfP*+_mV1sCj~S%aZc=lMK*i|u>o}$C$IrEF|0`8U6iUQxMk*NG$%Gp z{V)!Zh3_Vbs2)`fm`nm2@Ld!7-c1?+Orj0TfvZuk#yK(Q{R8spyD0c>5^@yka=5|_ z?1j}xoaJ7F-`B$xm>v}Y`~dGJb^L6gN1ZURVFLIe8fG|$=^UvV;-Z7{1Kxdb27U_sW8&v_$S~&1AZ{4IV%EUa}wf$o%811B>wf_ z)4zPsK=VcP0GoE3-uKj+Utikr$M@eHefXayaF119#h3RCO!YG6JsE?RzHjfJkx}A6w4QN>4YDIlqaX{NMv=ed=a=x zH<63_BqEB{)x%ed@~!gky}pyih3?&?j^QSpm&<6d9}e#~Q*=y~xVl-Uv{&@Zh9`9f zPi6*YjAqYyx{k$UWO_&cugXBfLGEMH z(lO3bj^Z{l7Q@tK!ZNm@i;`{N!JKZQ%R<~HnH%xgCNskY%oc}N!~jDk%D%VX_Z4bP zmh2yBzTdCk`@F~Rd7f90L-NG}%2_>tQHaBN3U(z=Pv5!?+6RQyXlnzwvcp%HqfZDv zAZIpI1sz2jRgk}ZhX&7KU`H_Gc+UjPioMT%TlHbhX^b#ITpSl0No>-6N%zz^vJ_4j zCt*ekHO%g|1NE!G&xNX7N-yPjaIK#j*R_U{GpS~2dO9Fo3>t>w0i_v?4eMz*g z_OUabPX>PA+J5JfdK`8o!<$Ue`ZUhf<1Jo3-}o_$};U73H^ z9(FFke^JxAtz8w--k?CYI$D)4)IY_l9;eZ?O#)|6P(Ay;>F2b@R+2HeE=gGM+bo=0ei{3&3+S(vcXDU0?(M;v$6eV)OvJiz^ z8OKHG*uc*&rk+!DPf&Qs4rP%<#&9J0g7RU!E5#o>1i#U5rbjskSAM0&4!Er9NapO7 zr}HaIIcRf4o^WeXR8qyJfQ^UcW_BZmk|Kq*BA8y^e{@cN&y$22c_8WDv zEZbbA&KqXtIXqhrc~*lYhC4(nUH6)!|*-ps$Xi2%jUj0wkw#ajX_e+ms%s?{Te6!3fjo_mf8?f8WiYPeUZE{UpLetqf8hs^3adOD(jOQoJ#pNV|ld=f8B0f|X7*JSO_p(omp^loIxfAgz zf2jxbI1pJ$lG5PjR%y_-X8(r7^^SFE)iE+ZO?14!Z?&6F>FQw}5f^Tj=gxE^I7#~~ zT317K!x_M*_rG+DFY@W7z9^v20-s*We}H~7gWO3#7~qM4Zt+LbZ_>Thw4U@pXUH~m zi$3e=d=mWaq2ENlNx2WI8wq;>>v4b|1#>xg58%TodjbD}>XL-$48VWrCmk#Bf=1Du zyh}P1&}T)VS&;7io%K_9d>_C!2{grk4}dV>n^cD0gv} z?gRKHO_9x0@ZH~@=5F*0YV;IL#69?q^qZ*j(AQD8DrU27(HTP5%pV#^pOrw)fOLz6 zEgT-|nsMH=L2+S^egWbFDiBl!Nlu_Q`748VY8WReKT3d@xya2H;PI mB3;rT*((=k)Gczkw&*>uP|qtS{U+s4!c%}pZU^Q^wfqZQy0lIJ literal 0 HcmV?d00001 diff --git a/crmeb/basic/BaseMessage.php b/crmeb/basic/BaseMessage.php new file mode 100644 index 0000000000000000000000000000000000000000..96a8c0e48233450790876c932d65eabdd1dbd620 GIT binary patch literal 23104 zcmdUXXLy@cwyt|Gl5E*lcagi}D%ZHka<^RM-kaR3Y{^BkWt$oZZAgX|5)%eOh8`F? zgd_t)C@CbgGfX&?02x|~XvdiwhNq9P4*I^9@5`J+BEI#{ODQgi)g7aj08LQ#q_De{QUS*p>Q;FZYDg^ z7+(}+EDc#s%?%4Tmd-DTgl$PfNzOrHuK+I}^?a~tzM7-1RtE~jBVyjF6L>;_u-(0+ z(!aP|77`>eax0zNl-#nZAlZ^}NYm_=7PC$lp%^ua`9jhE|0k6D*EUYNx0yx^^{V)! zDuaN>QS)RT4Mm~?ex-1#oI9uFxO$e9suyL#s3>h~b6fX9bXHhjk4aj{l?p1#1cCyI zAiLtb$rJD43GWuDs|F-h#%{TW7eAs25puW^f!N0-Q0AXsp$-wrd;m$kv9v3SJ4mE&76yPv&!LNuPaiBOb8-mv$nR*^cVnbyK!68CcWkehv9K6t1 z5MO+Cp#K5p3$#HFHhlc!W!@?71y8wIys4Eh4-^Pj#oxx$*P;PqDQ@*3Y~mJcEYg*Q*zhRkg+Z@Bgb_v`f2^^(Mr@ z0E`+_XcvAt`SI};AA-XOaB>20$i1L9dAwTSgC}rO3!J?Do2_r0N-)C-GM*GTDFa3o zP#loetC8dbtJA<29>9k^$3Hw~%WCaHpoP`8oU}dRx8uUfsMW0gf9Hg!a!GW%01l^C zaZ(L&k=9yU^^qG!w|1e6gVAlpp%;9S07&u_L?7M*K2!rA#K4DM@Wr-Fg5;BKB(fa3 zQXliuT2I*7ZmSR8pfKo*o;;#3w`3B9*=8gPQwcV-fG=j&6B`A37@t4o}$;om2r1vw*{vD1yTbXq0<}-t_1aQ`-L>qb4CPYP<%9d+JGCw92f$ zAV}JB(hF?BuRxttferaaqA>5QBYa3uBtGrgZRLZlH<`*=abWr4hXle055Qpxa2Smu zI8<1?89#C~@b_k%3*!(6oD^~Wy55co16T!g&Y`~mV4*H-58z$uh zhlhoP4_*TUU!?b0vtIN(Q(A%pQMvz)!(UPeANnCKvH;0{@`zSTL8Gcnimrz;*Jhmm znLea}PWH#dhMn;uICMyCZNS(RLGFH7PH?EFT8%m>02^+tB6;&q!vqImYWkDjTB{Al zSX(~)T4Wuh`k;ll*amU&?)>WdfgARh$lq5#T-clOBYu!CIAT#}ZZ^pmJp!vQFtRXT z^h3Ug^C2fVgAFo>%|VFGLC}XibwnSA`2>d@y`H<>+pIOry#>FoeqcJe4dUVfh>Q6s zQU#$-27wL!yx-=-zhiYR)DN-UOSAvTC5&p5S$%;D!$BON68o}%;BXJvz@@R-4K~~_ zBKjcDB{&>POM2QZ$67~y8E31LRg@0~A*tn_%Of~ktRj5a2yyWU#D&2Pt3j>YNb_c9 z#P6vFf6bfRupr>1NbFU(w}~*SE5hoF3q@Als%o$aYHL_}GO*;iP1Qii|D4!#IcqUEpaYqvI1@htH;eW>{!iP5k2@ZdTuh;=` zvD8G=9(58=NNONB{C3v+HI)-`{D70yu6)U~2RWgZW9tiy%|*!F+gq&l1I8xi3$!7t zjp&0bkKk~#TgGEWVb=b_sQi68xig&b;eCjU*C8%`Xe1d2_2DC|CzpSl5C4wUu}}qt z%}Y4{s3Cmttg!k5k;K^ah1`9{+lpj9?UGQdKN=+Z@K4A#c*2CP=hI28HS_8_exFXh z(oB5uI>g1Lkh30Fkj#tvfF~@K6C6SShu@B@3$t1ToNSZ@6x{DZPVnor`r_YJAZWu; z4MFluHNl}g+w^0jmSz8ccY;-;_GS}49EGn~!MGS9brkkl4!vf@YiYmE$=`!yJ#bP2 zIjcxRa5zy*d@(U(wE>Zw27QpAKKKzFE=eOgISe+eW|SlN0&AEd714*ON`k}MdXkHE zHSpn$1;U3HRTtI=7Trx?!#iLDpL!GetYj%v<~n!VxVW0?3#uHA3|dfu&Xymi~92Uae7ANs80?|*dsgJ&Oo znDv{%5St%=_2uznRh16<%C4PbZG;b4KeR&q@KEerS88X%!7@vC0KQn#>6eyO!7(|$ zOFW@tQ|hu>pj9o-F8r zIdeu`qRBiCU9{YsBT2{)>#6ph_8u|zL`KPD@&cuV57=+=!G=d?4~stY|L)2XI)AWt z*UuUAmzRd77p3kAe50d;+mtk;w&cwwh>J9ZPxEzg*WH4>9>ztOZYn>P%Lyt;PSHe^ zw>l*#z1^2)mL-S-A9Qld@rSR#9w(OKz>vfqXEl)xd|nZj|v?LtN$q?IB?-B(3|hQc3f3pQXET+ zCVY5$iNpmT`0(h%TaLf)ec0{LyO({tk=E6R?T9`k01n89Px^|$oBFe7CTPA$A*}WT zjY2-W``~^9D9q-a9V9L``jdR2qBsOjEb`XL%MOJqNnF$nk+|>&l|x27@wXrS-{hR$ zq=}|+5lG@fNO8Drd8lqmBHl6OL9%~bFo_E;#3uTpX3Ja2kS~5187F;KjF{jcfVjXK z=BV*j0c4z&FD8gSl-d&<#%S-~yJh8RLFvGXlSE@CC+&();pe=yBdTqOs*ZPYF!BqT)+X9 zc2^2fdm(xgPIyQ}aOeXZ@B~k1QcspzGH?7y$a;c<8`yv+OgWOcC|;Gb@PuWmax1Px zC%b9x{!&l)AhUc0oKQ<}XrMKWs+-`DK=onXiR8^nI*0kYC*eaN#o_*Dk}v!rHWA5t z>In{7umO<_bR#$fL0lk`$+-jvu_f#IxctGH;2^L>w^DL{3c;a~>cb^t1P2M#$=kFf zZwAu5`Lmed5J~kx<3jk5Z1HAv&rfkAE<}_MJDo|shyq_Ak|D0Pd{|$yh7a>=_|Ra> zhqEq(4?M~T2OnEL$kT24FwtqthpW8S@FByN4_9(*`5>~hu)9~7dc z`}FmsmO~`PfI~C*BKFfRo%-A4+fpeG)g7(16}?T}BF_9=>4-zSS56qAPL=xwd0T5Z6B!3u#T5g*MjSJQELOvpiwVW^5@WF`>oNvEe z{@M_Yi>2{dqgfiAz@J_x4=xIu)5-ePh$PnbH4s@X54>}g^ak0VN@!egJzH{=`=Os+VXtLKA@@u10 z@*1Rs4^qIP4SeAn$2~FPQq$G~Cl6h)t~RaV~c{ z*T_pysSo#3eb9%rnMzmT@W~(V-oksK|F%MkgR=hU(XT%}@W89z|9Ir>L*GC2@VUS2 z`ParjpU2_J9OF~`b$d@LC=T7x;o;>a^X*e}VNua~z0p3?#eE<*%XcbwFVzhg z^aj8Id;egtA?9yi9SZsE{p<6nKJ?BlCPW4n_L}px16e8Y`O})596NDIY@Rl-szM;E z;rY%kPJ>S3EXW&t(X#uY2T$D*_O>(ChtA4^s^T2qky&M7X-!3^y^|ZS2NeeU3(Oaz zUq5te&mDmex>J2fYZOK&Hv6TRlFF-Fs>I3;ce{eX75=tL(CQZ8r0WesncC;;4$aei zF_M&KSf5&%PO{zyIgAgf8~@?z`_ZRAIZ+%=9r)tG>sHSG<;L$m`Rwk!PdtC(iyKZ} z+mh8)&yua`O8`M8-a5(dey6NzDy)R`_99k;Y>J;K!1F_izHVlN^5<6Iv^N1VONu#m7J+QVppj90bV{jJ~8k4%y zv+OkPli>-oXanQJwazIL*$DSe8RdhzzEdPsCs^(;u%7(JImS{)HPC#Ko7hlVD(TE+ zI2;`RFs}cOmu`|#9P(mMZQAzdqc8n!?}N`>ajR7y!nR+s;f1YMeWlq~n%wQ-Fd6Bwloi<=63(mcbn|N!RaKmi3#Wg$ zRO$X^cfEk}p^59_Wo)Rl=bbtH-d*=Tc#!Gj?XEWuC1f;R=|^?)hl9`G{o`%-z4Q8W zFWee`&G!3nHi$aexbAU}l^4$(^QSsFlrPVb1}Sp|LxGn2tX|+lJH$n&LMw@h^uMcv z)(`z^!_s{I^5XcQVZPKMEWAW-wA7PKCu;_#b~>xt-qul_9G=q~W~A#9oXs(k+>$(V zspG5#NruDAIrnftqc&@(J_LuG+5*5AEMIINz0n_Z^0`u)FC40REquVfyA-rq7u=i| zTB>_1h}I85y!iO>(K>m7b94{(I7}yh>H7SQr_R>@FhX@w(c7;dH7!O37FMrw7bMrQ z{-QPNwIrAoAFHQ)P{foMUi)y_wNN9 zocqm+M@^)TS^%A_24AqbeK^?Q!4DEY;zQ~vIn+^D%N+q5^1%iNuwgkSs+X5a>ZofW zHt~-21jQi;>IZusNA`6PsiO{pMs1HIH4Ii_h42*%KBR`h6SBY;Jg`9tHel|Co|pd~ zO#T^?g`f{{U<2M?U?m1UZ*d&lfV9Swyh*-7BoR@aYycd1V8cNkIbjZbfjthZC*@$n z@KkD>7wx;p!G;*HVJpqub6|tNU;G5in`yLuNTfDE-`%!SsW+0U80OUw7oHHCSVtir zpj#~2DX-zZGR{sQIAHIOxqAe@B3NEl24y55*%$j1@Bw499BjZ7^ngQ}Su39iv}Kfp z>SQe7U`9@s6Fz)I>uQEWB-pShs4_-`k-FNK>f|8c;0-p&!G_WfCI9PSQdcK}4KH_F zSse*BbQcduT$f2*-9zJod_{#?3}4|cB)-5C%$Bc!yh-%|dOhu;N?m=4&^i;tI%*5e z7hYgPn4A~zY%{5=PXiwky{&v`1su`^q^89a>>yuwf(_oF4>*^DUQe-3Bn@Yb5`Yac zU<2k&{0f+Xgcd_|2bYk#ntTN}EP&$B2sliF4Fw_O1V`Wl4{SIBIG{!agD*P85)tv{ zfFy$IWFpvr8U=Hh?j89R<;0tH?HusMIM{&o1AYZ)RG}-}44w^QClDO=(7L(}aEO)p z7Zp-{cpmtGwH(ujQLsU{EaS<82p`y2bXmGZA*T*(NCq70ibQ4HsX^0D7uz|BmAF4qg z+Scg9ZD0eQ5J~hQ@*zK>4@H&b`NLoX?tz4X4K1h-;7yhKXPxN7)#zjXOVbu9KjG5#MHiyBP7@olHlCIK`e8J{04jx1w*c>Lv z*>(;y)<|$*bC|QOBwsKbesL!C1DnHmc-zilwx`+7VJfnT!Y~}VXcK z5`|%Nm`@b8bC?|xt>pwZhnYwxI?3iRo1BTlu({mlMYeO8myK3FAd(AxL?75(ZaCd` z4)a=u?HuNfHFLS2*UaUPXAym1apCGq@&%jADFaE)Vsp8zYvyuC*UaSviMD)bpS0z} z<%%_Yn6l+VdlTUUo69Bl+w$QbX|{ZLDASe?{^PcM=;^WL1Ky$F31S*q`V3n>G&$Px zq2A4w4<1b-#a~S)*iC$^nPTp2Z zbyA+u?dwVVtkhKB_99>3nn~k8Y(^H}Qctpev;9*y&&dCn`J*qbqYCR>-9$ZI&eDKr zelK6CTA#T-A+Scs8ygt5;K2ILEBQZ8zo36^KcChQ1$701-VVCdK0~dV>sNVx4zqWi zs~l?kM+a$Klr+`{2|y>=JnCl$lPnnKQJyqkENU8-l%P?p&-z{cCfLC8#qa7jY2L(n z)UWoNC-3it8Na2!z`5MJ_uKJ~A4zySo${gFUFxUk@oq_7_FPi>wB%`=+^dCA{rx?& zVe$n@Tth>!UB0=xq>6YGca!>Jb&xOq{!?1dWoI?drciwlrlgx3CdSpp#(eX#sm895 z=UW*#6B*T{kID}(?Bsa}eC7r^XJU}m?5-K-Q6piu#?0}1j?dHjq0mkmR@v2%;34d2 z&{TG~YifonTR6ep*`qVFXanvAVZXUwDO+E+AlodncvGqhbdD<#0}hN2KWEST<+%iI z=TbgYwFq2zl1Vk|yA5Cc`1yZcrh5r%dyI=JcbSagFs=|UbvnzMQDN8|#_j!mx19c> z@^vWeK2KKY&N*&#p?uJ)8+z64_9o@y z1W8suoK<}`36ZseyK0#A6#0&p%!_+L?ZAg^BO7po;;(q0g$iSD=Pij}g+r~~kg_LA z_dbW>AmnD12bT7D&1I804C}j}Ncd+VMI+D8;zI z+8*bVgMpV>?r{nscO#No59bb4S~j1Id++(dibC~amN)GjwJ`Ez-6GK_qO_#0h8t4( zX0N`O)%7Iitkv~oIZT_srF&xR1XfqOf(>qM8n>$w$O+ql4~wgIwBn$Sa)54;^_#d) zTME9wyJp0p4!#2W&67?fU!XqVT@u#SxXUU7Z>s$ghL%G~J$W18AO;-%MC&Ln)|1tS zh5zg#`Qj(=#da>?B=R90kS>cLT8$@U0w<+lLkZY`GZ462)IKdQg^HBq3lqeq4s5{P zMPwA*Er#-;8eH3NvbaEv!hUmmH90{6zR-gW>^`d!Y*^%18*@X54XBgRV8hK|1I|d* zU_)SsQo!_K$kHX56$WYp+%4v$R}F|s_KzRQhdRoc_Il_GxMLN0z*g`MAv=NK@CB`- z%HS(PRqFDIAaVlsS;)yU+Ft~L4THfv-gpbC9~cgJ&x;wS3UI)l*Q<=w4@YR9#Tcao z8?t0Fc_W|H5ABxd)_6Gq4mof_8SueHD&n6mCUKDrd^kL6?fsR2!(c&(s4 zxAH*+IIO3$AUwelIOzg5OaLD+Hequ>?Xn>CV~i4k4H~MG_!TgZ3Y!6yizy`a1NjQE zyolnE0X8VXhJrwHf<5rT1#CDDIG{$AfG;{EJ`N=Nhlu8AT;zZasMXMK)*E`vbebfQ zslgXIumSTXeg)jQCwvK6?=yRL0>J_2QK%2YfJ1X^bpLb`sUL72g}FNoY`_x?V1w45 zD~S}aj+N+SJK%sPB!CTLfWyQ9;lr&oE?9rz4K{d0lGwx(`hX8k5SytG7dRV)d6dhI zZ8hg77=HjhoD}$MNe3Iy7q~g_$02U$F2Div#TCGZ0pR3ziUaatcp(Zjgz?f1)Rx0Y2c4 zH|iv^dKtcAQC2-qyvYrF8gMW@7x|}fz~LIO0e3LI>QsvFwRn@vVK#ydr@;n1VIFMI zRP@PyqZ#%QL{ab z`gy?NR={BtPM8Ev-U~Lkf(`4bFM7a+B+3VNulG*J&hF3uv--Yfii09uQ93$NoHJ3Y zdhVrX51f1Az@xXHx&4}RTkbr4`=#o!QTz3IKFPHqnTnx_^5I~SeNA2~bj|MhjUs|W z5ZK^tVHAmrfKH-O`B5Y;6w8DUY%j=ocK_859)0(*ezR;QIzA@adcWDW`JJZ=!iCqf zd;gMX<2)zcibK(b`tE3J-+i#=r`$(&KC?TJ#>M1(cWQJ*&D@e^ZXq2w`4io@XZ@yj zeUjzf0gDS(S8KRWw(Z+=@EvE$hrtTvV6|LpR3+z8Mv=I{IqlweQl4f?i(5V65gNZS z9l?R+3#M|J7#9)Nda@)gV*8$-pT0KG!fL51E|ymo%jcCQ4XDFrfRn6_^6S@rT;ggx zBe!IKv3y{#+2D^8414#Dr!T$Y%*Hc++5O`sJErHEH~T{8T4lYJSyR0_W4{y3KomU# zeb)KIqa7TKtYf%WjEoBKCvhQ)CHlbjK)Ah%CtS5;Mv8F}3~^BpHWY67CQYc;pJn?G zeub|5##y*)7Ls}r@AXilmVlF}Fr&c9D4BoR`=x{rmtHsgG*MboKXiZ%rUj|xJr16L z`GVzcJfR!~}mho9k6DnU*h{uB@9Di(jzLF=Fe9B}8K;E)6-_`WEodtw+DxF;s1IynZuh?fZb?{K!wo2&{_ z!&fZB#M?-9vXbTt=FJ-Lg?$iL@+RFAW8TDkfqXa(zEFGhMUVCo9Oh|Uu)K*n=>f0I zSX|tH`fo~L)DGNr#}l&iq$ct1@@u{j6P-XPxVAr5~9Z+fr9_@L&+57p6mHP#QSPdETJ)Ix2~`ppcNuIYH_ zH!)wJFP!zEfgJfo`#=Xs6?GeO%_+kZm60*E9Zibt-hdGI{C0m; zO3dkUNkU;X6^-ta6%6b}HiTI~POhD5ejb9q&J9->O_;b2-O8jW7s&!S1{N zdGn>}BN5--oloOpws@j%dUAMDr`MYo!lTt2BS<~T=Cp4N5I(RutuwT8hy&|4zx=;E zrwtX7+Mdm;=R$}#+5P7K>6~_77*TtcFAjPTMzJ~VhA^V`|Jylj!4y##rjz-hBre## z+*RvHT(JGge>bOnC4umP&1t_9kq(9N;eR@(O=`2{!?ehj593{H_^@V9yF)|rCY#gp zWOrI>d%Rn;AlZ>(d7s7R4{RRwznxDe9LaZfea5iMp6Ww>r;;C-uFWc4E?aWqY3d5n z+8hPqisUe3prw9bad9f{G5PI{kNv>nqDWU+tf_BGo~danZuH4NUq9^1UXC@wUU8Bo z>qYkjFGqz`f>yJ=!HwDL=IUUt8278Oekf`xY%cKzF>XWav7QMR=zYum$6<#1b`?SbsPvpe^T71LQGt)tQs%d1O!I&&+Ei{is$ z;_aQr=4b07irfdw*Udzz{c8&yoGaGXs)Iu4zCD}MUiXe^`P{30&*QrT)atVODka+s z@=^x*^ewqh3FPxjx|z)0;4*=)OLaZH9fGVELhEYGS*W!5b`tCAOW`YEFUaMu5|S^L!G;dNf$8Kc zU_@>FOod_^sUwItV(6d^iO*;9k(S zMRLMDzz2tUYc=>O_(BVNK`buvfs_7V1MW{^uLpCOus=v7;fzr@r`3WDxG#ra0dGL2 za$u^~PUp1bD|}o;6o=hlgAQy^hL97gfe&S1!*Rd?dz`)C3*TxO;R6n6gNepP0@#4> z{h_99GxO>?h&S~noWm%=hShVJBAB|b-3!`C>&Z_52iyy4qxx_hki_{U(}z7^Loe(F z&Codv!$Ar-Afp}v8zg{31D(^pZ0VASFHm8g0UTUlM*3(WiHmYO(_@|x7pM<76MG17 zXi^6YZV0vN1McMP0~?T0F8~hqGQQ+uK8dV%0S6A?u!-Vu57^*aP*FAuqcJ>Tz`|;H z?@#$~%%TrMSr_fQPXH&a-sDR5fDK*{n=EgB<-7Ad2uoZPxy19VFZ!^ZY$ z(}L;|Pf|yfTB4hI)7o!}L#zF-^wGUlKylzy6>>QZ0aEP!kq!90$IHrQN=3rGdEuQ!}Ztx`1pqpy#Dr5h}boLGTEm*$vsQc zV;)`Xjp!R4hzgB^J}ZA&o0p?7HYf{l4`g9JPTo?%cQ5v8n;M**3e3aqpr>bmzOKT0 z(g$oH-t^DE!JEXzee_-PNG^#Bwnv(?^3|(lBI$E%|G{xy*cRqz?KiXkx@W6FBHO|C zAB5q>r7j~RU*LUK+U8FVRSQHbtnW^$=nE4!lfE1GX}9VVsutlsOK9lAK1PB!oo(&i(odde%qh;g1yJdU%b-tG8*d#M6!?eo2!tYJQ)bC^FiHf$j$5F9oDCs)s5SUt(&Vh;w4o#pBIEPUIA3nf*0nt4Gae<7If*&Yb$1HN0_05&YctsLvSH|c|I-W^oBOsj^#2G)1K{Y8L#zwzC-r@#ip zp`%V(gL^^l>h{+@eEZzvH=o&g#W#;U{pSOx$8sj1Tb$1!`wwjX(01$5bkNBi0W@D^ zMTsSdWLz4_7eN#UsYAczJul85@Pu~ydmtDWSWi|{KI{Y=Dou*IK)OfD_F)z%4reU- zkf3FIVtBvFau&|a&%sx$-V;mt>K9kg>J|v!QtH*-z;Rz1&B`<_>CFCGoLBcXhc>1Tv;{3Y&Y6adivhUhr5Np1Z>k|W zd3_UMHJd*)K6?FqmHxsN)^DcH%$I2b$z2lOcPDTA>8&Dx|6kc&key;WE*@sZtgilN z&Y3(d-1`eGDkoLN#5j=M=32W$uI)r05XoA4pM`ZbzNN)IQbh7Dh>HS+*3h}8j>5Qr z8s?p2G%lDy(34fDIdzx`H$Qc5=bukqa^LyMe^^ekdCDm((~i@c zJsA~PQ0(Wn=rRQp&YYao^&Ml8dF%ZR6MWD1)LD6Xl4Dll`ecC^f2&7M-?_8?qW=PO z`-B+l++KM5>z}ROmov;8xWIlB-_qi}9_qsehzlJr{(M}l zW;Mpem22X{>7frUUCjpvW2ht`|JUP!&7+)E+$ZnYaP$&0=p^ugw`v~s!~VZt{p^`D z8xDNG=Pn`42D9Vi(!2VCb7Lyjk7>FWa@KceT3=60z#U4ve`#A+_ww-2_)Lx=HYL^} z5EW)J!yY1QgueG@d`P~)JW2$=QN#M~dC$voL918FY4%?%AMUecz2Z#E@2X)fhxLPf z&}y|O8int>Uk5%o!*9E>_c+z&tGnR7dqqO^Avm;FhbJ%`_Sp4b`=da$&F{bC@a?`= zuefjjnLmH_{oX%*_tfrRE`Ip@Ty8vnU@#=Pdvc~dF4_pWdor%dDcbVxpvjli4+5t4 z^RHPH2JhT0xjX+RP#AK5VVUI2AF%KNYdQRi6?mnNCy-a_TaH%(4*1TUy{%sT&K-Ap z*S>SVAq%}Jl(2WrkqKXBU{X)uCmF^wmTsxf6sB>|HY_ zFTi^lbn=#PqLWiRQi0&RX7oj4@I)QHYZgoseZYPb>xcRe5_F%7c3*+-yDgQNk7hva z+EcyIH(kG|v(`~N<(%xaL)}*=(YRP$N3FdHiZHa7Pu2`g4F%%uLwf3ZY6ITmT*o=F zwbIA=Tn<%xvsCM^o13mTQGH;1*!@g%>SZZ`&!S$WN}u^4s0JOgvXZ`iaMy`vp84*IU+#V3GG;@^NYVOnd+*}p+))}?^+YGJ z*TeUE7kRF@YECIW6VSTaCoa&uur4eUZE)w*b+S3k%lWS!ue%}jR*faPg_7jdq(J$YxGxuo>WcH>}w-e78OXtkM-IG9J0F|tm_5CRkxM20<@i|gIusQ9n3X=WVoc5%^x?)WY-!AWSp!%R}RR#pm`J}yPS3#j&4L`v{8HF`W za<4g!>EzCV{^-P`Za+6toh%-xDpB{e=CpKF7>Wbx_@+Epb9GN-0{IH-{e_G6gE^mj zcD%-=agnYH$O&)rkLiu==*H~N>dDi~BB5yI{v~imU?NC&9L9+S5cITopx5U6YuaSVR?)0wQsQ$pNR*TZI zcWQNyx3*Ltj5}kZ^<+g&QJD(fZz|!Pn#eh+L78UPo{^a`twXCkz-|`j)_vN1Pn@hM?FMed$QWfh>Lm8nx_GL4Uk`m9L zg36*9Q`A)a@@zt|t0AJ&PbH6)y3RL78M;TOKp&ofy&%?a9vXaj(D^L6X%`AEoa${nE1i!FZZC{cF^EH>d2TYA;ShM4$Y8e{t2v zC)4lN{e6Em?Ys5vy;aNl%4MT&uwSiI$3LNLTHap-7Qp+9o`LLmcz3JHOo|X{inPTcGe>FY+6(0Tl-CH@^TIw$na~17FbsGqG`6 zPom2CfeoGz7Z{r=h)sXXrWxtGI{`@<&6`+9;eOP=pgTCyZk+|84eY)fe~%RRqxR7k zf4B$IbiPyL@w(tE65*}fUG%+PIOPLTd${)p8|+Q2YZh|csXhp(4LFy}mWXZUa`>C5 ztLJjP;LQ#6y&jw7uzOw(-~e+u!D;$l&kl5Qc$E#P4};|ck}ZqG20NBFDWj6W7ae|e v?RI>^he+VVEW{?hrOg8ze1Q+n1?5$dbU$jnrCTJvz+W8N2EK5Dsr!EcHpv8_ literal 0 HcmV?d00001 diff --git a/crmeb/basic/BaseStorage.php b/crmeb/basic/BaseStorage.php new file mode 100644 index 0000000000000000000000000000000000000000..9e0065457494fceddf744d4d706339d6e249d381 GIT binary patch literal 9768 zcmdT~X>gn6wYKHmmSan@Y-{~2Z}PrM-r`M`yi2kjZ;|BPl2_T*W?7PDiQwLwz|hhZ zN+4-SXaWrlOKG49Bq^7&6$nXbx!)?7&eN8wT62H7UCC%03SrqUMg%gD#i9%*Pb3>~q$?a*2ZEb5!;0vdO z>@_d2`89A~c5Ew~itMfzD7hNGwS~1%8ygnY*pw1T@iQ_;^qUPsi%{-n`#H&K&%$U8sLSk9g{0Bh*IziLsvFl>Z<;CFAS3x zD0l(afL^GZ$1ez=hQT#8s7MVm(`pUh|AK9Vu3_z0)WcUW;48Y|D|S7ye=q)u)fc#H zYFPUM8)}FG9AW^62Oj$1ojn$egC1~j01lJi`xUm4^MAki{#qncZ$i@e9g?_)>>7+i zhM2OfAUXDZUx9lOQ+}_T?ggqr3N_rrO8(`?!@EC>Ug_rKLPjygE^423<$C>!(HUQL zcCNe9lkaJfWtk?dzFc<797`Kflw79oNMteuL82O`r=Y`Q&eR$ulM#!a0Uou`XcUQ3 z3JXULGlv5hDH9_XBMZ~i(jeozjpb{i1|QwQw(3x`)A7t zMfmVl;(A7zJ}!MjKkjuQ98!T%L$YD-v2z#CEer7rQ-qVA@9m~a*$#XN2Tq!SlLz;n z*mBlpffv-205~ZEMl}!|5UbZBsRULRK`;7%4qMSWSNg>BX8C1TFtw z7psg~%j)$t{9nC*IEl20YLGBEg75nZTNqY%7vM07aM+C1tp!~eHyNTgPU07sBBbus z7p6d)cEI7b0L1HA|e!ZoOX5B~75#@kJ6yZJvyG6eWAm@ME zM~yU+Jc>Ed_`?X>?pMsH_e+=~r76xJ#P!_ow)n z52zRO!0H#0$0qJtoY-lnIq9DfF}a2`4$DznKc6z{pK;6#=clC>S2R@?^c3e*%PmST zPcp%c3y=g?_OL<%R3RZ^-=cHEmut^8E=Xk|?wP@;ct;*fGgvoeV;Seo!zSlYQKs3E z;M>SmO;~RPjZ#j;hZLwGN^Q>jK)3I41MvsnNQy7Ac8SFo8wCYHvkfhyxg(2i6NAR# z+?k`tZpHz5HR|T~;eh4^LNYuQ`(!p~6TKjM{`fa1(#1!f>cV`ur2z9m1UMihzddv9 z?W5(+r+&AHb%Ew)H)u0%`_||72-27JWNxNNLo4Mujm&_^VA(>DntFhX`Or*!a$Is@ z2)&>r)Bo44m=ASi`Wrcz4|3u#IdRw@1Y~ah!;5u6k^I0Svm5yXV$|D9SQq`oqqZzy zUGT{CkMUwo3dp>u-GFgOA#-yk7V}{gdVw6~%`%Jwm+;|Nv6$5k;??Kbc>426hH37? z8OB30%mV2JpSWCTJk~`ZnHR5$us^6knw_ky?Trc6n{so+)>;#7nHs(VU;lrIRcxI{SG}y7858m*b z_z-gwAI8`7Vc!7uY98Uksj>BZxX-+v4>iN<`7l2`u0?s0&QS?~LlpF433~B5I1EdYEi=W?q_Oa$H3K@Gx3gQH4*k$3kv;X_JB>QF^MOtn_kw9v$e9$-ayHaWN~v7>kOjg2)F86`|bb?HPWn%%|Fi}>2tGb~Nzhl7YNYV!vh#xfFO zvl46$nLBr}bW~baFrQc1vY4e+Rd(pmyodxGF3g-vDe}!wx#UhyPA+iP_9xUVRYkKl8j5=)be?2>{qgPM>#_UvgbzkJ z73TLZIt$(Ix{=YL>=fBVI${*c)tyko<&U>k1efhRoJss4GuJ-lnYY&DFJ`&IESbT= zz{2dfSYK>LGVTS+)q3c~hF0;}{_(Hhh#|VjFV)A2JU zAFasFvjGlb;A8^S(0k9-m+fEOea=UGk{g$1wJDvW-pm=J)Dc>{5G)FtPYz_;G*dR| zgnQBA^hk2RACN8>&Y>xE}D1cy|=OhV&ecZ7x|hleFkDb1ic^?@kvcrLxZMZppaKvY_Y~krZt^Y1!7v8UE+Z7`VFGU!9*v$ zHPiV)RrlEdZ?yFf?POjococ$~PD7o?+7%}+=$a0Rj%w)3DzbRp3t2+gvuHki+MA!C zahXmJ5I$6uhSs+N4ruQV2Tp$45$P&vw4F~RbF;5m7ZB~^mm(5JaqlrW7V#D8_ z+y2`%{?N-zFK!#umvCDZHf5if6WYa&TI&yqf9UEHJgInlBjH0#Tj%DMZq1}973WFX zC(mxY&TD4NFH^)Pzdm^4!4qdbJ@VL(-}*6{IJ8enEq@&aPVN#ApR}@q*=XVj0f%6i zS&O4#6$-ZbSU$-QPP;WW&0oQaD8X}+_J<#wz4p$jftpJr#2>QcnxWdBm~vG!&JXmw zcxlh4hh8tM`oKx%MQ(M{LRnQ{Nn;b|SVS@OLX7i6DAa(m9GlF|S?C2{P2~nPtnOLJ zqdEx=L%@elfmo&I;`~7GS(7A3)c_8C+Ef+2U(k0Llz(uxC}Lj;e{rs zff^|G(A%N}w26@HCpEy1Bl7-01l`I*m2UGLTcdvh4Uo+6(13wOotk}gp^~e9dq(&;Dd)+8s6ocV zFLVMQ+)%?afCI`f68H*3s;UvITb&q3bkPGfpqT}`p7C+Dh+J9WCI-FO2sO}q7VNy% z?cnx%RrCuOhh^dqR=@#jXyOuoc#F*LW~c#eD0xtWu_a9{NunnX&edIHUi3i?X~4 z`@{7hULYG@;`1@1mY^3X)0VHOTa;n|97f^;7`d&hoJ2@Quc+J9$%7i2p@t+k-Y;ZC z7pMkwe;9xobg;!EJ_G|NbMHES;Dx2)`^3Z_Dwt&j{n3GfkX|kziElv$sNp?!-gEcr zw;n45J|Jbur)F%GRq{N0axKT(l383Px6IaZGZ&bwj**(GKt5kAVnmDNE=z&WH#6$D zR@tJ8`&oQ;7t9W?%3EIKngS#_+ACzwLifp4RvQLCBzHMFKj3asmZ!;{6+rkvBT456 zBmcn1c|Ox=dhcd%lHC>;M{pEy7=T_x0uK9tlU48)<3tw-2mR-*|Di5DzU5hhLyOzm z%^B!!ZWk-6bIo4$xML>QGe7GJvzdbh3?qC+ab|hxNI``xsctmCAjvx0Q#PZ{O0_O6 zF4;Kd%YT05mbb1xv+t_ExjjzNH&&yYvrYOWRihP?fi_pWCT=1#F3MxFEJ_Qm9)9Az z`z{`QVf(}Pp1=0gE6rB7yt1axyqU>MC@S%9VupoB#MM(NR=?A+@!Bf~Kl}WLTkiYG zjz7H>J-(@~DyX;&>p}p!h+J_Ptc#dAtc&Re>@bBU%!j#djO3k@*rVwDpz7IE1oz34 z5|SSp9N7)%1^ON(ANps2hT`p^b+OTrtyr6@`&#bsfj>N#NNQjdO7f7ypqV8CP8L;N zZvubVL+e6h@5@J=MESu0y@*uZGXk7E*+6_UA=@;A_(12${YQTM($77yKWZR8>F`PC z0+;MO&PoabPL|@kJ@P2zv^wGsXl9|i9P&vtak7Ec=@f@E&`dLG)vM7x3f(7lFuUno zee0QPZ{6P$efu2A4?KN%c$#nCIqAds;a5>u-Lpg&$fFP^=^Q0Fy7TQ*%$JWB5}(v7 z_0@_#b4|It_{NSmzB>HkjdyS7wm0`m$2ZsYce+d|OBH^b#a23E@=IE?oORk!#0Pl~ zbBf1|mB{@A3DL|r@6A!fZODj*=gKtZvYp19UN=A6sx^0+dq?3K=F zpOPIOJe%sOD`oN~>SEX4NY~y5k=x&VBSkf=y^*3kxs!{LR6{pmW}RWQy_yEQ{}wz*qrf1vlQ<;W*f@4P?lL?X!#RG-=@;s$(|tJU*YAC$5$ zUdkmn6zG*pQlzYi@*5vM@a^3P-dleD!HbWmLd-QGfCF!IX{M*fynz)Z>+mCg&ulH!tq{RV_sQV~?Dq71lIz4cP-JfYC3yXP@+UEv5A=QV zSRZCJeV?=sU_Q|I$^L@%_eq@q`y_pzY`f_`dD@Ttfxb_^ZN|Ew?~@mTaGs>^lOZ!0 z2l_rK?_YnPT&%$UKd`*=dv??y|DELPfdmKMKxJz^Gpnav zn7N_N5!%d`F&g@<<5l$Zr|%D!N5eSc6Y^u(Bu5GKnx^LQzL}O*?m|UtKwe=dMdh<5 z+woW6EQjt=8*gl88E%EC|<_QsS4<${Q>RW52zR&N#?H(#;i<#zWBnn zLkIu)^0haAeqjGyd%wAQ?1@J)ALw~e^DeN6U{yt-p*1)rIJ$!+oyzu(%q-mGlgo+kFTXZ@ivMlt=N8S`I$((=p-?8Uwe%(5uav;4u;h0yDn5 z!)&|bnW9&_zxbPt%*`sQ+U8wqbNgx>cDAb2I?v!~i|xX|RPG%78s&AB6?qpd1$mMd zk{{?htw{37$;K-o$LT%GGHJ{7t8+Ypd2bH<8kHOvZ|iVbq~t4TR^tpqW_J!_u-H#; zi_M@5A@l;_Kr(IrdAO=Qlt52jyl2IcJXsHX&~+LNXUWDY1fT3AoJ21S0S*JO>zyR~ zCOtQ?y17Cw=%Uz-cRf@C{qG<6qz3q1FTB6eHj35F7q?8oC$4l)K2j*#fLS1he~Rgb)4T4>FrNQL(gI!vuJB1ex7+fP-P>>W()Q zbccz88jvo?zB#rZ-2Uc$6XAe1cNXYk?Y@cjEIr9E=miehH-B%(d9s)Af!@2>fI}dk zX0>f3g!n@=sR3rUUaIWaOlNyJXfp*o3f-enB8Ay)AA@e*A;9y3-m?%6XyS07hLki_ zi`_*3=LWUs2p7ioK8Aqv9b?(!D@0YyupnG*sGRE1nkv#2@IrTMspa!!@ao V?3+tO7sw}3hC%-(C#)?^{ohq(D%b!3 literal 0 HcmV?d00001 diff --git a/crmeb/basic/BaseUpload.php b/crmeb/basic/BaseUpload.php new file mode 100644 index 0000000000000000000000000000000000000000..12b46a41cd4e84fd1a59885a5b52bed13e247948 GIT binary patch literal 48176 zcmeFaXPA>!*ET%8mrODxnMtPi-g{4`CewTGz4y#aW=27!Sx^B{;TBO8DT;!M4G|j( z0wO9RRuCHqDk31_yH@tzlU#G-<9)x!_v8DH@A(M_>|DM#D- zN4f_38+r$tTH9KEeMTk*2724bABTPXTnC0-Tf5qPeM;1S@2bFmHjMwzwSQpLwX1(* zw5hkZt<}dh*tIabupy&B;g^t-EKDsc@vbTw>2}o<__xYE1Ohu}N5`JHi7_u9WpIYC zGTUt~D%rzJnLRb_)TviS<^V}7w^&9H0dm}aTY0ZL?Wp~ zl&J8Vd*pUJ;Zs3Azf-92?DW!03yP_96Q?@Moh0UE5*I;Qc7Z!D*PF*Hsm&0HMin+H zRkU%XWwg>iaWqm9z>^8ZLIqFa#IJ!9&feRtK0)L`PUzVbwc9ZHe>$O+o?rtf5E<}< zJ6y>Ljvzy(vqpvtDnsvKjSM$FAt;8)p#3Xs;8zsGuPB9IvH$YpzmQ*{IYFQ$gZ2qx z&_e_0p&In?$RjVFxxbz0p$ha60D9=X;jajaF{655GI%V|WX!xKi42vOh#q_$6`pEM z`rPPOkh`ec|y$lQw z)u0Fa#L-YyEWtyS6}ink_!Y$?Au*0r4?ljxMO4&}VINfYt5m25H$YTtWNW~Mm%csq zWdqSe2Vk-d@R0O3G86+ItN@d}fXU6jyt8ELj!`&)CvyT!@&QqqR1XV(1s_ly1$SWr zczEf|nH5}Aw+0B+sODnwKhXoT3k{;QQT_j(6ZX^+>(&81OxkFyJ0I*K(x|#1e*mq! zHJ~sPty`mq9=MA@yo*Z04@qDbIbauZu!}Odi-((uCU=+;%QE;P_LNnN<^+R8EpMJ$cRBL#WarG?NMU`b_{0VPj7nRPMyPyoiu`F}S_Q;bc!!>il zFn7)pJ-9v-`jS<|!e8;vcX8Q~;Gqg^vl0+xYDDZJANXMf+{IAbf9i2=Y*``jE1c8B zIg4Wm)0*UI?gBY#My-cv)`6u=M7Aj63^Vw-yu1P|uVHGUU4puyy^c*e9u z4}6M;Q?bNneQibV;^hj0hib432lN+~gsY>d-`s1z(Bu4f{16G4j8yv0K59<=MgISM z7mfMuyd1F2La@zxkm2@R;x{)&5;~Jc1{tE}2qt@M2_7~)Z}xm`l_rL{C7c^SI07CphOw{3D5%@(2WyH4%9E== z4~sw#jrBwi%^(Aw;2cNraAWKKXS+bZ>6oI>WTJ=t&&IuI*{6x4R#$LkP*AS!NhGn{F)`7@@&JN|S3nO>f*!nw zi5{Xs20wRk>TL%9Ni_I(w+Xfh@uWy>TCu*5aFm&+<}Of^s0Y;K!78GMn?Z(Lu+0Lv zixiOIN)F)%c|Fm?13xt1Y&5`FPNlju%H>HhXzLV%d;Y0NB^qGifEBnY@ARgX-hRc(#fCoO{;gw}168qO0qK9K1UMrd^iasx+y&RNh#pRX4CuSNz&4d2 zgZK-=50-qQhkYkvpU?2nP@HFkl%8!?Ho{hi+uJ^Wfg^pO42^dBYdEIX*Q{OQAg zmH|(A#f0F&(uc>ht;-PI{Ry!w#t*hj{vMP6i6+M(o-E36biV0pV%_t37GjdxCgyq< zzS3w?NPRcTFnkZ;ha&=thjXc~R@V?c;0ej6|1+N4Q9|%g4tC)sf_QQTi612D+cYmL zdz$Eh>-BDASzLcXeub076fjwomYetDtK&~s?JOsFkb-U63q_+B_Yj7OQL}w(fbvJ8ha3Njf99xmz+{!!F@I<~Il;nP za~J=F2b3Z57QzoV)e$`?MQw{!)#NTTzv7?oVz)WLg9F&6omaQl@}Eik!1%%AXAM7a zE$ctCizvWkF8Hjg_YuGO+MDDqgx1`<@B^O2n6`Bd(L>JN z*mWDxL*+ljlYjRsK74(}fd`MBhs^!koj-kj`rOm!?)!Gjr=x##HqGbc~I`qi$} zUtiqv^_OS&Jih}Gb^iP|sG^)%vGb?Ji{F7d%=i@1gEPdFc)|s7*hYh2zd!PBjK(hN zfFCZ|^#1Jm=#ta6;5XGC$01oIa_(-6n{99!ueZz6t#9<5m{GN~4fZ4@wHZ&irbT7; z1=iJ%W%j$w1dsMLHw8`)jRd-u&8TvRx+0^xM^#2GBNFR|)`@}&^MWpeO7q;&?#|K9 zaaYfjk$ip^_$-WRzll+1{~Y3f#!}7pg0z67f-&Ez;UU*3?~EF|ludv?>QVYU5 zjBBv2`HI0$UaNw;K(=p+NG+b8n|14RSEl7e_D`io`6NjvLezT5gS%jQcxMUGq=f1L z^G(!bFUYV^lX-xLXFoZAz7k@4jV9k&5(He`2Qt`03?l(Nu)8n_>Gyfr@+dGbJyA+gPsxr86;s0@~cRaJv4lDdbihx{zAf&FJ%%$Im2ycf(*}J`*n-ap^!VhO9>usQV@Qy zqk8zpp!fY{NAw>N>k{j3vnRGG13Vz21d((1oPToN1>baH7Y1&`U${^`T#**$UDCbh z+|%jAE~GS`45XNRBfxssru}bxS3W}QLKaK(U=MK=qWXHH!yh}`p7?zACc?D(Jfeq8 zdKZVk{Gtu~#oelpDOZORe}Q))02y5F`oqA*y?ayfIl>Q@GKd}|kY9Xu{@G7DR~>oO z!9{ej^;N=?XC}CIF{5}(1c-XneL1m;*jh zdhWL$-!1Oi;{-BbMCz5RU)1B8R^O6I`9Vtf!4vd=mK9`8{6#3lFsRAX?nDpHEGn*S zR`aB~7DWAK4aji+&)<8bzh<_w2JnCH?`2Gj^#^@8q5I)7!HZv}-;qrHMN6n^ZZxR5pZSYGR}DWP!{kvtG{djx zt7}Dq=9Q0rSc7cdW02#~#o#J6PuD?LPi87dg9s)sz^NvIh$Whu%8xDHVfru1i zT09|-#t+Q|l-Cs8va6dq8VhMQ5FHQCN*CU{V>KIN3)uSxW12hG^YX z2Gj%Q{^g*Dq>K^o2sLAnQf`=zdh$ijSs0K_H&Zy%_)B{=;`tERu<-TsZ zr4j0K>s{2SR(Lwf#{KYwYFd}WSnl~9pPhH4{=y$*kgB4sFIs8erY5GH1Q|q7;gnE4 z)KEOIXmAjIMTJPEx@t}Af@O#N>+=k})#Y(4+SZx1;Hj3uQ+^mJMm55;E9gu4313{D7oqbwxp1I0o1m1g34 zThFSo(7yih-l(pT=_FxxY_CDCbr9HQ9IeY?owf|_!gA&AOX>C{C#CA!RH@nqdJ_#& z{S(LFSCj)LyBcSoe*4|MN1^1awu{{2z6`*m``C1=T9bRrh$a~xREfe3`NISc$S{l_ z9@_Rufb4Y*KjheE=1=t|hcSL&)dMl$;Vp~2W$ZRF0$H7JBd&5Fd3U@zLm_v8h;j!! zlt66|>(zE}7rui7QKz=d^9|udh3PVD+Lcuja=l!d=896emuI`;v2WWrGol ze1U#qV{%VeIPn))Gq(U4Ocps_n?67G^DyOyoKl+#YZAl6wG2T$%7Wm*fb!&>Wn8;B zZbkSZm)gZ!?SyIVDLsl3kkIgjA`)%tWP389IPdN zGZ1(ZPxvm8*hMzwhww&X7eZt&CtP*A9RH;5yLU^eT{K6|bVtqj8}OM{|U{WGl zJT7aDxJ!rPAwAV=(9boid4@kd;uSTl3bs>rSY;cG#l-6iP?J~#sfW9`+vCoD@ZD>( zsa;GdlwPPw#*@Eq|0Cqsp8E4elqbu^qB=`Gv+IoOj3q=a3X+Mcc+l?UEi&%V3w&yD*Y-TCo@_dmAh z{=4S&a3Lc9Av?jI^F34#<9@QL;kn7!nc$wT=J*k5O;lpa;8ySWib-ynj)nS9Z%-w5PYKOUG-L z54OqT>XGyN4!y9=?k_`X7vh2B(ZZyD`+Q|qV4aE&%(MsHQqUru$%@D zGfU38S)cgsI?iAq!+d+-j-$_Qy86-mPi@$G>i6d^zx?HspFRk7!QzKBry~Z@&xPEX zLU~da*gY~3G%_?x^?-fe9*`ld+f#b+4b?}s)L$g$H_v${`HZP39+)0J-xe2h+vT#K z;;0^k11Uc`VCm$H)F-o^4>&m0zZf+ov9w8`?HgsK3ZaF_H&s;o(g3-HM=X*LPsPi99)Ddi&PpkMG!ZZOQh>R=lp^hp1y~ zw>`ZBWi`rI$E{VrLN>+)ZU0Q9GOQkkH#Q%EWiC47vL1-|ZCaf+AGca}@tM*S* z#CFA|Yx9HRSZL?KRo#2o{6m^e$6#t-ejAJJ8BZQdJXdCK7q}#q^5l_A8&7=y{LObg zyz!1z=y|dJfIJx*a`8*PUE5wO%9DAOSv+w>QbImgLcLY8SNz4${(E;x}1-!QZ#M(?u)4h#m@QEVm~;_d1YayZNz7z~pOwa2Lo? zBVBV|cmj)~4s}OOZh2I3_cZmJ>DfB6dV>^My@1y+NaP>`<~V2<=r^IFHM#}Z{)&)$!u`}PY{0s49%gw6IpJ>5L$Frw zpb&mVc!87TGg_BR2ivp-o@9N0703`Y7?Ai*B8eX)a2FWETm~7ML53!f!8pw&XG~1u zhvUEx>43=(XdD#^dXQSjOuZgU;)k{9vz!SgkstEmSA=U#c}0NV3;-FNC|5&0O5fMG z%7Vq!so*c{C?1eupcXV+4&6z2nrD&QbmuX5ak5M zWOx&gV*vib17z4pIm!(Dg$YlkWc;9@{=$^X05!3iP@Dsyc#wl_no>MqJPEZR@9m>` zHfyKZ2}BP|X&j{sco_8Tb~BTa6YiwGTM9B@MA`s)NRo&~hiw_t5{3~`zgY@*Q3`qp zawm9LN9}^?!4PD~uFMeCjS#!Yqw%CI=%ET^NCiBU2|9TjTuD4R33#}kOJX@h)F8-^ zAS|i1a3=9&CiNHOR|v&&(1VU6iRJKwHmV2aHzDU8SnAEQdA^3klk8V)VR0155F~N3 z-(XMt#UjANB=mV1KV*OmRWB0vV#zko{b zYy?yfMm<=jM)Xih^$-Di@B|t1gye)0z(X_0a6jk)Yvv_@hl=E{T;V%_=tSh$OPkb%{spcd3^=)zCimd#EedN@n@VHosK8Nf^BQGWOw@SvVm zQ(Lzy#gSKo6~!(W=2Dja|fo42M7uctRD(pywk={~b6A zPq-KGkWTLcHR%9&kQi24E~4>6JlI7x$iVav4KhSW+qk`vP7sB4x&2^S_3GQq5M=;A zbc{wCOH2sEL;@a&CJ7$+AcH7}%s*7ZUGQ2C=5|C3J%x2z#Dn*c%E3ow!K-Rdtd!aM zCvI~lJgEaRkP{T1ITQ~VM?Lc7VyyJOCZ}u`sYvIyLk5EkzMb7f9EfUZaVh}# zwwl#piiMNO8ODY~Q4RGIvcy)HZl15h6pkgAG|!HNg!K$M1~}E$+WRPdL~2c9-faOg zuwQY_njq>O6Jncx%o02>zd3gQkB@5C<$P)j9o=U%e$#dBo{O;_datp3GkYwhH8@1$ zHyuwt|BifEaW~61CreWeD;za()U$tmdq{Oo@|Zcbi^<@D+17;V@lnc?OI^A7=9z4Q zNmhRlco2SI`R3Vrf(KTA$fkI}`3K~v!3Fh)ss;6jrUmtf<<k^@kl}-1@_d zw!~ks`opGV!Vj$e@N*f_1FJubE~r23vLkq4^#^$e!2_$?zZbx*KdcJi)*qCygdZ3l zJ`ExK!0Hb>`w34nJaoGdeqi;7>*0hSSUu{e9&Y`C=fTB;k(`T%X}1Mcw6)V*JX|c`;$cGw zu}xNwx;n-k(fEcPaN z=mV}+Yf>lltYx!#8P*?AldMi#dQ+WI+4j;EQW`&mcguLv#+ts&%+y&?t+HGYt?cRY zEUWLX7*K1H)nNus*M!Br7Ivhb`pw2ni>f}FXJwh06lc}zmkdrsPdoLdsQo6(yMGSc z5OK+P@1t4NUl{ZF1(iv9DaHZg^^WNY^Yw?{lcuGv(7%vVeyBI==#$eJCJ+3@wZ?!{ z0WbG4JMdYkNnUldcPouyuzz8E)4OY4xF&wmn#EE5<-9q0wVvE5!>3YeWKv}&G0@h7 z)sBBX_}RgPT?(p)$VQo6F4cpjqAkNDthEs}iF1SKHyhSRCG0y2R{r14L_prX+Tu&+d3NpKheZ7d_=+>OE#;>brJQ?KCU8tKBRcOg4{J{D+Pg(C@ zbnjkGA15?+V0bdLf4+~y>QQErZ*?H=z9XE*lbLpTdC0WbzW~bh90omn0Fxw|42AFm z=DftR2u~8W*VJikp19(c`P=YX8O6g~?x0tndy|r|oTk6Ici`?hIN@3p*e2eEcc-6P zlQ{E_^@nr)Z-fBTz7|Y*GAAt)Zc`IS`6dNjj`(b1J>p4 zk6x1sCw%Bkc~Ur4$HBvA(|bmMX?Jx{JV?{Z)eOVxw9V-zkrH9gd0q9d$SxQuupi2C zEgWr*A$VYQ`wK0NI}dEoTgL-Epy$n;^~$zxoQfh|PlJa|tIq#h-`}paMnc$L6Hgv! z{ZarPXOk}F2ZckqS`VxqwYvS&3gF3$1?p(9(z4aFLv2~iE*eLw+k51RA2m|D$a6^- zrw5tL#8X5uf3eZ|i)G>0(rziDJeiv}={r+2@yM*q%>03TCt#C(?4@)c}d3 zFyBlA84wR>7m#<`%Arf^ox?H|q6c4U7lZIC+(3qZ(f1enAcF(Qz~aeFxXn2a8<~ve z-D&VER3O75kO6(x2*@H^T4;E_cR@dc{&&P<|FK4kz4&ljnDNpu+3{aQTe~!M-It_SG&R0=7g|VQA z;0%UpCkf6!n1T$+fCuDinAtNgwwak>i1GwXT7eA6lgJNHmvj2mOFvCO=N|~F1!*#> z2XD}W7s%i`Nlu6YJQ#osYe5hA{vsCc!o;iFjYfm1E&@ z5Y{JAlcgX7&IRewy4-WrE{N9?is9LpM8}@kCNfMN;2{odGZE~<1x~=a+>hQiFb%8W zhsqG=FZ4kMybGM4jCOGn{GqmPViysBNvuyIKXii(aeVpw>xr{~hw@K`wn#t^XF(4* z|L{4?KWwLXKz_JGiyvA+hLSwj`PVc#a2Lo?*vCPxhS{X)ZDPlHR0kp+0F!La9QeW2 z9;)sVI}Ik$^D;eHf((H&p>Q9aBNc*e{s1z>QhsQLUt#3nkQSUpEXzYn4=6(+$S~)@ z%lsMsBO>Y$=%Lp~!_}>z2Uo3G)(vnMJzy6qkOAlIksppmw$0b=SAZUr&Q%*KL56c6 z15ToT=3-vDnd0FD;Gq#@K%T@*%>!fzOCF0R)-6<|Q5n#0A||0OH)kZrX?cQ&bijir z$iV9MFeet?2Z)k~u@i`0dM2LKPYAOrFw%7AtISG4N(H-TN4Usjs2+%QJMqIoh6-9USDyei z^C*y^gvx;Ya7rYc=Lhtgt>HsY;k=wl9+}~6bX0hKp}tL#$L*kpN|0ea#X}7IitKvX z{It9Yl>z(yC;m!7VwD==-el=Z+~!)Bg{v|#ntx~S&7nz z{aftqq%xbre)G`Q*u?M_f@*wA%W@n<)Jt{5E|yvoe%L7{Jc;i&abB+R<=ak22l3uu z^(e_yt>2t|H+Y<&mLpzFx#4OchOj4MN-DYgh!|F+Oh6hm<(F3bTRdo=%VD+f# zQeqdZKKYi2+$NikVob~G_J+RXHrafXP9f0)t4|uV5Ja*1YKFp_${x*?We2(FhS%Fg>ea`_B@K4#q^SKS;|ISlbW6hC zo7!te`N6R*d8mr^{c{Y>OG>k>ib(vGH4{xlhtZ=x`Q;jI52aAu^t$k;6+I_QB4+`^K z#~i8$bDNMns|e>ZL=>yTSiI?6Tl#7LF18P(IIpP8p*B8=pjuOxd-`Z(?;V>A&zVub zX;ZB5bM8y2YpT_6suVZ7CcCO81%o4V{a)V6K$*1GU0gqr5pBq4Y|rMaf7x%|a%^AS zGt(dgT9$82OSRe1Sk+8NNTpdpWo5C6jx*nHa42@VVP<-`qbEBfr8PR#Nx-rLmUnjq z9_S3mP}#awJNd6C53IKS zC60PMd3l3DK}%tyi|wS!R4K`G$dRiVhT&oMVlB_{pxGNdiU-Sd_XfM}SRIyMu)5rP zI;N}mQ@OwCt62{E-KD-k9n(&MO&&vqfvSwo{1Q|339LT3t5y1dq)v3f8hjQqOkQ;s zPekWo%xzn%vsy4?)y#>xh?bq(dQf=Kp6bE2)k2kT**LF=j}E?<>p;)I{b)4_LQH8Q@*gz^U2{c=1R41;$Yr(=xw_anvf9e%$QAJz<6V zS7aA#1wBBXRk;;rFj#(3PTziD`J90!5?co{L} zXAhX)yb3&Nt`Lc3v<{<$Ur`M*Y^S!l3S_8q7Gw~%=ka;FX#DTmUbF#nsM$ zhbqdG=yBkUnEN1fVScCYvxwJ&`D)4!FF;%k^A91yG;#vwSvbpzb0EkM_ktc;VE)0w zk;D%K)fpll#ly#N7f^?Z^av#J!`;*_m>$-E42DpLDJUlKLnO6}DA0o?$nZGWMbM;w zT3iDCzPmC&fBpQrXPQhKIfecu;$6o<&27O8)Dn65mw@G3c zlwmRTn@d3tlOoZejPe8KS;$e09~OfQJh8&Fl)lemC-7-Jc@$)TI*h2E&PN>wJP=J1 zJS+nl%IItoBC3nZ5Ck%?I_*)Y(+X&wg>_owD6B`}35(%Zw7`7S-_>b906k!x_C>8a zt+ot{K@aheXOU>I+iMDBc;7JU+Zf6Z@QyWfKQGrO#E$R-VYy1n=jgAv9c1u?l@71b z{SRmtXq#+)@@B+CmiIg+?*>fXUh1-81oVLQD5%3EtPu;mzEI*b?f7e9a=pbjHGCevUN?E+=MySN4LVB{i@n$h>0A5eZ^cz70MnDf)r?O%&9 zTKb*Vdz?=HiP3?`t|?|0ydt89BFYbVo5di*Dv$x+PMUxw&jKb#K?W<3fyECI9`{dY zZVGZuUH0z27x!P-dHI)j4J)r5A4{5)n#sh4sTS!i^gT`_$bfM*i{(%c=EcOa zlsbeT^aaFUu=t_lM)@Z6+*v$Xc%ytXM3Zk$-YDM;(d3)e( zumPpeYfNHNVtf-!IHO&#{6aUMn_m{uxW+2j(}|Eyy>O@xeA6R`;DP0vADC$32h`-( zo!or$NlR|NY1PBcH+dPvE?B;4AH>Z!Yr?qs=C($n2R0w|q7gUW6jpNa(3H)^!wcgJ z@DRbp!;^F#W`yG5h=_}aH=7ARu=+!xh?{Rl`g8Nm&RpUzSp8w60~ZgkJ8<#vauyd4 zJXq|BC$Rd%)G&!3SpA_cn~R4o4=x@qs))Z}cu=&;7TG3~`~o$}`u_j7b0Fp4JElh- z8hVe_Ck-VwdFdwBp#eU9J=Rk1=&|7TDeL^spq|biwcliM^>>4}75$QMcoU1Ovn*Xi zEma04Jy`-n<8s^idekRXIT0C=ty}HDHc<~*RR-Ddz)`Fo^=s3N%pdx^Lh3i|`>Jzw zfvZ`*S@6#3Usl{cxnxjn-B7PCFOZ7+1LBNE;aurwQ06#ZGm%wVTiT#sVA3?M zYV)1*x691xthPrd&CHaa{fv$0~ znf_q8XH&3$aG(py!1~<}+8KMg$%N~0-X1M0vczaM7EWMuLH|^LNV@#ko;M$q{LW@L zovRXam>#NUY$Vn7c9qC5EblfxcJoK4pRj$qlKRc|h}k~xY#*~M7wKRPU!2-toT{#9 zF+5~1jUH&zs!y7ZS67(v9THid#p*CG{R=nL2@kS(a-8ac<=xA^ZK`Ydo4mU})O;`~ zNjZ#`#q#bSwuH8O|4rV_?+>drE2~OH85kZ`FMsU3LM!jKFSW`y8TS_x>(?=I-v&8XYyFSl%7`ukpM7Ht#l*SJw65W>-z#z2c^m$2ocTl*eqTVb^@#ed0@X zh4V1>7LjSY)KwG>9=z}3ed8J|JPfOE)Od)k6OJX&cZ)K6o>_yQ0B%#0ck6x|_OYL{ zV&4GBfS8<`bZv{OC}}ImlDg)|?Mlon2LaWZ_~GX-KfZbQt&)dqX!^9`y5h zF2B$o>j{uyJMAT*=Y1YzXwlmJ7zdaf0~zprH;b!35{u?DHH@pRK?bx7!=y{)pU*RJ$FS4U~ z_j14k=9^f5K)d)2^iT}52i0``fuOomm_hNd3-sU)dQi~3`=0p>g&^ud&_fX9yrFdd z!IIhq_IU$9hD9KQahkLAcgXz_559nhEwIar`3uy;2;|)@2_%l{RHK^xif*r+@GJCS z{sHd-PpF}GVN6fJ{wBQNv^YAaoh{l(wo<$J9AvPG5&8TAGZ^Z45@nd5X2}q32R#(d zzbYbqe?5@F60942H}p5Fm!$=mGkhX+w1W z0sDG0Aj4&vcYgzSQ8%WrBT-PaG99fO>>>_iK(2m37W)u6xJW`glm9@0LXcL===lYhaMU~JPtAp zgC5LjUG52L7vwgx3s!*)=1>#6mv%^>13U=8HgRt=`iqA_4?2zo{8uD|A7&^&Y*pW; zAng~Bp(vPVdn?_Gf_T6gj2}P`o{(>DM1Bwncx&i<)JDL=Cm@3*#lsWuE8>LN-p42& z&H}1=Aj28T4_lERWW4z;nvT>i5~v=qF2^r$w-M8KNy`8a=(DgsiJJTZenlfRseg0S zU=r^FWk5vjfV+UYocsWN8+9w#<~Fru5ltQjJtWLqH`GAXY_FGQ40^!bkMJ(Z{|gsE zD!EM_59gyIsSJ1m)aA@o(1pp@dY6Q6?VHusEl%A8GK|zo{;e*DJc(R=2mA`G%av0Z zKBacCoa*6mkOAH$Ra~VLR%U9iM{*oI;S|V#Z|wu=yG5Lj!bofz<%f-+2Scfo%PXJ< zMAR>UhYN5Qs0U=2JCGlye3M;c2p-k~9(uexo>fsjtU-Q&x||Ee!%{V>HT>{4$RLGz zx%cRN)a9?f-N`r#5w#on0c3ca*5w|dcEL`#1Ty64GgP+*ETwjVxj*(;Vg4ccFw93W zhC#cS0vWI-h8zWTxnLiN2CeA3q|<;0d;>B>_3$&uFa__D{`6!g5Ir!SybOAPx}0(y ztrdT~IzAv7WY7aWJP0y;2r>*o^?j`?juOwih4KUQ7Z>0zDxm5v zrSBGls9jLs{mE1CE9#-@&idUaKRx=E+c$?!x==mLcE>lGPR9!SHhFJ zlpin(8Uh(uez7L#l;0uKHLrJ3e&|q5O#6?BXDrKwvT3-B?Qj=7kUh&@jzWA02-~lxm8ROOfJ8GIb+w?BI`P^?0y}A3( zd;i>j_VPy;KHvO_G47}-b(Vt+*ym+$?GX<@xRHF*-k=6;3 zWPLsPJumNzcUC;g`n(0c{!_kQy14l~;j#P=Q6%+q?_U~f_{yoF)= zAGS}sdwx^*=>BxT1L|SOwWb(nn+N^J)w9hbK3}M#Ae`Al>pnP2^f3P}$&Db2<=xMu z5|6|3Zp%sHFXrno-Dus>#;gv5dl&HpwhyE=0i!_@%ORqq3-+QU84-S9b(oV2-X$$H z#$Ta{qs)_t$663MYDCeSbDji~Fn5Z*B-BdSG>!w<-x9Sl_>8 zlv{_{QCH%nf@MR#k4s#`u@Fc^7sV?CMR+n?1Ao&HW%gr_tj$(5lOX(&J zhKKhS)a5D%xOJFaPJ|!W9LR-f%nqFRtPYdj%&o&b(nR#Y-l@GD#>Im$kc)@nJT4x_ zCKlkKf{TZXQi2Cohq+zB#ls&-geTb?NZBA44~jbCFW4N2$q*M0#JUA(xW5`TS*}L4 zLNg~;#>K-=(_B0pawjLSIS}3y7Z3J)E*@%>Ts-vpbMf$lf{O>{aT=*zIL8w_u>CNf z(EZi(c=($=IY)P#bp=hXb5h@CK3}ghKy4SS{_uZWk1BXJ(KYm!*@K4EUu5WrohExt zjkDw?q5KNdc!7R@cwMt=YlcOY+T$>u{MqB1(ZxCsy@uc5KtyF*YN!b1F&j>i3%(LPW85D2^vm6T`Lo7j;fW)x}N)@dVYH zdAUn#%B(k^vU|#z#*;GZytLfV;zUJ`-K>$yAl5a^Q4p*@oZ9W@7aS-za;k9B<#*J2 zNr`o9{N~roUCehKk6WXlc*rQvFJN`KUaz)*k{AQNWNvVFCeeS&(;-8*)3$OfMZeUV zMPjTTrEl_$cv29)!+_yoSn8S7ojH;mmJ9Wv3Vmbabp4tDw+J7l!!*jk-X+~zS7y>> z8GSi~#t*WJVtXmv1*=bNwsn&`- zriXycw8`L53j@Rh>*JVx`r3i-{|b48z3)|#JV;6g8r;|e4A-?`4{apzsNSvP!#lAMx;m`vVD7; zU51lM{J`d677IRmdd#5r*EGrxfeFp!7IYrQyUoHe%Z~6Q)5E*HI|6dO#Cuu)qR3ES z(3-B%!@kjE`*Y)Czr|5Kq**Hz1r!gFS;q5q+Izfe-S+l+Z)bfRr#@M#fvZt$eu%@2 ztH;dzzM#X8t}OsP9K>(aAj8;BwyQ0R)#a>G)jWBa>0u!rjyn8wf93bDe`P}P5L+W0 zji>df97kJy#*=IgLJD3JD>3+ z+oP5E-trAbukQS&R?TwI-)zk0<;PSe)>>tb6gpKJF+I%BiN(J;1hwLq2Pq!vY_rl( zlWdRH^+oDQ^#h0p)MPv52V0tNVy=fWV80vr;S0cIk;Ku_l+M$tzY7DHoTYYg4D`^< zlLxc>f_Odr28U)3MytYR{sjm2dGRfb_8tr|u-ubw+!HY8MUS%`WPm*w*?-Yq^GVP{ zvy}L5^f>$ASERrc2b%-I`3H<)SYK}s{0f`{*+l!i0}u`3ewaHz23v@$KL$M*IrF97 zv^@FB(I6}ZjeNq?Fx3dOF}E+8CI%K&>YYOkj{&u>-{0v>89PhtcD+oxkwVRGOQ ztw)h4$cg_G$bb>Zd+;l~Jj62ld}3KUsn5c?9NNWVxQl$qH%(?p{6Kz%jfAhZZiVM2 z&;!(?JZk8BoIAAgEIi>Okf8(WQDQTKhY{*8?gl+rgAD6I22pBI%5QY$e;V-c>wNW~ zr1n0Lp#%1j&gl@#x=8JUuv|X>CHNIXLF6tlA}yhIQAF(m=Rp2|Igr2Gld~3Nz&$x< z=_CohL+L3cu^igwTcC$7I-`Y_)eflc1R2e6+k6o8fHkqJAVaB537z6lsp{3%?VnfyGGGh?@AaCm z@bl@EmtGpyqvAmZ#t-lwC&UK4-oiaO%K?+f4|@TVxF;u*^20{J19COi<&a_U{Y5p@ zf`S*!fiQouA7p?z5J{~aVcM%y53G9dCg7n2w%j~M-|JzWRy_Z@YBcgykRbx|DWWc&TzSql1%bu@rCIKFhqr{*G?5W|NoL<L=%?{-72Fc997(;CDb6KNQ^Hz1|Dz zUlDD*nD9fWJFQ1OP5mbFB%ZJjeg({lxtygkGy@*Anf4sW5CnSgpnJSys3tF~ty?ec z66gWy)j7;>?x%Lq0=9`Y5a0);u4VKjvu=E^=MFMp{DAxbb7Cf9VEcu0V)!lz`Qbj$ z1I~%vq-Oip0DOi3;;}OzsLC#Dx60tKM+(C8PIR;gkOR0aUP_2cnR>Z9b`C8^{^CV&>PPd zyhHs3&QI0>CU=7jh{@HUhYIf=pO@6PDNfyk`~WhrIk5wvhk7TQaVxDkF(w0^uoq+) zff-KL-|U*Zuxh*euDfig9^$gv$Lyl~R26n^>I%kpc7!KqC_gZ}SXEB&psPkTyG>1g z5z)nc-)*DdsZY2aWUvJpRG^3Ja2MgAhgh(S6`%*0Gfz{29)5tkXa_yG0v=d@^QF;q zf4wu(_2L-SLsM)zA9f}iy7ySVzh>u^!%Mf{@xb|?wq9L)Fns{`1;vL70zG?_qTXf` ztA?(WAijw_TbwMzw=mJM7EP+I5sz@E-sC)kboaLGf<8ao6`T+gU^g(;5gG5M*OFX1 zIU89HuW3qq6H4GNaF#WNauoWkpV>zALZXMb3W5i@8?jB6XZhY>Uy$dZrY>i6gMC4M zu#<$vlZiLj7gQ+G^MOrA$bU`n&5-+i}x#=32LAO13(@{xp}u)EwOG^hjE?Y)?vQVCvi24AK1G^_CCvO!M>o`1^a>; z7tBZ9x}XlTdBJ>CZ!NbDvl~8?fS6=;n0*N(mSg$Fy-nOY4C6_BV~%#Qp_N1+tSm0@m;1AgTZb{V=GI|63rPgR>M$1#2_D#d)TvQ|hxs~80=Et$F5uQ-j<;~@FsIr{ zT+QloJEbH;VRgB9F|ls;9%r_nTZhSyA-2itFog^D72j4#^uX$JKZX;($?CMdiCjGV zP|d}|(xC--Nao__Tjc=%-#7Y`pk#Kpt+7rA&C-NMBK z+uO{($C_}Ai-#oo%_df-Wn7KlQ$tOL-p|FuV%XJ#ConwxNWbC5@UZ0-E*`Gm%f-X> zce!|Qy_@(=R;NwA%Eg1nN-iEo_i^zs^*9#~?7LB{F4slBb;$U^ZzC5Etj~+z*F#P2 zxs{8D4Tp#xSe^FGXSsOb9U>Vkd#~5~7Z(qe4{`Zncpn!J^1WOxFdWawX|2{8w>VZdUPJh*RI!4WMokC$tic)J| zaao!)r8YYx(Z9OYu57F%PDhwi>Drj4nG^f<){i64zR}gJ?3D*5&H0`T9lX ze)gF|9iE{HGc6%)Qwl2!gS;q63|TxG98z`c!tL+x!dVn#7?TQ*0+%jZqZ~<7b760i zbD=D*syaf|Jr_mz0l)dk2ac)*j(Q8eP2+4tcoK77?6Lmccg$h_0lvV6Um9BY1+I6N z;0gcq4X>5};xD`)&%zV<&ycu!c9QTUd#6_LEq8xZy=+V!ndAGcT<{l_5LdqlGVF9G z@dJLR7`fVAE2bq(JD+F$+jqo}tN;C1-1tjmY|fm{U~CcYeeTezgndW4={I57{z>L9 z9*#Qh^wm$FKT$>f1>2h>zV^c5eJOu@rlal*2=ULR&g=H7_sD|A}f?0;b;_97GA6I`jitRn9Dzhrm?qB3Qb*U9(*o5Ek zLXXoO-lOjGvN_VclvS?|mv-KkN#p7UJ9&+blU2 zg!w+so11L5pLpk&my>86#;wsWy+F4zw#uSfeFCe~7Dav4ncsKlA-1pB#bi8FME9B3 zB&4=@H7Cd|`%C8g-L1}F8cRbDyv4q!R%SHWl-tnIl*3CM%5k*m%WcTepBM?5?_YfQ z-8#W<>zBWmMC0lr-IB37)6}qfsX(2%vwTx>N!=;_koiq}>NnZ^!|l7V(mT3~y<1GC zdSG~nw%7IOuGhcUkm8|f&a-%I)@R66H6e(d)bNATu;a+GhAMc&a z?^1t(i}f$w{jd{89#)#v^sRPRXLIg~rrjycp5EyQrE=PBbZ`c0K^T#i)A}U#aqwGaSf|Cv{37@Z7{a%! zrQb_pJgK7ma0Twdq`(634KD3o`9*AVa7N z$#GDV-Jl2Dd1wbRpznVCmv@X;B#uRqteNZ!!fzdF?+f}0s?7`ciLw2YC*fD%KCz8- z<4`B?1JyypusylhdS`9MX1~LqJ z>gBvf-_qi~pg-rQqj|iSL56Vn2wfE2^S@<5{ICap1pq>=Ro! zPrCu^0{!N9AOp_R-a*6ESk?DoQagNa}l?7OrO4G#Li6vssel6RAAvC{Gq<%e%T4-lq` z1e71PfF^Mk1^YM{KYRx=ghKyf;hz5ruuWu`yFmur^IuNqX|Ji-p2RSC!gbJt$^0wz zl3MI1KP(44lzhxIp~1U&R; za}>No>4I5z6F#ZSJqCEdZ;_Z%esBcK8sX)6_ES7~QM(}44Rgit_8}X#iM~SLxnBl6 z@IVIC10sqKlLKXrU5*>+PBWahpH*8HIl&D!NF?%0YIW&%NFM_{Sb_}LW5pB1;CXT0 zo_&WDd(Fi25`Uq9&R~(&`-_W|9~?ji#t&}-KaALsJPUb}`EESH4*X^u;NdfSf`_wU zo8utEZEEXo4X}p|5-@Ks`iOpu1mELm^Mey`HS)v4`G@Z)KQzOpKAeBJOy?hv9~Qw^ zU0$FaF-zz*$7=Bd_Wh9`CO`(p4>`aOUUC+JXl4&k4-(*Nc;}vWYYwrCUjYwwa02wy z;Dl&pAlN3v52+v0_~ANW5`8!FBx+I!lLOe_T(}40b{ao~LT3=??HAEa8t6BJ0F$T( zJi!q>ua3y9;v${5N4r277{k=V7j|@$fgk95oTtGqOhJa*K?Xd*879?X{=wyY$`4<| zT~vZ?{zgv-gU(>kR6ueVowr{Kwpj-<$Uz1?!5?0-VEn-5?JrZiAh)TonTB37&fAk{ zkSDu|+J!OI1I7=3K>XmLwFiUMNby%>zy^sR(BvPpSMhFVHr%;|CsW>cjZqWjg=B;)jPRKV-n<0K^Xw7wG&0#t$C=Ciw!wlM0x1@0fp0 z5P$_e|05ku{FlZO= zf(%R#z_$E0cnk9ioqu=%WXJ;<4p5Hr1%5CW7S}&ccrSjF1!bV$V>K96%}pdWbqZHm z5xZE}=e>Fp!2|p5B)Lt^ynV|LhQe&Ed3%|xF1^#uS^gC00cZAbj`TX@az1bAR| zxtUL#PM5Ecoou9bq1EU8;=Wb$ecsC(uWo<;iQkTI`EA$57k*nKfE^UIwPGLPOof@e zs5FaLHR(T>mL(UR6WD;PV5w0gciERh4uD0 z_6}NERm{@w^Exp+;QlD~jX&gv7{J4fmcKZ0Gtooc3c@f}t4Uoh@G){iK6}hkSz+8a-6rU=M~;qL~|9b%Q+^gMOO1!B=ju2cynU)AwJw z_w0i?PUau7d3#a5r&~LGi-gr-KD^_N&C2-EU2G3V`dEm^v>V}S8R+4znyiQ3DA=*c zh}uO4d|{_im6+r0;`a3})R1_R^?9cZslTA{L&g$rU#|%g0X%`dzc_79;s@5} zUD(%qX^g}Vtk3&w9Ki$Y>z&<3@WAHnH{3+ z;h|_jpZ5uU5(Tk7@6k|V7p%|gyq=4P)Q`A$*tC5C9(uWWNbIKZ1Lf+?kf`Dbtj~Mm zQyM=|+jKg?#lz@wE*=Vtxp+A7Di;s8CUEhvuwI?GgNuhZUL`!q`u;l)aq+Nz5f=}) zKgGqv;4NG{)ZEO)L&9Dz9$wtQ#lxjLxp=t#F&7WQJGgi-`i6@K>0Mkrw5D+JKyEWb zBmu5QO}fH2#PI}%hh+=;ybsrM@$ljR7Z3RlaPhGFeJ&op*}}!chNE0O^nT67gXuNjU0OwLeQk_ceYbAv zlyAMX8$6EYo!Z9PW#bPgzy2G(b4Nt^hBg(6WXkfQp2$A$R>}PPi-#l39cG|^f$#lM zlj%A|SyjLftbg%WSZK*8eD?vrcYvDgj%aN6hWLTKL$UZT_i+BVdr`)ZH|zEPo^vvf z#?@mL{M><%Rsi|?V_)vDL-VHN%*X8A23tYX=K zRi~O2#5BMZGL5TQ|Ds3rkZL&B?FxIp>8fzy83=R(%!Xak6N2XoWDaw|y(XEN=3=i9 zl!3j!_^0m|8_5m?D(`Y;ky1s8O6hxZ{u{( zRJ0XgIZZ!n?bLh2UPtsF!C7}?nCbC3PhoJmlJNtx3q9k#pV&E@d^}F=BCWbW>PYP( z)yl0a)1UAI+ZUvCe0fPoc*v_26c6pG7PZavyHUmFw&__JgdbQxYwGOsl!8p>11x?p zGwZ6c7}dPTu{2ma(bEyV6~8lxOq*S$kfhFkC#Y>kk>jaG6x&DI9Cs$g=5O|q#&q|L z)WeuCG7RhMwJHo|AN*GI2>Xs$eNK(Ot$1QSu5Mj2`d#o;^b!_7gpJ80(qauB!agoO zS(p{{Jo6Xz<~ffAK}`HpO?N%+Btf1WD{vTV@*5l`ET`$~g%58L3LnvYA15WtW=0sZGYc6vhZ0&SR=_jbx@Z{G8>jv_)?4rqM zVnD1{rnk^8f(w@Cf((zay=s%=P3lOD@LdwlsPtfbaD%rrilL;5XgOp#D%V6pp*oO`dDOHt{<_IA@N(LKo|kj(OgTY5xMhckm$n z_5?;Cg;0M`(p^31d6j?%50GI1WMKV^n-}yi1R#TU|KivU`WHiLmQ&~c>iz}W(~Iv8 z_#gx0$x>Q>u%_>`a9?pJ$bfU^Sf4b6`a_x6Y5t2U@icz0rZV6j&U)Cx$!g|e@E7jD zQCJ(q+l23-c<6xF`-{H6AW^Z%<7MhEbfEq)THtP*PWOSlKy!Z+Y8R7GpKKHg|7}k% z?g~cRw1@g6?&)o#{Y_S%B)93G*af`nhUUECm^GuNv;a#P1aI<&N_mv0=cZ z70AHqF!()`JYc!p1>ZwyrFt*{%YyHr%=b4d0F(Y8!|U)X(05lueNwx>IY{d;10Vy| zX|X=JazTI72xQRiZ|2>gzxfj72L;sSwELT{fF`x;lPR=5xv;@ELuWZ1ULcTU+e=tOksU; zJWsHi?kqyPxJ7GsQwQ)vhqnd~djOM|sYL=Nv4?{FO&92I4r%QR!Wj(aFT#)?;4W5p z5WiWwH1cd1oPc`x5@cw^`edz4^5!sM+RI=Ux*)?vIN=kxiv;Xn*msFf%;_Ue0LJQRRp%_2)4=gk>dB%3SgRL;htX918TAv_yPCyno>-j1b!H!{D8kA z9P5)JN8aOfS1{HmtLC@6NL=EeK507twIk8!Dry%(4L`J;fLLlFKOj${CZj1ouz2zc zVDc=;0B@_+C*YpmN$A1^FWBS#0_6u+!VlEC$-70=q#@|xEjR(*XB{)h)O^Pr=O55E zMZgcXV4Kk2++ruONxcqtfinCGcJTz20THE({fiKO=3e?uw`8yjd>bXAJQ=0t2N#!% zw1={i@&ogm66jwHXyF0v;Ng62R)FX z6?zArbpC;4&4eG2qe?&q{Eqnr=%FAU)&eGRXHh@MfEA1&=q2d|2OjzPGHnxy3-8%7bReui`2JSQageCAW+RVnG=42RKZ?4tqU&uiQj2{qD9vDA3 ziN>8IB<~*A(gS)NU*rdo!uvo?Xi#a1{s!uZNk36 zbF)0nzCpAL?4e|X3@?Fg;v}j8zo_mF+P_!>b}M)}JE-LK zAj4;1n>fpA>B)m%L3|eS1Io|~dUzRpH~F5LNN`x|{boJLa3|$SZ;)Y!*7ww2rg79P z)dR#2E#o)f2NpjBP<}Y56+gs)4ErfR6oU-Qg`)ft$`5FpEXP5HNdn6a+G_N0*PlltAhv(Zmg>Q6)=Y%4-1rBCA6UKGskrgk*$z#wndKL;$8P21 z7jqI<^}9tEI{$z%Ek@>S{=pLXAw4ZHrIPOXXK^*!CeAh+AU^;m*7-| zk7GCypN5+3TSxGq4|c)0dIa#m_JJI0etYh1*;}ie;VzITW1_<|!;%uh`(v}OpLpcX zf9=||`jtN)dN~(f9VP|LB{ej8CdU7t#;(Mv={t)PD9W)M$|2#9aG3zbaD;G04J06J zA`qe&5NHUXA*4VO0tCX*R*PMAXKBHqc5&zyP^+_oTWx2syX)4f<4o&RU01j5bgEr- z_GqW8Zdn)WeqX-d2O;Cm>_5Q#czN%AKHv9wM|rlAvxXrK)T4ZP%0^*vqr;=H9(Chq%kT5{bn6^( zfqlhKCO35n4!yHS!hTJ^Tkj2HWCa-YA3S!C5riJ0_Q+sb7nixELX3$Lb%LU6hsm~c~#+(LA-T>d= zXD@>-oGZA`w;c4rogp+1)fXws6OQdF2SrxoMY`vZKa6g zQn%N*?BRsi1k5S`UQMtY{b8VQL_zZ8xEJ#WnKsv9N!*JfyZ@G@LYVhh#_W)_Gj9!v z?)2hxJK3gygRC zqgM+Vk7|mqlG#g*$-U`%YDvz{`y!&D;5*BY&37Y@g18{u{&oT74~z5N`zF2}&G>lF zXejXqU?3^7M!7gGv%>DT{Epbv`w#aTga0`EKkp3APL2NX${4!-l=>Hp)-AoNF# zR@2@jKpg0YxviydJ;)E&GAVyReG{fg;J1J}3~(6mNm2_UY>;%^eF3Z(nEA7(X&_f0 zY^Hf~EwjVr6MJH`Pb(*rGAR0ASJC%H5Q~eCSN0G7F!#cn+)T>Mk492U8kj%a$sTGY z^{BB03B^r}i@>V5ip$$0zfZ(0m%&|~(8tZx)Mq&u2=?2jw|qLyZTjL@RmiKOGH}Lx z=GC_!Ub=F8eD=hV-z{3wCrZxG8IW_;ViFg=sjXSW4iK9-cksFJlfy<)@sAy9))`Mp)`tmsCQS+Qa*|O4}*{C`vUtPp1ef)1J>nc{!Q(G{SW7B0sTq8 z9ODm~KIhoqzxw$l5B0==W zJgHQD&f$MF@&Nm*OM*%?H81)kB~-cX0*}Ien5jgqC0F$3-fG4l&fNIR!kK@*JM^Ei z1G8sOkBtBP0QCo)zwo$g3ut=ebqwF##Xe;v<%xA0<>5hb*1BqanS1`~_4fLxO-%s~ zJK#J{?Toi?+PG!d&4K>Pcu8YrNT;IOT@g{pSE?f-3j8<$aY@y-oQj5J{Na>jeC@gT zBcI{k=0cTH9ZlZ;^c6&!!tATIb8tCC4 zW@@*aZLv0ip(8h0W96$fMV72W_P)Tn{f&-myFaQubrJ6jM*Hv3<*K%FtG2Dt=XG@R zgq_JL2{x;R*Hhb^RIUzbOVW7uR2T%*tC#eP+HVRJ#!J2P+nGOTbNcl{cJH9fouih! z)zoPz!@zq_+0s$EqTW!_j?mEvD#TIAJtK7E}t-MnukjlH`?y&FpcHrK@|d*cZdt*liJqrzHAz9S)5a=&yZI14)n*o z7~7rSENbo1X7V@4x|ZhDGZ(t-GY3r#cof7YdE+!ZB$Zy*{z>RF zhYS-+z5)6tQNMt>1E_(FGyXtMXa#nY`HOfb9tHYE2f+)7%}DYMK922h6ffZ30bmxs zvta%L?lrsKI{-TXhY2Cy;C$}@^ottC?ctqONd61Bcd(o37wya+XtocOhmvooBV3MV zdqYAvtIMH=0{TV1i+-_=c$Bk#(eMoY0_QLM$Txs~G3m5FO5*elU-^=% +// +---------------------------------------------------------------------- + + +namespace crmeb\exceptions; + + +use think\exception\HttpResponseException; + +class AuthException extends HttpResponseException +{ + public function __construct($message, $code = 40000) + { + parent::__construct(app('json')->make($code, $message)); + } +} diff --git a/crmeb/exceptions/SmsException.php b/crmeb/exceptions/SmsException.php new file mode 100644 index 00000000..6c8f361b --- /dev/null +++ b/crmeb/exceptions/SmsException.php @@ -0,0 +1,22 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\exceptions; + + +use Throwable; + +class SmsException extends \Exception +{ + +} diff --git a/crmeb/exceptions/UploadException.php b/crmeb/exceptions/UploadException.php new file mode 100644 index 00000000..f8ee7b3d --- /dev/null +++ b/crmeb/exceptions/UploadException.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + + +namespace crmeb\exceptions; + + +use Throwable; + +/** + * Class AuthException + * @package crmeb\exceptions + */ +class UploadException extends \RuntimeException +{ + public function __construct($message = "", $code = 0, Throwable $previous = null) + { + if (is_array($message)) { + $errInfo = $message; + $message = $errInfo[1] ?? '未知错误'; + $code = $errInfo[0] ?? 400; + } + + parent::__construct($message, $code, $previous); + } +} diff --git a/crmeb/exceptions/UploadFailException.php b/crmeb/exceptions/UploadFailException.php new file mode 100644 index 00000000..5a93fb6d --- /dev/null +++ b/crmeb/exceptions/UploadFailException.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\exceptions; + + +use think\exception\HttpResponseException; + +class UploadFailException extends HttpResponseException +{ + + public function __construct($message = '附件上传失败') + { + parent::__construct(app('json')->fail($message)); + } +} diff --git a/crmeb/exceptions/WechatException.php b/crmeb/exceptions/WechatException.php new file mode 100644 index 00000000..d7214cf3 --- /dev/null +++ b/crmeb/exceptions/WechatException.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\exceptions; + + +use think\exception\HttpResponseException; +use think\exception\ValidateException; +use think\Response; + +class WechatException extends ValidateException +{ +} diff --git a/crmeb/interfaces/DeliveryInterface.php b/crmeb/interfaces/DeliveryInterface.php new file mode 100644 index 00000000..1efcec52 --- /dev/null +++ b/crmeb/interfaces/DeliveryInterface.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\interfaces; + + +interface DeliveryInterface +{ + # public function __construct($config); + public function addMerchant($data); //注册商户 + public function addShop($data); //创建门店 + public function updateShop($data); //更新门店 + public function addOrder($data); //发布订单 + public function getOrderPrice($data); //计算订单价格 + public function getOrderDetail($data); //获取订单详情 + public function cancelOrder($data); //取消订单 + public function getRecharge($data); //获取充值地址 + public function getBalance($data); //获取余额 + public function addTip($data); //支付小费 + public function getCity($data); //获取城市信息 +} diff --git a/crmeb/interfaces/JobInterface.php b/crmeb/interfaces/JobInterface.php new file mode 100644 index 00000000..04d1a0ff --- /dev/null +++ b/crmeb/interfaces/JobInterface.php @@ -0,0 +1,22 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\interfaces; + + +interface JobInterface +{ + public function fire($job, $data); + + public function failed($data); +} diff --git a/crmeb/interfaces/ListenerInterface.php b/crmeb/interfaces/ListenerInterface.php new file mode 100644 index 00000000..76e5b187 --- /dev/null +++ b/crmeb/interfaces/ListenerInterface.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- + + + +namespace crmeb\interfaces; + + +interface ListenerInterface +{ + public function handle($event): void; +} diff --git a/crmeb/interfaces/MiddlewareInterface.php b/crmeb/interfaces/MiddlewareInterface.php new file mode 100644 index 00000000..f12ba301 --- /dev/null +++ b/crmeb/interfaces/MiddlewareInterface.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- + + + +namespace crmeb\interfaces; + + +use app\Request; +use think\Response; + +interface MiddlewareInterface +{ + public function handle(Request $request, \Closure $next): Response; +} diff --git a/crmeb/interfaces/RouteParserInterface.php b/crmeb/interfaces/RouteParserInterface.php new file mode 100644 index 00000000..92576d31 --- /dev/null +++ b/crmeb/interfaces/RouteParserInterface.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\interfaces; + + +interface RouteParserInterface +{ + public function create($rule, $params); + +} diff --git a/crmeb/interfaces/VersionUpdateInterface.php b/crmeb/interfaces/VersionUpdateInterface.php new file mode 100644 index 00000000..511fa0cf --- /dev/null +++ b/crmeb/interfaces/VersionUpdateInterface.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\interfaces; + + +use think\console\Input; +use think\console\Output; + +interface VersionUpdateInterface +{ + public function __construct(Input $input, Output $output); + + public function autoUpdateStart(); + + public function autoUpdateBefore(); + + public function autoSqlBefore(); + + public function autoSqlAfter(); + + public function autoCopyBefore(); + + public function autoCopyAfter(); + + public function autoUpdateAfter(); + + public function autoUpdateEnd(); + + public function autoUpdateFail(\Throwable $e); +} diff --git a/crmeb/jobs/ApplyBroadcastGoodsJob.php b/crmeb/jobs/ApplyBroadcastGoodsJob.php new file mode 100644 index 00000000..c858a8c9 --- /dev/null +++ b/crmeb/jobs/ApplyBroadcastGoodsJob.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\broadcast\BroadcastGoodsRepository; +use crmeb\interfaces\JobInterface; +use crmeb\services\YunxinSmsService; +use think\facade\Log; + +class ApplyBroadcastGoodsJob implements JobInterface +{ + + public function fire($job, $goodsId) + { + $broadcastRoomGoodsRepository = app()->make(BroadcastGoodsRepository::class); + $goods = $broadcastRoomGoodsRepository->get($goodsId); + if ($goods) { + try { + $res = $broadcastRoomGoodsRepository->wxCreate($goods); + } catch (\Exception $e) { + $goods->error_msg = $e->getMessage(); + $goods->status = -1; + } + if (isset($res)) { + $goods->goods_id = $res->goodsId; + $goods->audit_id = $res->auditId; + $goods->status = 1; + } + $goods->save(); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/AutoChangeStatusActivityJob.php b/crmeb/jobs/AutoChangeStatusActivityJob.php new file mode 100644 index 00000000..3d1fb85d --- /dev/null +++ b/crmeb/jobs/AutoChangeStatusActivityJob.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\StoreActivityRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; +use app\common\repositories\store\product\ProductRepository; + +class AutoChangeStatusActivityJob implements JobInterface +{ + + public function fire($job, $data) + { + $make = app()->make(StoreActivityRepository::class); + $make->getsearch(['is_status' => 1])->chunk(100,function($list){ + foreach ($list as $item) { + try{ + if (strtotime($item['end_time']) <= time()) { + $item->is_show = 0; + $item->status = -1; + $item->save(); + } else if (!$item['status'] && strtotime($item['start_time']) <= time()) { + $item->is_show = 1; + $item->status = 1; + $item->save(); + } + }catch (\Exception $exception){ + Log::info('自动同步活动状态失败:'.$exception->getMessage()); + } + } + }); + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/AutoUserPosterJob.php b/crmeb/jobs/AutoUserPosterJob.php new file mode 100644 index 00000000..802edd3f --- /dev/null +++ b/crmeb/jobs/AutoUserPosterJob.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; + +class AutoUserPosterJob implements JobInterface +{ + public function fire($job, $uid) + { + $userRepository = app()->make(UserRepository::class); + $user = $userRepository->get($uid); + if (!$user) + $job->delete(); + try { + $userRepository->routineSpreadImage($user); + } catch (\Exception $e) { + }; + try { + $userRepository->wxSpreadImage($user); + } catch (\Exception $e) { + }; + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/BatchDeliveryJob.php b/crmeb/jobs/BatchDeliveryJob.php new file mode 100644 index 00000000..82559bc6 --- /dev/null +++ b/crmeb/jobs/BatchDeliveryJob.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class BatchDeliveryJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(StoreOrderRepository::class)->batchDelivery($data['mer_id'],$data['data']); + $job->delete(); + }catch (\Exception $exception){ + Log::info(var_export($exception, 1)); + } + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/CancelGroupBuyingJob.php b/crmeb/jobs/CancelGroupBuyingJob.php new file mode 100644 index 00000000..7910cd0b --- /dev/null +++ b/crmeb/jobs/CancelGroupBuyingJob.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\order\StoreRefundOrderRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class CancelGroupBuyingJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + //TODO 关闭子团,自动退款,关闭订单 + $make = app()->make(StoreRefundOrderRepository::class); + $make->autoRefundOrder($data['order_id'], 1, $data['message']); + $job->delete(); + }catch (\Exception $exception){ + Log::info(var_export($exception, 1)); + } + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/CancelGroupOrderJob.php b/crmeb/jobs/CancelGroupOrderJob.php new file mode 100644 index 00000000..483675c2 --- /dev/null +++ b/crmeb/jobs/CancelGroupOrderJob.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\product\ProductAttrValueRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\StoreDiscountRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Db; +use think\facade\Log; + +class CancelGroupOrderJob implements JobInterface +{ + + public function fire($job, $groupOrderId) + { + $groupOrderRepository = app()->make(StoreGroupOrderRepository::class); + $groupOrder = $groupOrderRepository->getCancelDetail($groupOrderId); + if (!$groupOrder) return $job->delete(); + Db::transaction(function () use ($groupOrder) { + $couponId = $groupOrder->coupon_id ? [$groupOrder->coupon_id] : []; + $productRepository = app()->make(ProductRepository::class); + foreach ($groupOrder->orderList as $order) { + if ($order->coupon_id) + $couponId = array_merge($couponId, explode(',', $order->coupon_id)); + foreach ($order->orderProduct as $cart) { + $productRepository->orderProductIncStock($order, $cart); + } + if ($order->activity_type == 10) { + app()->make(StoreDiscountRepository::class)->incStock($order->orderProduct[0]['activity_id']); + } + } + if (count($couponId)) { + app()->make(StoreCouponUserRepository::class)->updates($couponId, ['status' => 0]); + } + }); + return $job->delete(); + } + + public function failed($data) + { + Log::info('取消订单执行失败:' . var_export($data, true)); + } +} diff --git a/crmeb/jobs/ChangeMerchantStatusJob.php b/crmeb/jobs/ChangeMerchantStatusJob.php new file mode 100644 index 00000000..27b7c36c --- /dev/null +++ b/crmeb/jobs/ChangeMerchantStatusJob.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; + +class ChangeMerchantStatusJob implements JobInterface +{ + + public function fire($job, $merId) + { + $merchant = app()->make(MerchantRepository::class)->get($merId); + if ($merchant) { + $where = [ + 'mer_status' => ($merchant['is_del'] || !$merchant['mer_state'] || !$merchant['status']) ? 0 : 1 + ]; + app()->make(ProductRepository::class)->changeMerchantProduct($merId, $where); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ChangeSpuStatusJob.php b/crmeb/jobs/ChangeSpuStatusJob.php new file mode 100644 index 00000000..1b58d5c9 --- /dev/null +++ b/crmeb/jobs/ChangeSpuStatusJob.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\product\SpuRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class ChangeSpuStatusJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + $make = app()->make(SpuRepository::class); + if (is_array($data['id'])){ + foreach ($data['id'] as $i) { + $make->changeStatus($i,$data['product_type']); + } + } else if(is_numeric($data['id'])){ + $make->changeStatus($data['id'],$data['product_type']); + } + }catch (\Exception $exception){ + Log::info($exception->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/CheckProductExtensionJob.php b/crmeb/jobs/CheckProductExtensionJob.php new file mode 100644 index 00000000..b8c238b6 --- /dev/null +++ b/crmeb/jobs/CheckProductExtensionJob.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; +use app\common\repositories\store\product\ProductRepository; + +class CheckProductExtensionJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(ProductRepository::class)->checkProductByExtension(); + $job->delete(); + }catch (\Exception $exception){ + Log::info(var_export($exception, 1)); + } + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/CheckProductPresellJob.php b/crmeb/jobs/CheckProductPresellJob.php new file mode 100644 index 00000000..4e84acc4 --- /dev/null +++ b/crmeb/jobs/CheckProductPresellJob.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\product\ProductPresellRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; + +class CheckProductPresellJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + $make = app()->make(ProductPresellRepository::class); + $make->checkStatus(null); + }catch (\Exception $exception){ + Log::info($exception->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ClearCacheJob.php b/crmeb/jobs/ClearCacheJob.php new file mode 100644 index 00000000..f4a8cc00 --- /dev/null +++ b/crmeb/jobs/ClearCacheJob.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\system\CacheRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class ClearCacheJob implements JobInterface +{ + public function fire($job, $type) + { + $make = app()->make(CacheRepository::class); + try { + $make->clearCacheAll($type); + } catch (\Exception $e) { + Log::INFO('清除缓存失败:'.$type); + }; + + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ClearMerchantStoreJob.php b/crmeb/jobs/ClearMerchantStoreJob.php new file mode 100644 index 00000000..5a36869b --- /dev/null +++ b/crmeb/jobs/ClearMerchantStoreJob.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\product\ProductRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class ClearMerchantStoreJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(ProductRepository::class)->clearMerchantProduct((int)$data['mer_id']); + }catch (\Exception $e){ + Log::info('商户ID:'.$data['mer_id'].'清除出错'); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ClearUserIntegralJob.php b/crmeb/jobs/ClearUserIntegralJob.php new file mode 100644 index 00000000..836fb92b --- /dev/null +++ b/crmeb/jobs/ClearUserIntegralJob.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Db; +use think\facade\Log; + +class ClearUserIntegralJob implements JobInterface +{ + + public function fire($job, $data) + { + try { + $user = app()->make(UserRepository::class)->get($data['uid']); + if ($user && $user->integral > 0) { + $validIntegral = app()->make(UserBillRepository::class)->validIntegral($data['uid'], $data['startTime'], $data['endTime']); + if ($user->integral > $validIntegral) { + $clear = bcsub($user->integral, $validIntegral, 0); + $user->integral = $validIntegral; + app()->make(UserBillRepository::class)->decBill($user->uid, 'integral', 'timeout', [ + 'link_id' => 0, + 'status' => 1, + 'title' => '积分过期', + 'number' => $clear, + 'mark' => $clear . '积分已过期', + 'balance' => $user->integral + ]); + $user->save(); + } + } + } catch (\Exception $e) { + Log::info('用户ID:' . $data['uid'] . '积分清理失败'); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/CloseSvipCouponJob.php b/crmeb/jobs/CloseSvipCouponJob.php new file mode 100644 index 00000000..313ed62a --- /dev/null +++ b/crmeb/jobs/CloseSvipCouponJob.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class CloseSvipCouponJob implements JobInterface +{ + public function fire($job, $type) + { + $meka = app()->make(StoreCouponRepository::class); + try { + $couponIds = $meka->validCouponQuery(null,StoreCouponRepository::GET_COUPON_TYPE_SVIP)->column('coupon_id'); + app()->make(StoreCouponUserRepository::class)->getSearch([])->whereIn('coupon_id',$couponIds)->update(['status' => 2]); + } catch (\Exception $e) { + Log::INFO('付费会员优惠券过期操作失败:'.implode(',',$couponIds)); + }; + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/CloseUserSvipJob.php b/crmeb/jobs/CloseUserSvipJob.php new file mode 100644 index 00000000..95b926a7 --- /dev/null +++ b/crmeb/jobs/CloseUserSvipJob.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\system\CacheRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class CloseUserSvipJob implements JobInterface +{ + public function fire($job, $type) + { + $make = app()->make(UserRepository::class); + try { + $uids = $make->search(['is_svip' => 1])->whereTime('svip_endtime','<=',time())->column('User.uid'); + $make->updates($uids,['is_svip' => 0]); + } catch (\Exception $e) { + Log::INFO('关闭付费会员失败:'.implode(',',$uids)); + }; + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ExpressSyncJob.php b/crmeb/jobs/ExpressSyncJob.php new file mode 100644 index 00000000..4f19bdad --- /dev/null +++ b/crmeb/jobs/ExpressSyncJob.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\shipping\ExpressRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class ExpressSyncJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(ExpressRepository::class)->syncExportAll(); + }catch (\Exception $exception){ + Log::info(var_export($exception, 1)); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/GauaranteeCountJob.php b/crmeb/jobs/GauaranteeCountJob.php new file mode 100644 index 00000000..054ac90d --- /dev/null +++ b/crmeb/jobs/GauaranteeCountJob.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\GuaranteeRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class GauaranteeCountJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(GuaranteeRepository::class)->countGuarantee(); + }catch (\Exception $exception){ + Log::info($exception->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ImportSpreadsheetExcelJob.php b/crmeb/jobs/ImportSpreadsheetExcelJob.php new file mode 100644 index 00000000..0b8e52cf --- /dev/null +++ b/crmeb/jobs/ImportSpreadsheetExcelJob.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class ImportSpreadsheetExcelJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(StoreOrderRepository::class)->setWhereDeliveryStatus($data['data'],$data['mer_id']); + }catch (\Exception $e){ + Log::info('商户ID:'.$data['mer_id'].' 导入文件 error : ' . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/MerchantSendCouponJob.php b/crmeb/jobs/MerchantSendCouponJob.php new file mode 100644 index 00000000..d579b551 --- /dev/null +++ b/crmeb/jobs/MerchantSendCouponJob.php @@ -0,0 +1,68 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponSendRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Cache; + +class MerchantSendCouponJob implements JobInterface +{ + + public function fire($job, $sendId) + { + $storeCouponSendRepository = app()->make(StoreCouponSendRepository::class); + $send = $storeCouponSendRepository->get((int)$sendId); + if (!$send || $send->status == 1) { + return $job->delete(); + } + $cacheKey = '_send_coupon' . $sendId; + $cache = Cache::store('file'); + if (!$cache->has($cacheKey)) { + $send->status = -1; + return $job->delete(); + } + $storeCouponRepository = app()->make(StoreCouponRepository::class); + $storeCouponUserRepository = app()->make(StoreCouponUserRepository::class); + $coupon = $storeCouponRepository->get($send->coupon_id); + if (!$coupon) { + $send->status = -1; + return $job->delete(); + } + $uids = $cache->get($cacheKey); + do { + $install = []; + foreach (array_splice($uids, -30) as $k => $uid) { + $data = $storeCouponRepository->createData($coupon, $uid); + $data['send_id'] = $sendId; + $install[] = $data; + } + try { + $storeCouponUserRepository->insertAll($install); + } catch (\Exception $e) { + } + usleep(100); + } while (count($uids)); + $send->status = 1; + $send->save(); + return $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/OrderProfitsharingJob.php b/crmeb/jobs/OrderProfitsharingJob.php new file mode 100644 index 00000000..16da9a3e --- /dev/null +++ b/crmeb/jobs/OrderProfitsharingJob.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\order\StoreOrderProfitsharingRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class OrderProfitsharingJob implements JobInterface +{ + + public function fire($job, $id) + { + $make = app()->make(StoreOrderProfitsharingRepository::class); + $profitsharing = $make->get((int)$id); + if (!$profitsharing || $profitsharing->status != 0) { + $job->delete(); + return; + } + try { + $make->profitsharing($profitsharing); + } catch (\Exception $e) { + Log::info('自动分账失败:' . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/OrderReplyJob.php b/crmeb/jobs/OrderReplyJob.php new file mode 100644 index 00000000..1f519571 --- /dev/null +++ b/crmeb/jobs/OrderReplyJob.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\store\product\ProductReplyRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Db; +use think\facade\Log; +use think\facade\Queue; + +class OrderReplyJob implements JobInterface +{ + + public function fire($job, $orderId) + { + $storeOrderRepository = app()->make(StoreOrderRepository::class); + $productReplyRepository = app()->make(ProductReplyRepository::class); + $order = $storeOrderRepository->getWhere(['order_id' => $orderId, 'status' => 2]); + if ($order) { + $data = ['comment' => '系统默认好评', 'product_score' => 5, 'service_score' => 5, 'postage_score' => 5, 'rate' => 5, 'sort' =>0]; + $data['uid'] = $order->uid; + $data['nickname'] = $order->user ? $order->user['nickname'] : '****'; + $data['avatar'] = $order->user ? $order->user['avatar'] : ''; + $data['mer_id'] = $order->mer_id; + $ids = []; + //订单记录 + $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class); + $orderStatus = [ + 'order_id' => $order->order_id, + 'order_sn' => $order->order_sn, + 'type' => $storeOrderStatusRepository::TYPE_ORDER, + 'change_message' => '交易完成', + 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_AUTO_OVER, + ]; + try { + Db::transaction(function () use ($productReplyRepository, $order, &$ids, $data,$storeOrderStatusRepository,$orderStatus) { + foreach ($order->orderProduct as $orderProduct) { + if ($orderProduct->is_reply) continue; + $data['order_product_id'] = $orderProduct['order_product_id']; + $data['product_type'] = $orderProduct['cart_info']['product']['product_type']??0; + $ids[] = $data['product_id'] = $orderProduct['product_id']; + $data['unique'] = $orderProduct['cart_info']['productAttr']['unique']; + $productReplyRepository->create($data); + $orderProduct->is_reply = 1; + $orderProduct->save(); + } + $order->status = 3; + $order->save(); + //TODO 交易完成 + $storeOrderStatusRepository->createSysLog($orderStatus); + }); + foreach ($ids as $id) { + Queue::push(UpdateProductReplyJob::class, $id); + } + } catch (\Exception $e) { + Log::error($orderId . '自动评价商品失败' . $e->getMessage()); + } + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/PayGiveCouponJob.php b/crmeb/jobs/PayGiveCouponJob.php new file mode 100644 index 00000000..12eec6fb --- /dev/null +++ b/crmeb/jobs/PayGiveCouponJob.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class PayGiveCouponJob implements JobInterface +{ + public function fire($job, $data) + { + $storeCouponRepository = app()->make(StoreCouponRepository::class); + $coupons = $storeCouponRepository->getGiveCoupon($data['ids']); + foreach ($coupons as $coupon) { + if ($coupon->is_limited && 0 == $coupon->remain_count) + continue; + try { + $storeCouponRepository->sendCoupon($coupon, $data['uid'], StoreCouponUserRepository::SEND_TYPE_BUY); + } catch (\Exception $e) { + Log::info('自动发放买赠优惠券:' . $e->getMessage()); + } + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/ProductImportJob.php b/crmeb/jobs/ProductImportJob.php new file mode 100644 index 00000000..fdecdfce --- /dev/null +++ b/crmeb/jobs/ProductImportJob.php @@ -0,0 +1,27 @@ +make(ProductRepository::class); + $make->create($data['data'],$data['product_type']); + }catch (\Exception $e){ + Log::error('商户ID:'.$data['mer_id'].' 导入文件 error : ' . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SendNewPeopleCouponJob.php b/crmeb/jobs/SendNewPeopleCouponJob.php new file mode 100644 index 00000000..d53cd6ef --- /dev/null +++ b/crmeb/jobs/SendNewPeopleCouponJob.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class SendNewPeopleCouponJob implements JobInterface +{ + + public function fire($job, $uid) + { + if (!app()->make(UserRepository::class)->exists($uid)) + return $job->delete(); + + $storeCouponRepository = app()->make(StoreCouponRepository::class); + $newPeopleCoupon = $storeCouponRepository->newPeopleCoupon(); + foreach ($newPeopleCoupon as $coupon) { + if ($coupon->is_limited && 0 == $coupon->remain_count) + continue; + try { + $storeCouponRepository->sendCoupon($coupon, $uid, StoreCouponUserRepository::SEND_TYPE_NEW); + } catch (\Exception $e) { + Log::info('自定发放优惠券:' . $e->getMessage()); + } + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SendNewsJob.php b/crmeb/jobs/SendNewsJob.php new file mode 100644 index 00000000..4d0c3446 --- /dev/null +++ b/crmeb/jobs/SendNewsJob.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\user\UserRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\interfaces\JobInterface; +use crmeb\services\WechatService; +use think\queue\Job; + +class SendNewsJob implements JobInterface +{ + + public function fire($job, $data) + { + $wechatUserRepository = app()->make(WechatUserRepository::class); + [$id, $news] = $data; + if (!$id || !($openId = $wechatUserRepository->idByOpenId((int)$id))) { + return $job->delete(); + } + try { + WechatService::create()->staffTo($openId, WechatService::newsMessage($news)); + } catch (\Exception $e) { + $job->failed($e); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SendSmsJob.php b/crmeb/jobs/SendSmsJob.php new file mode 100644 index 00000000..6c0e17f0 --- /dev/null +++ b/crmeb/jobs/SendSmsJob.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use crmeb\interfaces\JobInterface; +use crmeb\services\SmsService; +use crmeb\services\WechatTemplateMessageService; +use think\facade\Log; + +class SendSmsJob implements JobInterface +{ + + public function fire($job, $data) + { + $status = app()->make(SystemNoticeConfigRepository::class)->getNoticeStatusByConstKey($data['tempId']); + if ($status['notice_sms'] == 1) { + try { + SmsService::sendMessage($data); + } catch (\Exception $e) { + Log::info('发送短信失败' . var_export($data, 1) . $e->getMessage()); + } + } + if ($status['notice_wechat'] == 1) { + try { + app()->make(WechatTemplateMessageService::class)->sendTemplate($data); + } catch (\Exception $e) { + Log::info('模板消息发送失败' . var_export($data, 1) . $e->getMessage()); + } + } + if ($status['notice_routine'] == 1) { + try { + Log::info('订阅消息发送数据' . var_export($data, 1)); + app()->make(WechatTemplateMessageService::class)->subscribeSendTemplate($data); + } catch (\Exception $e) { + Log::info('订阅消息发送失败' . var_export($data, 1) . $e->getMessage()); + } + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SendSvipCouponJob.php b/crmeb/jobs/SendSvipCouponJob.php new file mode 100644 index 00000000..8689434d --- /dev/null +++ b/crmeb/jobs/SendSvipCouponJob.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\coupon\StoreCouponRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use app\common\repositories\system\CacheRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Cache; +use think\facade\Log; +use think\facade\Queue; + +class SendSvipCouponJob implements JobInterface +{ + public function fire($job, $type) + { + $moth = date('Y-m-d',time()); + $meka = app()->make(StoreCouponRepository::class); + try { + $couponIds = $meka->sendSvipCoupon(); + } catch (\Exception $e) { + Log::INFO('发送付费会员优惠券失败:'.$moth); + }; + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SendTemplateMessageJob.php b/crmeb/jobs/SendTemplateMessageJob.php new file mode 100644 index 00000000..dedb55fd --- /dev/null +++ b/crmeb/jobs/SendTemplateMessageJob.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; +use crmeb\services\WechatTemplateService; +use app\common\repositories\user\UserRepository; +use crmeb\services\WechatTemplateMessageService; + +class SendTemplateMessageJob implements JobInterface +{ + + public function fire($job, $data) + { + $make = app()->make(WechatTemplateMessageService::class); + try{ + $make->sendTemplate($data); + }catch (\Exception $e){ + Log::info('公众号消息模板:' . $e->getMessage()); + } + try{ + $make->subscribeSendTemplate($data); + }catch (\Exception $e){ + Log::info('小程序消息模板:' . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SpreadsheetExcelJob.php b/crmeb/jobs/SpreadsheetExcelJob.php new file mode 100644 index 00000000..5c1b3790 --- /dev/null +++ b/crmeb/jobs/SpreadsheetExcelJob.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; +use crmeb\services\ExcelService; + +class SpreadsheetExcelJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(ExcelService::class)->getAll($data); + }catch (\Exception $e){ + Log::info('导出文件:'.$data['type'].'; error : ' . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/SupplyChainOrderBrokerAgeJob.php b/crmeb/jobs/SupplyChainOrderBrokerAgeJob.php new file mode 100644 index 00000000..24845644 --- /dev/null +++ b/crmeb/jobs/SupplyChainOrderBrokerAgeJob.php @@ -0,0 +1,148 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use app\common\model\system\supplychain\SupplyChainBorkerage; +use app\common\model\system\supplychain\SupplyChainTeam; +use app\common\model\system\supplychain\SupplyChainLevel; +use app\common\model\system\supplychain\SupplyChainLinkMerchant; +use app\common\repositories\user\UserBillRepository; +use app\common\model\user\User; +use app\common\model\store\GeoArea; + +/** + * + * 供应链分佣队列 + * + */ +class SupplyChainOrderBrokerAgeJob implements JobInterface +{ + public function fire($job, $data) + { + try { + return false; + // 获取当前用户 + $user = app()->make(UserRepository::class)->get($data['uid']); + $supplyTeam = SupplyChainTeam::find($user['fa_supply_team_id']); + $supplyTeamId = SupplyChainLinkMerchant::where('eb_merchant_id', $data['mer_id'])->value('fa_supply_chain_id'); // 获取供应链团队ID + $supplyLevel = SupplyChainLevel::find($supplyTeam['supply_level_id']); // 获取供应链等级 + $price = $data['brokerage_price']; // 待分润金额 == 订单佣金金额 + + // 判断 存在数据的话,进行分润 + if($supplyTeam) + { + // 可获得金额 + $usrPrice = floatval(($price/100)*$supplyLevel['rate']); + + // 分润数据 + $dataArr = [ + 'user_id' => $data['uid'], // 用户ID + 'pay_price' => $data['inc'], // 订单金额 + 'price' => $price, // 订单分佣金额 + 'order_sn' => $data['order_sn'], // 订单编号 + 'supply_sn' => $data['order_sn'], // 订单编号 + 'order_id' => $data['order_id'], // 订单ID + 'mer_id' => $data['mer_id'], // 商户ID + 'status' => 1, + 'supply_level_id' => $supplyLevel['id'], // 分佣等级ID + 'brokerage_price' => $usrPrice, // 获取的佣金金额 + 'user_info' => $user['nickname'], // 用户名 + 'fa_supply_chain_id' => $supplyTeamId, // 供应链团队ID + 'brokerage_rate' => $supplyLevel['rate'] // 分佣比例 + ]; + + // 储存小组服务分佣记录 + SupplyChainBorkerage::create($dataArr); + // 写入冻结佣金 + $userBillRepository = app()->make(UserBillRepository::class); + + // 加入账单记录 佣金明细 + $userBillRepository->incBill($data['uid'], 'brokerage', 'order_one', [ + 'link_id' => $data['order_id'], + 'status' => 0, + 'title' => '获得采购佣金', + 'number' => $usrPrice, // 增加金额 + 'mark' => $data['order_sn'] . '采购:' . $data['inc'] . '元,获得采购佣金' . $usrPrice, + 'balance' => 0, + 'source' => 1 // 1 小组采购 2 普通商品 + ]); + + $userRepository = app()->make(UserRepository::class); + + // 增加小组服务佣金 + $userRepository->incSupplyBrokerage($data['uid'], $price); + + // 后台分组用户开始 + $userInfo = User::with('nkUserMsg')->find($data['uid']); // 当前用户信息 + $nkUserMsg = $userInfo['nkUserMsg']; // 当前用户关联上级街道、区县等信息 + + $brigade_id = $nkUserMsg['brigade_id']; // 大队 + $village_id = $nkUserMsg['village_id']; // 村 + $street_id = $nkUserMsg['street_id']; //镇 + $area_id = $nkUserMsg['area_id']; // 区域 + $city_code = GeoArea::where('area_code', $area_id)->value('city_code'); // 市 + + // 获取供应链团队 + $supplyChainTeam = SupplyChainTeam::with('level') + ->where('parent_code', 'in', [$brigade_id, $village_id, $street_id, $area_id, $city_code]) + ->select(); // 获取关联上级团队 + + if($supplyChainTeam) + { + // 进行分佣 + foreach ($supplyChainTeam as $v) { + + // 可获得金额 + $usrPrice = floatval(($price/100)*$v['level']['rate']); + + // 分润数据 + $dataArr = [ + 'supply_team_id' => $v['id'], // 团队ID + 'pay_price' => $data['inc'], // 订单金额 + 'price' => $price, // 订单分佣金额 + 'order_sn' => $data['order_sn'], // 订单编号 + 'supply_sn' => $data['order_sn'], // 订单编号 + 'order_id' => $data['order_id'], // 订单ID + 'mer_id' => $data['mer_id'], // 商户ID + 'supply_level_id' => $v['supply_level_id'], // 分佣等级ID + 'brokerage_price' => $usrPrice, // 获取的佣金金额 + 'fa_supply_chain_id' => $supplyTeamId, // 供应链团队ID + 'brokerage_rate' => $v['level']['rate'] // 分佣比例 + ]; + + SupplyChainBorkerage::create($dataArr); // 储存小组服务分佣记录 + SupplyChainTeam::where('id', $v['id'])->inc('free_brokerage', $usrPrice)->update(); // 增加冻结佣金 + } + } + } + + \think\facade\Log::record('供应链佣金分布执行完毕'); + + } catch (\Exception $e) { + Log::info('小组服务佣金同步失败: ' . var_export($data, 1) . $e->getMessage()); + } + + $job->delete(); + + } + + public function failed($data) + { + } +} diff --git a/crmeb/jobs/SyncProductTopJob.php b/crmeb/jobs/SyncProductTopJob.php new file mode 100644 index 00000000..11ea00ba --- /dev/null +++ b/crmeb/jobs/SyncProductTopJob.php @@ -0,0 +1,79 @@ +make(SpuRepository::class); + $RedisCacheService = app()->make(RedisCacheService::class); + $prefix = env('queue_name','merchant').'_hot_ranking_'; + $oldKeys1 = $RedisCacheService->keys($prefix.'top_*') ?: []; + $oldKeys1 = array_combine($oldKeys1, $oldKeys1); + $mset = []; + $hot = systemConfig(['hot_ranking_switch','hot_ranking_lv']); + if (!$hot['hot_ranking_switch']) return $job->delete(); + $where['product_type'] = 0; + $where['spu_status'] = 1; + $where['mer_status'] = 1; + $where['order'] = 'sales'; + $ids = $SpuRepository->search($where)->limit(15)->column('spu_id'); + $mset[$prefix.'top_0'] = implode(',', $ids); + unset($oldKeys1[$prefix.'top_0']); + + $make = app()->make(StoreCategoryRepository::class); + foreach ([1,2,3] as $level) { + $cateList = $make->getSearch(['status' => 1])->where('level','<',$level)->column('store_category_id,cate_name,pic'); + foreach ($cateList as $item) { + $id = $item['store_category_id']; + $ids = $make->findChildrenId($id); + $ids[] = $id; + $where['cate_id'] = $ids; + $spuList = $SpuRepository->search($where)->limit(15)->select(); + if (count($spuList)) { + foreach ($spuList as $i => $spu) { + $key = $prefix.'top_item_' . $id . '_' . $spu['spu_id']; + $mset[$key] = json_encode([$item['cate_name'], $i + 1, $id], JSON_UNESCAPED_UNICODE); + unset($oldKeys1[$key]); + } + $_key = $prefix.'top_' . $id; + $mset[$_key] = implode(',', $spuList->column('spu_id')); + unset($oldKeys1[$_key]); + } + } + Cache::set($prefix.'topCate', implode(',', array_column($cateList, 'store_category_id'))); + } + if (count($mset)) { + $RedisCacheService->mSet($mset); + } + if (count($oldKeys1)) { + $RedisCacheService->handler()->del(...array_values($oldKeys1)); + } + }catch (\Exception $e){ + Log::info('热卖排行统计:' . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } + + public function work() + { + + } +} diff --git a/crmeb/jobs/TestJob.php b/crmeb/jobs/TestJob.php new file mode 100644 index 00000000..9f04cd1f --- /dev/null +++ b/crmeb/jobs/TestJob.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; + +class TestJob implements JobInterface +{ + + public function fire($job, $data) + { + Log::info(var_export($data, 1)); + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/UpdateProductReplyJob.php b/crmeb/jobs/UpdateProductReplyJob.php new file mode 100644 index 00000000..dabac1dc --- /dev/null +++ b/crmeb/jobs/UpdateProductReplyJob.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\store\product\ProductReplyRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\interfaces\JobInterface; + +class UpdateProductReplyJob implements JobInterface +{ + + public function fire($job, $productId) + { + $productReplyRepository = app()->make(ProductReplyRepository::class); + + $total = $productReplyRepository->productTotalRate($productId); + if (!$total) return $job->delete(); + if(!$total['total_rate']) { + $rate = 5; + } else { + $rate = bcdiv($total['total_rate'], $total['total_count'], 1); + } + app()->make(ProductRepository::class)->update($productId, [ + 'rate' => $rate, + 'reply_count' => $total['total_count'] + ]); + $data = $productReplyRepository->getWhere(['product_id' => $productId], 'mer_id'); + $merchantRate = $productReplyRepository->merchantTotalRate($data['mer_id']); + app()->make(MerchantRepository::class)->update($data['mer_id'], $merchantRate); + $job->delete(); + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/jobs/UserBrokerageLevelJob.php b/crmeb/jobs/UserBrokerageLevelJob.php new file mode 100644 index 00000000..367294f5 --- /dev/null +++ b/crmeb/jobs/UserBrokerageLevelJob.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use app\common\repositories\user\UserBrokerageRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\JobInterface; +use think\facade\Log; + +class UserBrokerageLevelJob implements JobInterface +{ + public function fire($job, $data) + { + try { + $user = app()->make(UserRepository::class)->get($data['uid']); + if ($user) { + $flag = true; + if ($data['type'] == 'spread_money') { + $user->spread_pay_price = bcadd($user->spread_pay_price, $data['inc'], 2); + } else if ($data['type'] == 'spread_pay_num') { + $user->spread_pay_count = bcadd($user->spread_pay_count, $data['inc'], 0); + } else { + $flag = false; + } + if ($flag) { + $user->save(); + } + } + if ($user && $user->is_promoter) { + app()->make(UserBrokerageRepository::class)->inc($user, $data['type'], $data['inc']); + } + } catch (\Exception $e) { + Log::info('分销等级同步失败: ' . var_export($data, 1) . $e->getMessage()); + } + $job->delete(); + } + + public function failed($data) + { + } +} diff --git a/crmeb/jobs/UserHistoryJob.php b/crmeb/jobs/UserHistoryJob.php new file mode 100644 index 00000000..6a499f30 --- /dev/null +++ b/crmeb/jobs/UserHistoryJob.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\jobs; + + +use crmeb\interfaces\JobInterface; +use think\facade\Log; +use think\queue\Job; +use app\common\repositories\store\product\ProductRepository; + +class UserHistoryJob implements JobInterface +{ + + public function fire($job, $data) + { + try{ + app()->make(ProductRepository::class)->checkProductByExtension(); + $job->delete(); + }catch (\Exception $exception){ + Log::info(var_export($exception, 1)); + } + } + + public function failed($data) + { + // TODO: Implement failed() method. + } +} diff --git a/crmeb/listens/AuthCancelActivityListen.php b/crmeb/listens/AuthCancelActivityListen.php new file mode 100644 index 00000000..b5430db8 --- /dev/null +++ b/crmeb/listens/AuthCancelActivityListen.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\PresellOrderRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\AutoChangeStatusActivityJob; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use think\facade\Queue; + +class AuthCancelActivityListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 60 * 2, function () { + try { + Queue::push(AutoChangeStatusActivityJob::class,[]); + } catch (\Exception $e) { + + } + }); + } +} diff --git a/crmeb/listens/AuthCancelPresellOrderListen.php b/crmeb/listens/AuthCancelPresellOrderListen.php new file mode 100644 index 00000000..1878802b --- /dev/null +++ b/crmeb/listens/AuthCancelPresellOrderListen.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\PresellOrderRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; + +class AuthCancelPresellOrderListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 1.5, function () { + $presellOrderRepository = app()->make(PresellOrderRepository::class); + $ids = $presellOrderRepository->getTimeOutIds(date('Y-m-d H:i:s')); + foreach ($ids as $id) { + try { + $presellOrderRepository->cancel($id); + } catch (\Exception $e) { + Log::info('自动关闭尾款订单失败' . var_export($id, 1)); + } + } + }); + } +} diff --git a/crmeb/listens/AuthTakeOrderListen.php b/crmeb/listens/AuthTakeOrderListen.php new file mode 100644 index 00000000..09d43fb5 --- /dev/null +++ b/crmeb/listens/AuthTakeOrderListen.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\OrderReplyJob; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use think\facade\Queue; + +class AuthTakeOrderListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 60, function () { + $storeOrderRepository = app()->make(StoreOrderRepository::class); + request()->clearCache(); + $timer = ((int)systemConfig('auto_take_order_timer')) ?: 15; + $time = date('Y-m-d H:i:s', strtotime("- $timer day")); + $ids = app()->make(StoreOrderStatusRepository::class)->getTimeoutDeliveryOrder($time); + foreach ($ids as $id) { + try { + $storeOrderRepository->takeOrder($id); + Queue::push(OrderReplyJob::class, $id); + } catch (\Exception $e) { + Log::error('自动收货失败:' . $e->getMessage()); + } + } + }); + } +} diff --git a/crmeb/listens/AutoCancelGroupOrderListen.php b/crmeb/listens/AutoCancelGroupOrderListen.php new file mode 100644 index 00000000..271e4505 --- /dev/null +++ b/crmeb/listens/AutoCancelGroupOrderListen.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\StoreGroupOrderRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; + +class AutoCancelGroupOrderListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(60000, function () { + $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class); + request()->clearCache(); + $timer = ((int)systemConfig('auto_close_order_timer')) ?: 15; + $time = date('Y-m-d H:i:s', strtotime("- $timer minutes")); + $groupOrderIds = $storeGroupOrderRepository->getTimeOutIds($time); + foreach ($groupOrderIds as $id) { + try { + $storeGroupOrderRepository->cancel($id); + } catch (\Exception $e) { + Log::info('自动关闭订单失败' . var_export($id, 1)); + } + } + }); + } +} diff --git a/crmeb/listens/AutoCheckCouponListen.php b/crmeb/listens/AutoCheckCouponListen.php new file mode 100644 index 00000000..451f4b26 --- /dev/null +++ b/crmeb/listens/AutoCheckCouponListen.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\community\CommunityTopicRepository; +use app\common\repositories\store\coupon\StoreCouponUserRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; + +class AutoCheckCouponListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 30, function () { + app()->make(StoreCouponUserRepository::class)->failCoupon(); + }); + } +} diff --git a/crmeb/listens/AutoClearIntegralListen.php b/crmeb/listens/AutoClearIntegralListen.php new file mode 100644 index 00000000..88c6cf36 --- /dev/null +++ b/crmeb/listens/AutoClearIntegralListen.php @@ -0,0 +1,96 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\model\user\User; +use app\common\repositories\store\IntegralRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\ClearUserIntegralJob; +use crmeb\jobs\SendSmsJob; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Cache; +use think\facade\Db; +use think\facade\Queue; + +class AutoClearIntegralListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + //TODO 自动解冻积分 + $this->tick(1000 * 60 * 20, function () { + request()->clearCache(); + if (!systemConfig('integral_status')) return; + $make = app()->make(IntegralRepository::class); + $end = $make->getTimeoutDay(); + if ($end == strtotime(date('Y-m-d') . ' 00:00:00')) { + $start = $make->getInvalidDay(); + $make->clearTimeoutDay(); + if ($start) { + $startTime = date('Y-m-d H:i:s', $start); + $endTime = date('Y-m-d H:i:s', $end); + User::getDB()->where('integral', '>', 0)->field('uid')->chunk(1000, function ($users) use ($startTime, $endTime) { + foreach ($users as $user) { + $uid = $user['uid']; + Queue::later(1800, ClearUserIntegralJob::class, compact('uid', 'startTime', 'endTime')); + } + usleep(100); + }); + } + } else if ($end < strtotime('+15 day')) { + $make1 = app()->make(UserBillRepository::class); + $invalidDay = $make->getInvalidDay(); + $cache = Cache::store('file'); + $checkKey = 'integral_check'; + if ($cache->has($checkKey)) { + return; + } + $endTime = $end; + $startTime = date('Y-m-d H:i:s', $invalidDay); + User::getDB()->where('integral', '>', 0)->where('phone', '<>', '')->field('uid,phone,integral')->chunk(1000, function ($users) use ($endTime, $startTime, $invalidDay, $end, $make1, $cache) { + foreach ($users as $user) { + $cacheKey = 'integral_sms' . $user['uid']; + if ($cache->has($cacheKey)) { + continue; + } + $integral = $user['integral']; + if ($integral > 0 && $invalidDay) { + $validIntegral = $make1->validIntegral($user['uid'], $startTime, $endTime); + if ($integral > $validIntegral) { + $nextClearIntegral = (int)bcsub($integral, $validIntegral, 0); + $cache->set($cacheKey, 1, 3600 * 24 * 20); + Queue::push(SendSmsJob::class, [ + 'tempId' => 'INTEGRAL_INVALID', + 'id' => [ + 'integral' => $nextClearIntegral, + 'phone' => $user['phone'], + 'date' => $endTime + ] + ]); + continue; + } + } + $cache->set($cacheKey, 1, 3600 * 24 * 2); + } + usleep(200); + }); + $cache->set($checkKey, 1, 3600 * 24 * 1); + } + }); + } +} diff --git a/crmeb/listens/AutoOrderProfitsharingListen.php b/crmeb/listens/AutoOrderProfitsharingListen.php new file mode 100644 index 00000000..cfc98448 --- /dev/null +++ b/crmeb/listens/AutoOrderProfitsharingListen.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\StoreOrderProfitsharingRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\OrderProfitsharingJob; +use crmeb\services\TimerService; +use think\facade\Queue; + +class AutoOrderProfitsharingListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 20, function () { + request()->clearCache(); + $day = (int)systemConfig('sys_refund_timer') ?: 15; + $time = strtotime('-' . $day . ' day'); + $ids = app()->make(StoreOrderProfitsharingRepository::class)->getAutoProfitsharing(date('Y-m-d H:i:s', $time)); + foreach ($ids as $id) { + Queue::push(OrderProfitsharingJob::class, $id); + } + }); + } +} diff --git a/crmeb/listens/AutoOrderReplyListen.php b/crmeb/listens/AutoOrderReplyListen.php new file mode 100644 index 00000000..19ad5b5b --- /dev/null +++ b/crmeb/listens/AutoOrderReplyListen.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\OrderReplyJob; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Queue; + +class AutoOrderReplyListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 60, function () { + request()->clearCache(); + if (systemConfig('open_auto_reply') === '0') { + return; + } + $storeOrderRepository = app()->make(StoreOrderRepository::class); + $time = date('Y-m-d H:i:s', strtotime('- 7 day')); + $ids = $storeOrderRepository->getFinishTimeoutIds($time); + foreach ($ids as $id) { + Queue::push(OrderReplyJob::class, $id); + } + }); + } +} diff --git a/crmeb/listens/AutoSendPayOrderSmsListen.php b/crmeb/listens/AutoSendPayOrderSmsListen.php new file mode 100644 index 00000000..861aef31 --- /dev/null +++ b/crmeb/listens/AutoSendPayOrderSmsListen.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\order\StoreGroupOrderRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\SendSmsJob; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Queue; + +class AutoSendPayOrderSmsListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 5, function () { + $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class); + $time = date('Y-m-d H:i:s', strtotime("- 10 minutes")); + $groupOrderIds = $storeGroupOrderRepository->getTimeOutIds($time, true); + foreach ($groupOrderIds as $id) { + Queue::push(SendSmsJob::class, [ + 'tempId' => 'ORDER_PAY_FALSE', + 'id' => $id + ]); + $storeGroupOrderRepository->isRemind($id); + } + }); + } +} diff --git a/crmeb/listens/AutoUnLockBrokerageListen.php b/crmeb/listens/AutoUnLockBrokerageListen.php new file mode 100644 index 00000000..f86b882e --- /dev/null +++ b/crmeb/listens/AutoUnLockBrokerageListen.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\user\UserBillRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Db; + +class AutoUnLockBrokerageListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + //TODO 自动解冻佣金 + $this->tick(1000 * 60 * 20, function () { + $userBill = app()->make(UserBillRepository::class); + request()->clearCache(); + $timer = ((int)systemConfig('lock_brokerage_timer')); + $time = date('Y-m-d H:i:s', $timer ? strtotime("- $timer day") : time()); + $bills = $userBill->getTimeoutBrokerageBill($time); + Db::transaction(function () use ($userBill, $bills) { + foreach ($bills as $bill) { + if ($bill->number > 0 && $bill->user) { + $brokerage = bcsub($bill->number, $userBill->refundBrokerage($bill->link_id, $bill->uid), 2); + if ($brokerage > 0) { + $bill->user->brokerage_price = bcadd($bill->user->brokerage_price, $brokerage, 2); + $bill->user->save(); + } + } + $bill->status = 1; + $bill->balance = $bill->user ? $bill->user->brokerage_price : 0; + $bill->save(); + } + }); + }); + } +} diff --git a/crmeb/listens/AutoUnLockIntegralListen.php b/crmeb/listens/AutoUnLockIntegralListen.php new file mode 100644 index 00000000..1442343b --- /dev/null +++ b/crmeb/listens/AutoUnLockIntegralListen.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\user\UserBillRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Db; + +class AutoUnLockIntegralListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + //TODO 自动解冻积分 + $this->tick(1000 * 60 * 20, function () { + $userBill = app()->make(UserBillRepository::class); + request()->clearCache(); + $timer = ((int)systemConfig('integral_freeze')); + $time = date('Y-m-d H:i:s', $timer ? strtotime("- $timer day") : time()); + $bills = $userBill->getTimeoutIntegralBill($time); + Db::transaction(function () use ($userBill, $bills) { + foreach ($bills as $bill) { + if($bill->user){ + if ($bill->number > 0) { + $integral = bcsub($bill->number, $userBill->refundIntegral($bill->link_id, $bill->uid), 2); + if ($integral > 0) { + $bill->user->integral = bcadd($bill->user->integral, $integral, 2); + $bill->user->save(); + } + } + } + $bill->status = 1; + $bill->balance = $bill->user->integral ?? 0; + $bill->save(); + } + }); + }); + } +} diff --git a/crmeb/listens/AutoUnlockMerchantMoneyListen.php b/crmeb/listens/AutoUnlockMerchantMoneyListen.php new file mode 100644 index 00000000..612b2080 --- /dev/null +++ b/crmeb/listens/AutoUnlockMerchantMoneyListen.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\user\UserBillRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use think\facade\Db; + +class AutoUnlockMerchantMoneyListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 60 * 20, function () { + request()->clearCache(); + $userBill = app()->make(UserBillRepository::class); + $timer = ((int)systemConfig('mer_lock_time')); + $time = date('Y-m-d H:i:s', $timer ? strtotime("- $timer day") : time()); + $bills = $userBill->getTimeoutMerchantMoneyBill($time); + $merchant = app()->make(MerchantRepository::class); + foreach ($bills as $bill) { + Db::transaction(function () use ($bill, $merchant) { + $merchant->addMoney($bill->mer_id, $bill->number); + $bill->status = 1; + $bill->save(); + }); + } + }); + } +} diff --git a/crmeb/listens/CloseUserSvipListen.php b/crmeb/listens/CloseUserSvipListen.php new file mode 100644 index 00000000..3d3b2d34 --- /dev/null +++ b/crmeb/listens/CloseUserSvipListen.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\CloseUserSvipJob; +use crmeb\services\TimerService; +use think\facade\Queue; + +class CloseUserSvipListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 15, function () { + request()->clearCache(); + Queue::push(CloseUserSvipJob::class,[]); + }); + } +} diff --git a/crmeb/listens/CreateTimerListen.php b/crmeb/listens/CreateTimerListen.php new file mode 100644 index 00000000..9572b8c3 --- /dev/null +++ b/crmeb/listens/CreateTimerListen.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\interfaces\ListenerInterface; +use Swoole\Process; +use Swoole\Server; + +class CreateTimerListen implements ListenerInterface +{ + + public function handle($event): void + { + $process = new Process(function () { + app()->event->trigger('create_timer'); + }, false, 0, true); + + app()->make(Server::class)->addProcess($process); + } +} diff --git a/crmeb/listens/ExcelFileDelListen.php b/crmeb/listens/ExcelFileDelListen.php new file mode 100644 index 00000000..54992cda --- /dev/null +++ b/crmeb/listens/ExcelFileDelListen.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\listens; + +use app\common\repositories\store\ExcelRepository; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use crmeb\interfaces\ListenerInterface; + +class ExcelFileDelListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 60 * 60, function () { + $make = app()->make(ExcelRepository::class); + $time = date('Y-m-d H:i:s', strtotime("-" . 3 . " day")); + $data = $make->getDelByTime($time); + foreach ($data as $id => $path) { + try { + $make->del($id, $path); + } catch (\Exception $e) { + Log::info('自动删除导出文件失败' . var_export($id, true)); + } + } + }); + } +} diff --git a/crmeb/listens/GuaranteeCountListen.php b/crmeb/listens/GuaranteeCountListen.php new file mode 100644 index 00000000..0621df4e --- /dev/null +++ b/crmeb/listens/GuaranteeCountListen.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\listens; + +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\GauaranteeCountJob; +use crmeb\services\TimerService; +use think\facade\Log; + +class GuaranteeCountListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 60 * 15, function () { + try { + queue(GauaranteeCountJob::class,[]); + } catch (\Exception $e) { + Log::info('自动更新保障服务数量失败' . var_export($e, true)); + } + }); + } +} diff --git a/crmeb/listens/InitSwooleLockListen.php b/crmeb/listens/InitSwooleLockListen.php new file mode 100644 index 00000000..479a10a9 --- /dev/null +++ b/crmeb/listens/InitSwooleLockListen.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use crmeb\interfaces\ListenerInterface; +use crmeb\utils\Start; +use Swoole\Lock; + +class InitSwooleLockListen implements ListenerInterface +{ + + public function handle($event): void + { + $GLOBALS['_swoole_order_lock'] = []; + $locks = array_merge(['default'], config('swoole.locks')); + foreach ($locks as $lock) { + $GLOBALS['_swoole_order_lock'][$lock] = new Lock(SWOOLE_MUTEX); + } + app()->make(Start::class)->show(); + } +} diff --git a/crmeb/listens/MerchantApplyMentsCheckListen.php b/crmeb/listens/MerchantApplyMentsCheckListen.php new file mode 100644 index 00000000..ed7cde1c --- /dev/null +++ b/crmeb/listens/MerchantApplyMentsCheckListen.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use app\common\repositories\system\merchant\MerchantApplymentsRepository; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use crmeb\interfaces\ListenerInterface; + +class MerchantApplyMentsCheckListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + //申请状态: 0.平台未提交,-1.平台驳回,10.平台提交审核中,11.需用户操作 ,20.已完成,30.已冻结,40.驳回 + $make = app()->make(MerchantApplymentsRepository::class); + + $this->tick(1000 * 60 * 30, function () use($make) { + $ret = $make->getSearch(['is_del' => 0])->where('status','in',[10,11,30])->select(); + try { + foreach ($ret as $item) { + $make->check($item['mer_id']); + } + } catch (\Exception $e) { + Log::info('自动查询分账商户审核失败' . date('Y-m-d H:i:s', time())); + } + }); + } +} diff --git a/crmeb/listens/ProductGroupStatusCheckListen.php b/crmeb/listens/ProductGroupStatusCheckListen.php new file mode 100644 index 00000000..ca836103 --- /dev/null +++ b/crmeb/listens/ProductGroupStatusCheckListen.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use crmeb\interfaces\ListenerInterface; +use app\common\repositories\store\product\ProductGroupBuyingRepository; + +class ProductGroupStatusCheckListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 60, function () { + $make = app()->make(ProductGroupBuyingRepository::class); + try { + $make->checkStatus(null); + } catch (\Exception $e) { + Log::info('自动检测拼团结束失败' . date('Y-m-d H:i:s', time()). $e->getMessage()); + } + }); + } +} diff --git a/crmeb/listens/ProductPresellStatusListen.php b/crmeb/listens/ProductPresellStatusListen.php new file mode 100644 index 00000000..4926781a --- /dev/null +++ b/crmeb/listens/ProductPresellStatusListen.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use app\common\repositories\store\order\PresellOrderRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use crmeb\jobs\CheckProductPresellJob; +use crmeb\jobs\SendSmsJob; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use crmeb\interfaces\ListenerInterface; +use think\facade\Queue; + +class ProductPresellStatusListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 300, function () { + try { + Queue::push(CheckProductPresellJob::class, []); + } catch (\Exception $e) { + Log::info('自动更新失败'); + } + try { + $ids = app()->make(PresellOrderRepository::class)->sendSmsIds(date('Y-m-d H')); + foreach ($ids as $id) { + Queue::push(SendSmsJob::class, ['tempId' => 'PAY_PRESELL_CODE', 'id' => (int)$id]); + } + } catch (\Exception $e) { + Log::info('预售短信通知失败'); + } + }); + } +} diff --git a/crmeb/listens/QueueListen.php b/crmeb/listens/QueueListen.php new file mode 100644 index 00000000..bb37c5d6 --- /dev/null +++ b/crmeb/listens/QueueListen.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use Swoole\Process; +use Swoole\Server; +use Symfony\Component\Process\PhpExecutableFinder; + +class QueueListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $process = new Process(function (Process $process) { + $process->exec((new PhpExecutableFinder)->find(false), [ + dirname(__DIR__, 2) . '/think', 'queue:listen', '--tries=2', '--queue=' . env('queue_name', 'default') + ]); + }, false, 0, true); + app()->make(Server::class)->addProcess($process); + } +} diff --git a/crmeb/listens/RefundOrderAgreeListen.php b/crmeb/listens/RefundOrderAgreeListen.php new file mode 100644 index 00000000..400805b2 --- /dev/null +++ b/crmeb/listens/RefundOrderAgreeListen.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use crmeb\interfaces\ListenerInterface; +use app\common\repositories\store\order\StoreRefundOrderRepository; + +class RefundOrderAgreeListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 60 * 5, function () { + $make = app()->make(StoreRefundOrderRepository::class); + request()->clearCache(); + $merAgree = systemConfig('mer_refund_order_agree') ?? 7; + $time = date('Y-m-d H:i:s', strtotime('-' . $merAgree . ' day')); + $data = $make->getTimeOutIds($time); + foreach ($data as $id) { + try { + $make->adminRefund($id); + } catch (\Exception $e) { + Log::info('自动退款失败' . var_export($id, true)); + } + } + }); + } +} diff --git a/crmeb/listens/SeckillTImeCheckListen.php b/crmeb/listens/SeckillTImeCheckListen.php new file mode 100644 index 00000000..93af06c1 --- /dev/null +++ b/crmeb/listens/SeckillTImeCheckListen.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Log; +use crmeb\interfaces\ListenerInterface; +use app\common\repositories\store\StoreSeckillActiveRepository; +use app\common\repositories\store\product\ProductAssistRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; + +class SeckillTImeCheckListen extends TimerService implements ListenerInterface +{ + public function handle($event): void + { + $this->tick(1000 * 60, function () { + $make = app()->make(StoreSeckillActiveRepository::class); + $make_1 = app()->make(ProductAssistRepository::class); + $make_2 = app()->make(ProductPresellRepository::class); + $make_3 = app()->make(ProductGroupRepository::class); + try { + $make->valActiveStatus(); + $make_1->valActiveStatus(); + $make_2->valActiveStatus(); + $make_3->valActiveStatus(); + } catch (\Exception $e) { + Log::info('自动检测秒杀结束失败' . date('Y-m-d H:i:s', time())); + } + }); + } +} diff --git a/crmeb/listens/SendSvipCouponListen.php b/crmeb/listens/SendSvipCouponListen.php new file mode 100644 index 00000000..4ecaf8b1 --- /dev/null +++ b/crmeb/listens/SendSvipCouponListen.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\CloseSvipCouponJob; +use crmeb\jobs\SendSvipCouponJob; +use crmeb\services\TimerService; +use think\facade\Cache; +use think\facade\Queue; + +class SendSvipCouponListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 60 * 23, function () { + $key = 'send_svip_coupon_status'; + $nuxt = Cache::get($key); + if (!$nuxt || $nuxt < time()) { + Queue::later(60,SendSvipCouponJob::class,[]); + $day = date('Y-m-d',time()); + + $nuxt = strtotime(date('Y-m-01', strtotime($day)) . ' +1 month'); + $delay = $nuxt - time(); + Cache::set($key, $nuxt); + Queue::later($delay,SendSvipCouponJob::class,[]); + + $last = strtotime(date('Y-m-d',$nuxt) . " -1 day"); + $ldelay = (($last - time()) > 0) ?: 10; + Queue::later($ldelay,CloseSvipCouponJob ::class,[]); + } + }); + } +} diff --git a/crmeb/listens/SumCountListen.php b/crmeb/listens/SumCountListen.php new file mode 100644 index 00000000..50dbb8b9 --- /dev/null +++ b/crmeb/listens/SumCountListen.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\community\CommunityTopicRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; + +class SumCountListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 10 * 5, function () { + app()->make(CommunityTopicRepository::class)->sumCountUse(null); + }); + } +} diff --git a/crmeb/listens/SwooleTaskListen.php b/crmeb/listens/SwooleTaskListen.php new file mode 100644 index 00000000..ecb5146d --- /dev/null +++ b/crmeb/listens/SwooleTaskListen.php @@ -0,0 +1,209 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use app\common\repositories\store\service\StoreServiceLogRepository; +use app\common\repositories\store\service\StoreServiceReplyRepository; +use app\common\repositories\store\service\StoreServiceUserRepository; +use app\common\repositories\system\admin\AdminLogRepository; +use app\common\repositories\user\UserRepository; +use app\common\repositories\user\UserVisitRepository; +use app\webscoket\handler\UserHandler; +use app\webscoket\Manager; +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\SendSmsJob; +use Swoole\Server; +use Swoole\Server\Task; +use think\facade\Cache; +use think\facade\Queue; + +class SwooleTaskListen implements ListenerInterface +{ + /** + * @var Task + */ + protected $task; + + public function handle($task): void + { + request()->clearCache(); + $this->task = $task; + if (method_exists($this, $task->data['type'])) + $this->{$task->data['type']}($task->data['data']); + } + + public function message(array $data) + { + $server = app()->make(Server::class); + $uid = is_array($data['uid']) ? $data['uid'] : [$data['uid']]; + $except = $data['except'] ?? []; + if (!count($uid) && $data['type'] != 'user') { + $fds = $data['type'] == 'mer' ? Manager::merFd($data['mer_id'] ?? 0) : Manager::userFd(0); + foreach ($fds as $fd) { + if (!in_array($fd, $except) && $server->isEstablished($fd) && $server->exist($fd)) + $server->push((int)$fd, json_encode($data['data'])); + } + } else { + foreach ($uid as $id) { + $fds = Manager::userFd(array_search($data['type'], Manager::USER_TYPE), $id); + foreach ($fds as $fd) { + if (!in_array($fd, $except) && $server->isEstablished($fd) && $server->exist($fd)) + $server->push((int)$fd, json_encode($data['data'])); + } + } + } + } + + /** + * //TODO 用户给客服发送消息 + * + * @param array $data + * @author xaboy + * @day 2020/6/15 + */ + public function chatToService(array $data) + { + $flag = UserHandler::serviceOnline($data['uid'], $data['data']['uid']); + $serviceLogRepository = app()->make(StoreServiceLogRepository::class); + $lst = Cache::sMembers('m_chat' . $data['uid']) ?: []; + $server = app()->make(Server::class); + foreach ($lst as $item) { + [$fd, $merId, $toUid] = explode('/', $item); + if (!in_array($fd, $data['except'] ?? []) && $server->isEstablished($fd) && $server->exist($fd)) { + $data['data']['is_get'] = 1; + $server->push((int)$fd, json_encode(['type' => $toUid == $data['data']['uid'] ? 'chat' : 'back_chat', 'data' => $data['data']])); + } + } + if (!$flag) { + //TODO 客服消息提醒 + $user = app()->make(UserRepository::class)->get($data['data']['uid']); + $params = [ + 'mer_id' => $data['data']['mer_id'], + 'keyword1' => date('Y-m-d H:i:s',time()), + 'keyword2' => $data['data']['msn'], + 'url' => '/pages/chat/customer_list/chat?userId=' . $data['data']['uid'] . '&mer_id=' . $data['data']['mer_id'] + ]; + Queue::push(SendSmsJob::class, ['tempId' => 'SERVER_NOTICE', 'id' => $data['uid'], 'params' => $params]); + }else{ + $serviceLogRepository->serviceRead($data['data']['mer_id'], $data['data']['uid'], $data['data']['service_id']); + app()->make(StoreServiceUserRepository::class)->read($data['data']['mer_id'], $data['data']['uid'], true); + } + if ($data['data']['msn_type'] === 1) { + $serviceLogRepository = app()->make(StoreServiceLogRepository::class); + $reply = app()->make(StoreServiceReplyRepository::class)->keywordByValidData($data['data']['msn'], $data['data']['mer_id']); + if ($reply) { + $log = null; + if (($reply->type === 2 || $reply->type === 1) && $reply['content']) { + $log = $serviceLogRepository->create([ + 'mer_id' => $data['data']['mer_id'], + 'msn' => $reply['content'], + 'uid' => $data['data']['uid'], + 'service_id' => $data['data']['service_id'], + 'remind' => 1, + 'send_type' => 1, + 'msn_type' => $reply->type === 2 ? 3 : 1, + 'type' => 1, + 'service_type' => 0, + ]); + } + if ($log) { + $lst = Cache::sMembers('u_chat' . $data['data']['uid']) ?: []; + $log->append(['service']); + $server = app()->make(Server::class); + foreach ($lst as $item) { + [$fd, $merId] = explode('/', $item); + if ($server->isEstablished($fd) && $server->exist($fd) && $merId == $data['data']['mer_id']) { + $server->push((int)$fd, json_encode(['type' => 'chat', 'data' => $log->toArray()])); + } + } + $lst = Cache::sMembers('m_chat' . $log->service->uid) ?: []; + $server = app()->make(Server::class); + foreach ($lst as $item) { + [$fd, $merId, $toUid] = explode('/', $item); + if ($server->isEstablished($fd) && $server->exist($fd) && $toUid == $data['data']['uid']) { + $server->push((int)$fd, json_encode(['type' => 'chat', 'data' => $log->toArray()])); + } + } + } + } + } + } + + /** + * //TODO 客服给用户发送消息 + * @param array $data + * @author xaboy + * @day 2020/6/15 + */ + public function chatToUser(array $data) + { + $flag = UserHandler::userOnline($data['uid'], $data['data']['mer_id']); + if ($flag) { + $serviceLogRepository = app()->make(StoreServiceLogRepository::class); + $lst = Cache::sMembers('u_chat' . $data['uid']) ?: []; + $server = app()->make(Server::class); + foreach ($lst as $item) { + [$fd, $merId] = explode('/', $item); + if (!in_array($fd, $data['except'] ?? []) && $server->isEstablished($fd) && $server->exist($fd) && $merId == $data['data']['mer_id']) { + $data['data']['is_get'] = 1; + $server->push((int)$fd, json_encode(['type' => 'chat', 'data' => $data['data']])); + } + } + $serviceLogRepository->userRead($data['data']['mer_id'], $data['data']['uid']); + app()->make(StoreServiceUserRepository::class)->read($data['data']['mer_id'], $data['data']['uid']); + } else { + //TODO 客服给用户发送消息 + $params = [ + 'mer_id' => $data['data']['mer_id'], + 'keyword1' => date('Y-m-d H:i:s', time()), + 'keyword2' => $data['data']['msn'], + 'url' => '/pages/chat/customer_list/chat?mer_id=' . $data['data']['mer_id'] + ]; + Queue::push(SendSmsJob::class, ['id' => $data['uid'], 'tempId' => 'SERVER_NOTICE', 'params' => $params]); + } + } + + public function admin(array $data) + { + $this->message([ + 'uid' => $data['uid'] ?? [], + 'type' => 'admin', + 'data' => $data['data'] + ] + ); + } + + public function merchant(array $data) + { + $this->message([ + 'uid' => $data['uid'] ?? [], + 'mer_id' => $data['mer_id'], + 'type' => 'mer', + 'data' => $data['data'] + ] + ); + } + + public function visit(array $data) + { + /** @var UserVisitRepository $make */ + $make = app()->make(UserVisitRepository::class); + $make->create($data); + } + + public function log(array $data) + { + app()->make(AdminLogRepository::class)->create($data['merId'], $data['result']); + } +} diff --git a/crmeb/listens/SwooleWorkerExitListen.php b/crmeb/listens/SwooleWorkerExitListen.php new file mode 100644 index 00000000..f72bf528 --- /dev/null +++ b/crmeb/listens/SwooleWorkerExitListen.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use crmeb\interfaces\ListenerInterface; +use Swoole\Timer; + +class SwooleWorkerExitListen implements ListenerInterface +{ + + public function handle($event): void + { + Timer::clearAll(); + } +} diff --git a/crmeb/listens/SyncBroadcastStatusListen.php b/crmeb/listens/SyncBroadcastStatusListen.php new file mode 100644 index 00000000..940ae87d --- /dev/null +++ b/crmeb/listens/SyncBroadcastStatusListen.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\store\broadcast\BroadcastGoodsRepository; +use app\common\repositories\store\broadcast\BroadcastRoomRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use Swoole\Timer; +use think\facade\Cache; +use think\facade\Log; + +class SyncBroadcastStatusListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 5, function () { + $broadcastGoodsRepository = app()->make(BroadcastGoodsRepository::class); + try { + $broadcastGoodsRepository->syncGoodStatus(); + } catch (\Exception $e) { + Log::error('同步直播商品:' . $e->getMessage()); + } + }); + + $this->tick(1000 * 60 * 5, function () { + if (Cache::has('_sys_break_b_room')) { + return; + } + $broadcastRoomRepository = app()->make(BroadcastRoomRepository::class); + try { + $broadcastRoomRepository->syncRoomStatus(); + } catch (\Exception $e) { + if ($e instanceof \EasyWeChat\Core\Exceptions\HttpException && $e->getCode() == '48001') { + Cache::set('_sys_break_b_room', 1, 3600); + } + Log::error('同步直播间:' . $e->getMessage()); + } + }); + } +} diff --git a/crmeb/listens/SyncHotRankingListen.php b/crmeb/listens/SyncHotRankingListen.php new file mode 100644 index 00000000..19a0ac61 --- /dev/null +++ b/crmeb/listens/SyncHotRankingListen.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + +use crmeb\interfaces\ListenerInterface; +use crmeb\jobs\SyncProductTopJob; +use crmeb\services\TimerService; +use think\facade\Log; +use think\facade\Queue; + +class SyncHotRankingListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $hot = systemConfig('hot_ranking_switch'); + if (!$hot) return ; + $time = systemConfig('hot_ranking_time'); + $time = ($time && $time > 1) ?: 1 ; + $this->tick(1000 * 60 * 60 * $time, function () { + request()->clearCache(); + try{ + Queue::push(SyncProductTopJob::class, []); + }catch (\Exception $e) { + Log::info('热卖排行错误:'.var_export([$e->getMessage()],1)); + } + }); + } +} diff --git a/crmeb/listens/SyncSmsResultCodeListen.php b/crmeb/listens/SyncSmsResultCodeListen.php new file mode 100644 index 00000000..5a1e36c2 --- /dev/null +++ b/crmeb/listens/SyncSmsResultCodeListen.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\system\sms\SmsRecordRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use crmeb\services\YunxinSmsService; +use Swoole\Timer; + +class SyncSmsResultCodeListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 60 * 5, function () { + $smsRecordRepository = app()->make(SmsRecordRepository::class); + $time = date('Y-m-d H:i:s', strtotime("- 10 minutes")); + $ids = $smsRecordRepository->getTimeOutIds($time); + if (count($ids)) return; + $list = (array)YunxinSmsService::create()->getStatus($ids); + foreach ($list as $item) { + if (isset($item['id'])) { + if ($item['resultcode'] == '' || $item['resultcode'] == null) $item['resultcode'] = 134; + $smsRecordRepository->updateRecordStatus($item['id'], $item['resultcode']); + } + } + }); + } +} diff --git a/crmeb/listens/SyncSpreadStatusListen.php b/crmeb/listens/SyncSpreadStatusListen.php new file mode 100644 index 00000000..7cbd46cf --- /dev/null +++ b/crmeb/listens/SyncSpreadStatusListen.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens; + + +use app\common\repositories\user\UserRepository; +use crmeb\interfaces\ListenerInterface; +use crmeb\services\TimerService; +use crmeb\services\YunxinSmsService; +use Swoole\Timer; + +class SyncSpreadStatusListen extends TimerService implements ListenerInterface +{ + + public function handle($event): void + { + $this->tick(1000 * 10, function () { + request()->clearCache(); + app()->make(UserRepository::class)->syncSpreadStatus(); + }); + } +} diff --git a/crmeb/listens/pay/MealSuccessListen.php b/crmeb/listens/pay/MealSuccessListen.php new file mode 100644 index 00000000..7f8b25bf --- /dev/null +++ b/crmeb/listens/pay/MealSuccessListen.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens\pay; + +use app\common\repositories\system\serve\ServeOrderRepository; +use crmeb\interfaces\ListenerInterface; + +class MealSuccessListen implements ListenerInterface +{ + + public function handle($data): void + { + app()->make(ServeOrderRepository::class)->paySuccess($data); + } +} diff --git a/crmeb/listens/pay/OrderMicroPaySuccessListen.php b/crmeb/listens/pay/OrderMicroPaySuccessListen.php new file mode 100644 index 00000000..49a40dce --- /dev/null +++ b/crmeb/listens/pay/OrderMicroPaySuccessListen.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens\pay; + + +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\interfaces\ListenerInterface; + +class OrderMicroPaySuccessListen implements ListenerInterface +{ + + public function handle($data): void + { + $orderSn = $data['order_sn']; + $is_combine = $data['is_combine'] ?? 0; + $groupOrder = app()->make(StoreGroupOrderRepository::class)->getWhere(['group_order_sn' => $orderSn]); + if (!$groupOrder || $groupOrder->paid == 1) return; + $orders = []; + if ($is_combine) { + foreach ($data['data']['sub_orders'] as $order) { + $orders[$order['out_trade_no']] = $order; + } + } + $groupOrder['micro_pay']=1; + app()->make(StoreOrderRepository::class)->paySuccess($groupOrder, $is_combine, $orders); + } +} diff --git a/crmeb/listens/pay/OrderPaySuccessListen.php b/crmeb/listens/pay/OrderPaySuccessListen.php new file mode 100644 index 00000000..cc2f7c29 --- /dev/null +++ b/crmeb/listens/pay/OrderPaySuccessListen.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens\pay; + + +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use crmeb\interfaces\ListenerInterface; +use think\facade\Log; + +class OrderPaySuccessListen implements ListenerInterface +{ + + public function handle($data): void + { + $orderSn = $data['order_sn']; + $is_combine = $data['is_combine'] ?? 0; + $groupOrder = app()->make(StoreGroupOrderRepository::class)->getWhere(['group_order_sn' => $orderSn]); + if (!$groupOrder || $groupOrder->paid == 1) return; + $orders = []; + if ($is_combine) { + foreach ($data['data']['sub_orders'] as $order) { + $orders[$order['out_trade_no']] = $order; + } + } + Log::info('微信支付成功回调执行队列' . var_export([$data,$groupOrder], 1)); + app()->make(StoreOrderRepository::class)->paySuccess($groupOrder, $is_combine, $orders); + } +} diff --git a/crmeb/listens/pay/PresellPaySuccessListen.php b/crmeb/listens/pay/PresellPaySuccessListen.php new file mode 100644 index 00000000..a229b8e0 --- /dev/null +++ b/crmeb/listens/pay/PresellPaySuccessListen.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens\pay; + + +use app\common\repositories\store\order\PresellOrderRepository; +use crmeb\interfaces\ListenerInterface; + +class PresellPaySuccessListen implements ListenerInterface +{ + + public function handle($data): void + { + $orderSn = $data['order_sn']; + $is_combine = $data['is_combine'] ?? 0; + $order = app()->make(PresellOrderRepository::class)->getWhere(['presell_order_sn' => $orderSn]); + if (!$order || $order->paid == 1) return; + $orders = []; + if ($is_combine) { + foreach ($data['data']['sub_orders'] as $_order) { + $orders[$_order['out_trade_no']] = $_order; + } + } + app()->make(PresellOrderRepository::class)->paySuccess($order, $is_combine, $orders); + } +} diff --git a/crmeb/listens/pay/UserOrderSuccessListen.php b/crmeb/listens/pay/UserOrderSuccessListen.php new file mode 100644 index 00000000..f4d9fa14 --- /dev/null +++ b/crmeb/listens/pay/UserOrderSuccessListen.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens\pay; + + +use app\common\repositories\user\UserOrderRepository; +use app\common\repositories\user\UserRechargeRepository; +use crmeb\interfaces\ListenerInterface; + +class UserOrderSuccessListen implements ListenerInterface +{ + + public function handle($data): void + { + app()->make(UserOrderRepository::class)->paySuccess($data); + } +} diff --git a/crmeb/listens/pay/UserRechargeSuccessListen.php b/crmeb/listens/pay/UserRechargeSuccessListen.php new file mode 100644 index 00000000..1b1efd45 --- /dev/null +++ b/crmeb/listens/pay/UserRechargeSuccessListen.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\listens\pay; + + +use app\common\repositories\user\UserRechargeRepository; +use crmeb\interfaces\ListenerInterface; + +class UserRechargeSuccessListen implements ListenerInterface +{ + + public function handle($data): void + { + $orderSn = $data['order_sn']; + app()->make(UserRechargeRepository::class)->paySuccess($orderSn); + } +} diff --git a/crmeb/services/AccessTokenServeService.php b/crmeb/services/AccessTokenServeService.php new file mode 100644 index 00000000..e175842d --- /dev/null +++ b/crmeb/services/AccessTokenServeService.php @@ -0,0 +1,173 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use app\common\repositories\system\config\ConfigValueRepository; +use think\exception\ValidateException; +use think\facade\Cache; + +/** + * Class AccessTokenServeService + * @package crmeb\services + */ +class AccessTokenServeService extends HttpService +{ + /** + * 配置 + * @var string + */ + protected $account; + + /** + * @var string + */ + protected $secret; + + /** + * @var Cache|null + */ + protected $cache; + + /** + * @var string + */ + protected $accessToken; + + /** + * @var string + */ + protected $cacheTokenPrefix = "_crmeb_plat"; + + /** + * @var string + */ + protected $apiHost = 'http://sms.crmeb.net/api/'; + + /** + * 登录接口 + */ + const USER_LOGIN = "user/login"; + + + /** + * AccessTokenServeService constructor. + * @param string $account + * @param string $secret + * @param Cache|null $cache + */ + public function __construct(string $account, string $secret, $cache = null) + { + $this->account = $account; + $this->secret = $secret; + } + + /** + * 获取配置 + * @return array + */ + public function getConfig() + { + return [ + 'account' => $this->account, + 'secret' => $this->secret + ]; + } + + /** + * 获取缓存token + * @return mixed + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function getToken() + { + $accessTokenKey = md5($this->account . '_' . $this->secret . $this->cacheTokenPrefix); + $cacheToken = Cache::get($accessTokenKey); + if (!$cacheToken) { + $getToken = $this->getTokenFromServer(); + Cache::set($accessTokenKey, $getToken['access_token'], 300); + $cacheToken = $getToken['access_token']; + } + $this->accessToken = $cacheToken; + + return $cacheToken; + + } + + /** + * 从服务器获取token + * @return mixed + */ + public function getTokenFromServer() + { + $params = [ + 'account' => $this->account, + 'secret' => $this->secret, + ]; + if (!$this->account || !$this->secret) { + throw new ValidateException('请先登录一号通平台!'); + } + $response = $this->postRequest($this->get(self::USER_LOGIN), $params); + $response = json_decode($response, true); + if (!$response) { + throw new ValidateException('获取token失败'); + } + if ($response['status'] === 200) { + return $response['data']; + } else { + throw new ValidateException($response['msg']); + } + } + + /** + * 请求 + * @param string $url + * @param array $data + * @param string $method + * @param bool $isHeader + * @return array|mixed + */ + public function httpRequest(string $url, array $data = [], string $method = 'POST', bool $isHeader = true) + { + $header = []; + if ($isHeader) { + $this->getToken(); + if (!$this->accessToken) { + throw new ValidateException('配置已更改或token已失效'); + } + $header = ['Authorization:Bearer-' . $this->accessToken]; + } + + $res = $this->request($this->get($url), $method, $data, $header); + if (!$res) { + throw new ValidateException('平台错误:发生异常,请稍后重试'); + + } + $result = json_decode($res, true) ?: false; + if (!isset($result['status']) || $result['status'] != 200) { + if ($result['msg'] == '接口请求失败:用户或密码错误') { + app()->make(CrmebServeServices::class)->logout(); + } + throw new ValidateException(isset($result['msg']) ? '平台错误:' . $result['msg'] : '平台错误:发生异常,请稍后重试'); + } + return $result['data'] ?? []; + + } + + /** + * @param string $apiUrl + * @return string + */ + public function get(string $apiUrl = '') + { + return $this->apiHost . $apiUrl; + } +} diff --git a/crmeb/services/AlipayService.php b/crmeb/services/AlipayService.php new file mode 100644 index 00000000..f9b79bd9 --- /dev/null +++ b/crmeb/services/AlipayService.php @@ -0,0 +1,148 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use crmeb\services\alipay\AlipayNotify; +use Payment\Client; +use Payment\Proxies\AlipayProxy; +use think\exception\ValidateException; +use think\facade\Route; + +class AlipayService +{ + /** + * @var Client + */ + protected $application; + + /** + * @var array + */ + protected $config; + + public function __construct(array $config) + { + $this->config = $config; + $this->application = new Client(Client::ALIPAY, $config); + } + + public static function create($type = '') + { + return new self(self::getConfig($type)); + } + + public static function getConfig($type = '') + { + $config = systemConfig(['site_url', 'alipay_app_id', 'alipay_public_key', 'alipay_private_key', 'alipay_open']); + if (!$config['alipay_open']) throw new ValidateException('支付宝支付未开启'); + $siteUrl = $config['site_url']; + return [ + 'app_id' => $config['alipay_app_id'], + 'sign_type' => 'RSA2', // RSA RSA2 + 'limit_pay' => [ +// 'balance',// 余额 +// 'moneyFund',// 余额宝 +// 'debitCardExpress',// 借记卡快捷 + //'creditCard',//信用卡 + //'creditCardExpress',// 信用卡快捷 + //'creditCardCartoon',//信用卡卡通 + //'credit_group',// 信用支付类型(包含信用卡卡通、信用卡快捷、花呗、花呗分期) + ], // 用户不可用指定渠道支付当有多个渠道时用“,”分隔 + + // 支付宝公钥字符串 + 'ali_public_key' => $config['alipay_public_key'], + // 自己生成的密钥字符串 + 'rsa_private_key' => $config['alipay_private_key'], + 'notify_url' => rtrim($siteUrl, '/') . Route::buildUrl('alipayNotify', ['type' => $type])->build(), + 'return_url' => $siteUrl, + ]; + } + + public function qrPaymentPrepare($out_trade_no, $total_fee, $body, $detail = '') + { + $data = [ + 'body' => $detail ?: $body, + 'subject' => $body, + 'trade_no' => $out_trade_no, + 'amount' => floatval($total_fee), + 'time_expire' => time() + (15 * 60), + 'return_params' => $out_trade_no, + ]; + try { + $res = $this->application->pay(Client::ALI_CHANNEL_QR, $data); + } catch (\Exception $e) { + throw new ValidateException('支付宝支付错误返回:' . $e->getMessage()); + } + return $res['qr_code']; + } + + public function appPaymentPrepare($out_trade_no, $total_fee, $body, $detail = '') + { + $data = [ + 'body' => $detail ?: $body, + 'subject' => $body, + 'trade_no' => $out_trade_no, + 'amount' => floatval($total_fee), + 'time_expire' => time() + (15 * 60), + 'goods_type' => 1, + 'return_params' => $out_trade_no, + ]; + try { + $res = $this->application->pay(Client::ALI_CHANNEL_APP, $data); + } catch (\Exception $e) { + throw new ValidateException('支付宝支付错误返回:' . $e->getMessage()); + } + return $res; + } + + public function wapPaymentPrepare($out_trade_no, $total_fee, $body, $return_url = '', $detail = '') + { + $data = [ + 'body' => $detail ?: $body, + 'subject' => $body, + 'trade_no' => $out_trade_no, + 'amount' => floatval($total_fee), + 'time_expire' => time() + (15 * 60), + 'goods_type' => 1, + 'return_params' => $out_trade_no, + ]; + $config = AlipayProxy::$config; + if ($return_url) + $config->offsetSet('return_url', $return_url); + $data['quit_url'] = $config->get('return_url'); + try { + $res = $this->application->pay(Client::ALI_CHANNEL_WAP, $data); + } catch (\Exception $e) { + throw new ValidateException('支付宝支付错误返回:' . $e->getMessage()); + } + return $res; + } + + public function payOrderRefund($trade_sn, array $data) + { + $data = [ + 'trade_no' => $trade_sn, + 'refund_fee' => floatval($data['refund_price']), + 'reason' => $data['refund_id'], + 'refund_no' => $data['refund_id'], + ]; + return $this->application->refund($data); + } + + public function notify($type) + { + $this->application->notify(new AlipayNotify($type)); + } +} diff --git a/crmeb/services/ApiResponseService.php b/crmeb/services/ApiResponseService.php new file mode 100644 index 00000000..5d98b905 --- /dev/null +++ b/crmeb/services/ApiResponseService.php @@ -0,0 +1,133 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + +use think\contract\Arrayable; +use think\response\Json; + +class ApiResponseService +{ + protected $response; + + const DEFAULT_SUCCESS_MESSAGE = 'success'; + const DEFAULT_FAIL_MESSAGE = 'fail'; + + const DEFAULT_SUCCESS_CODE = 200; + const DEFAULT_FAIL_CODE = 400; + + public function __construct(Json $response) + { + $this->response = $response; + } + + public function code(int $code) + { + $this->response->code($code); + + return $this; + } + + /** + * @param $data + * @return array|string|null + */ + private function parseData($data) + { + if ($data instanceof Arrayable) + return $data->toArray(); + else + return $data; + } + + /** + * @param int $status + * @param string $message + * @param array|Arrayable|null $data + * @return Json + */ + public function make(int $status, string $message, $data = null): Json + { + $content = compact('status', 'message'); + if (!is_null($data)) + $content['data'] = $this->parseData($data); + $this->response->data($content); + return $this->response; + } + + /** + * @param string|array|Arrayable $message + * @param array|Arrayable|null $data + * @return Json + */ + public function success($message = self::DEFAULT_SUCCESS_MESSAGE, $data = null) + { + $message = $this->parseData($message); + if (is_array($message)) { + $data = $message; + $message = self::DEFAULT_SUCCESS_MESSAGE; + } else { + $data = $this->parseData($data); + } + return $this->make(self::DEFAULT_SUCCESS_CODE, $message, $data); + } + + /** + * @param string|array|Arrayable $message + * @param array|Arrayable|null $data + * @return Json + */ + public function fail($message = self::DEFAULT_FAIL_MESSAGE, $data = null) + { + $message = $this->parseData($message); + if (is_array($message)) { + $data = $message; + $message = self::DEFAULT_FAIL_MESSAGE; + } else { + $data = $this->parseData($data); + } + return $this->make(self::DEFAULT_FAIL_CODE, $message, $data); + } + + /** + * @param $status + * @param string|array|Arrayable $message + * @param array|Arrayable $result + * @return Json + */ + public function status($status, $message, $result = []) + { + $message = $this->parseData($message); + if (is_array($message)) { + $result = $message; + $message = self::DEFAULT_SUCCESS_MESSAGE; + } else { + $result = $this->parseData($result); + } + return $this->make(self::DEFAULT_SUCCESS_CODE, $message, compact('status', 'result')); + } + + /** + * @param string $type + * @param $data + * @return Json + * @author xaboy + * @day 2020/6/13 + */ + public function message(string $type, $data) + { + $this->response->data(compact('type', 'data')); + return $this->response; + } + +} diff --git a/crmeb/services/BaseExpress.php b/crmeb/services/BaseExpress.php new file mode 100644 index 00000000..eb8e4022 --- /dev/null +++ b/crmeb/services/BaseExpress.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use crmeb\basic\BaseStorage; + +/** + * Class BaseExpress + * @package crmeb\basic + */ +abstract class BaseExpress extends BaseStorage +{ + + /** + * access_token + * @var null + */ + protected $accessToken = NULL; + + + public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile) + { + parent::__construct($name, [], $configFile); + $this->accessToken = $accessTokenServeService; + } + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config = []) + { +// parent::initialize($config); + } + + + /** + * 开通服务 + * @return mixed + */ + abstract public function open(); + + /**物流追踪 + * @return mixed + */ + abstract public function query(string $num, string $com = ''); + + /**电子面单 + * @return mixed + */ + abstract public function dump($merId,$data); + + /**快递公司 + * @return mixed + */ +// abstract public function express($type, $page, $limit); + + /**面单模板 + * @return mixed + */ + abstract public function temp(string $com); +} diff --git a/crmeb/services/BaseProduct.php b/crmeb/services/BaseProduct.php new file mode 100644 index 00000000..f6f23333 --- /dev/null +++ b/crmeb/services/BaseProduct.php @@ -0,0 +1,62 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use crmeb\basic\BaseStorage; +use crmeb\services\AccessTokenServeService; + +/** + * Class BaseProduct + * @package crmeb\basic + */ +abstract class BaseProduct extends BaseStorage +{ + + /** + * access_token + * @var null + */ + protected $accessToken = NULL; + + /** + * BaseProduct constructor. + * @param string $name + * @param AccessTokenServeService $accessTokenServeService + * @param string $configFile + */ + public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile) + { + parent::__construct($name, [], $configFile); + $this->accessToken = $accessTokenServeService; + } + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config = []) + { +// parent::initialize($config); + } + + /** + * 开通服务 + * @return mixed + */ + abstract public function open(); + + /**复制商品 + * @return mixed + */ + abstract public function goods(string $url); +} diff --git a/crmeb/services/BaseSmss.php b/crmeb/services/BaseSmss.php new file mode 100644 index 00000000..5e831336 --- /dev/null +++ b/crmeb/services/BaseSmss.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- +namespace crmeb\services; + +use crmeb\basic\BaseStorage; +use crmeb\services\AccessTokenServeService; + +/** + * Class BaseSmss + * @package crmeb\basic + */ +abstract class BaseSmss extends BaseStorage +{ + + /** + * access_token + * @var null + */ + protected $accessToken = NULL; + + /** + * BaseSmss constructor. + * @param string $name + * @param AccessTokenServeService $accessTokenServeService + * @param string $configFile + */ + public function __construct(string $name, AccessTokenServeService $accessTokenServeService, string $configFile) + { + $this->accessToken = $accessTokenServeService; + $this->name = $name; + $this->configFile = $configFile; + $this->initialize(); + } + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config = []) + { + + } + + + /** + * 开通服务 + * @return mixed + */ + abstract public function open(); + + /**修改签名 + * @return mixed + */ + abstract public function modify(string $sign = null, string $phone, string $code); + + /**用户信息 + * @return mixed + */ + abstract public function info(); + + /**发送短信 + * @return mixed + */ + abstract public function send(string $phone, string $templateId, array $data); + + /** + * 短信模板 + * @param int $page + * @param int $limit + * @param int $type + * @return mixed + */ + abstract public function temps(int $page, int $limit, int $type); + + + /** + * 申请模板 + * @param string $title + * @param string $content + * @param int $type + * @return mixed + */ + abstract public function apply(string $title, string $content, int $type); + + /** + * 模板记录 + * @param int $tempType + * @param int $page + * @param int $limit + * @return mixed + */ + abstract public function applys(int $tempType, int $page, int $limit); + + /**发送记录 + * @return mixed + */ + abstract public function record($record_id); +} diff --git a/crmeb/services/BlockPuzzleCaptchaService.php b/crmeb/services/BlockPuzzleCaptchaService.php new file mode 100644 index 00000000..9f6a6f85 --- /dev/null +++ b/crmeb/services/BlockPuzzleCaptchaService.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- +namespace crmeb\services; + +use Fastknife\Domain\Vo\PointVo; +use Fastknife\Exception\ParamException; +use Fastknife\Service\BlockPuzzleCaptchaService as baseBlockPuzzleCaptchaService; + +class BlockPuzzleCaptchaService extends baseBlockPuzzleCaptchaService +{ + /** + * 验证 + * @param string $token + * @param string $pointJson + * @param null $callback + */ + public function validate($token, $pointJson, $callback = null) + { + //获取并设置 $this->originData + $this->setOriginData($token); + //数据处理类 + $blockData = $this->factory->makeBlockData(); + $pointJson = json_decode($pointJson); + //解码出来的前端坐标 + $targetPoint = new PointVo($pointJson->x, $pointJson->y); + //检查 + $blockData->check($this->originData['point'], $targetPoint); + if ( + abs($pointJson->x - $targetPoint->x) <= $blockData->getFaultOffset() && $pointJson->y == $targetPoint->y + ) { + return; + } + if($callback instanceof \Closure){ + $callback(); + } + } + + public function verificationByEncryptCode(string $encryptCode) + { + $result = explode('---',$encryptCode); + if(empty($result)){ + throw new ParamException('参数错误!'); + } + $this->validate($result[0], $result[1], function () use ($result,$encryptCode) { + $cacheEntity = $this->factory->getCacheInstance(); + $cacheEntity->delete($result['token']); + $cacheEntity->delete($encryptCode); + }); + + } +} diff --git a/crmeb/services/CacheService.php b/crmeb/services/CacheService.php new file mode 100644 index 00000000..6d62adc9 --- /dev/null +++ b/crmeb/services/CacheService.php @@ -0,0 +1,168 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use think\cache\driver\Redis; +use think\facade\Cache; +use think\facade\Config; + +/** + * crmeb 缓存类 + * Class CacheService + * @package crmeb\services + * @mixin \Redis + */ +class CacheService +{ + const TAG_TOPIC = 'topic'; + const TAG_CONFIG = 'config'; + const TAG_COMMUNITY = 'community'; + const TAG_BRAND = 'brand'; + const TAG_CATEGORY = 'category'; + const TAG_GROUP_DATA = 'group_data'; + const TAG_MERCHANT = 'merchant'; + + protected $handler; + protected $tag; + protected $type; + + /** + * @param int $admin + * @param string $tag + */ + public function __construct($type, $tag) + { + $key = config('app.app_key'); + $tagLst = ['__cache_' . $key]; + + if ($type) { + $tagLst[] = '__cache_mer_' . $key . '_' . $type; + $tagLst[] = '__cache_mer_' . $key; + } else { + $tagLst[] = '__cache_sys_' . $key; + } + + if ($tag) { + $tagLst[] = '__cache_tag_' . $key . '_' . $type . '_' . $tag; + } + $this->tag = $tag; + $this->type = $type; + $this->handler = Cache::store('file')->tag($tagLst); + } + + public static function create($admin, $tag) + { + return new static($admin, $tag); + } + + /** + * 清除所以缓存 + */ + public static function clearAll() + { + Cache::store('file')->tag('__cache_' . config('app.app_key'))->clear(); + } + + /** + * 清除商户缓存 + */ + public static function clearMerchantAll() + { + Cache::store('file')->tag('__cache_mer_' . config('app.app_key'))->clear(); + } + + /** + * 清除平台缓存 + */ + public static function clearSystem() + { + Cache::store('file')->tag('__cache_sys_' . config('app.app_key'))->clear(); + } + + /** + * @param int $merId + * 清除指定商户缓存 + */ + public static function clearMerchant($merId) + { + Cache::store('file')->tag('__cache_mer_' . config('app.app_key') . '_' . $merId)->clear(); + } + + /** + * 根据tag清除缓存 + * @param $merId + * @param $tag + */ + public static function clearByTag($merId, $tag) + { + Cache::store('file')->tag('__cache_tag_' . config('app.app_key') . '_' . $merId . '_' . $tag)->clear(); + } + + public static function delete($key) + { + Cache::store('file')->delete($key); + } + + /** + * @param $key + * @return string + * 生成 key + */ + public function cacheKey($key) + { + if (is_array($key)) { + $key = json_encode($key, JSON_UNESCAPED_UNICODE); + } + return '__sys_cache_' . config('app.app_key') . $this->type . $this->tag . $key; + } + + /** + * @param string|array $key + * @param $cache + * @param int $expire + */ + public function set($key, $cache, $expire = 3600) + { + $this->handler->set($this->cacheKey($key), $cache, $expire); + } + + /** + * @param string|array $key + * @param null $default + * @return mixed + */ + public function get($key, $default = null) + { + return $this->handler->get($this->cacheKey($key), $default); + } + + /** + * @param string|array $key + * @return mixed + */ + public function has($key) + { + return $this->handler->has($this->cacheKey($key)); + } + + /** + * @param string|array $key + * @param $value + * @param int $expire + * @return mixed + */ + public function remember($key, $value, $expire = 3600) + { + return $this->handler->remember($this->cacheKey($key), $value, $expire); + } + +} diff --git a/crmeb/services/CombinePayService.php b/crmeb/services/CombinePayService.php new file mode 100644 index 00000000..e98656e7 --- /dev/null +++ b/crmeb/services/CombinePayService.php @@ -0,0 +1,77 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\model\user\User; +use app\common\repositories\wechat\WechatUserRepository; +use think\exception\ValidateException; + +class CombinePayService +{ + protected $type; + protected $options; + + public function __construct(string $type, array $options) + { + $this->type = $type; + $this->options = $options; + } + + public function pay(User $user) + { + $method = 'payCombine' . ucfirst($this->type); + if (!method_exists($this, $method)) { + throw new ValidateException('不支持该支付方式'); + } + return $this->{$method}($user); + } + + public function payCombineWeixin(User $user) + { + $wechatUserRepository = app()->make(WechatUserRepository::class); + $openId = $wechatUserRepository->idByOpenId($user['wechat_user_id']); + if (!$openId) + throw new ValidateException('请关联微信公众号!'); + $config = WechatService::create()->combinePay()->payJs($openId, $this->options); + return compact('config'); + } + + public function payCombineWeixinQr(User $user) + { + $config = WechatService::create()->combinePay()->payNative($this->options); + return ['config' => $config['code_url']]; + } + + public function payCombineRoutine(User $user) + { + $wechatUserRepository = app()->make(WechatUserRepository::class); + $openId = $wechatUserRepository->idByRoutineId($user['wechat_user_id']); + if (!$openId) + throw new ValidateException('请关联微信小程序!'); + $config = MiniProgramService::create()->combinePay()->payJs($openId, $this->options); + return compact('config'); + } + + public function payCombineH5(User $user) + { + $config = WechatService::create()->combinePay()->payH5($this->options, 'Wap'); + return ['config' => ['mweb_url' => $config['h5_url']]]; + } + + public function payCombineWeixinApp(User $user) + { + $config = WechatService::create()->combinePay()->payApp($this->options); + return compact('config'); + } +} diff --git a/crmeb/services/CopyCommand.php b/crmeb/services/CopyCommand.php new file mode 100644 index 00000000..9fb7e01b --- /dev/null +++ b/crmeb/services/CopyCommand.php @@ -0,0 +1,149 @@ + +// +---------------------------------------------------------------------- +namespace crmeb\services; + +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\SpuRepository; +use think\exception\ValidateException; +use think\helper\Str; + +class CopyCommand +{ + protected $type = [ + '0' => 'p/:', //普通商品 + '1' => 's/:', //秒杀商品 + '2' => 'r/:', //预售商品 + '4' => 'g/:', //拼团商品 + '30' => 'sa/:', //助力活动 + '40' => 'gb/:', //拼团活动 + ]; + protected $productType = [ + 'p' => 0, + 's' => 1, + 'r' => 2, + 'g' => 4, + 'sa' => 30, + 'gb' => 40, + ]; + + /** + * TODO 创建口令 + * @param int $id + * @param string $type + * @param $userInfo + * @return string + * @author Qinii + * @day 9/8/21 + */ + public function create(int $id, string $type, $userInfo) + { + $data = $this->getTitle($id, $type); + $str = $this->setNumberToStr($data['id'], $type); + if ($userInfo->uid) $str .= '嗯'.dechex($userInfo->uid); + + return $str. '*/ '.$data['title']; + } + + /** + * TODO 创建口令ID + * @param $id + * @param $type + * @return string + * @author Qinii + * @day 9/8/21 + */ + public function setNumberToStr($id, $type) + { + $count = 10; + $id = dechex($id); + $strlen = strlen($id); + $str = '/@'. $strlen.$this->type[$type]; + $str .= Str::random(($count-$strlen),null); + $str .= $id; + return $str; + } + + /** + * TODO 商品信息 + * @param $id + * @param $type + * @return array + * @author Qinii + * @day 9/8/21 + */ + public function getTitle($id, $type) + { + switch ($type){ + case 0: + $ret = app()->make(ProductRepository::class)->get($id); + $title = $ret->store_name; + break; + case 1: + $ret = app()->make(ProductRepository::class)->get($id); + $title = $ret->store_name; + break; + case 2: + $ret = app()->make(ProductPresellRepository::class)->get($id); + $title = $ret->store_name; + break; + case 4: + $ret = app()->make(ProductGroupRepository::class)->get($id); + $title = $ret->product->store_name; + break; + case 30: + $ret = app()->make(ProductAssistSetRepository::class)->get($id); + if (!$ret) throw new ValidateException('数据不存在'); + $title = $ret->assist->store_name; + break; + case 40: + $ret = app()->make(ProductGroupBuyingRepository::class)->get($id); + if (!$ret) throw new ValidateException('数据不存在'); + $title = $ret->productGroup->product->store_name; + break; + default: + return ; + break; + } + return compact('title','id'); + } + + /** + * TODO 解析口令 + * @param string $key + * @return array + * @author Qinii + * @day 9/8/21 + */ + public function getMassage(string $key) + { + $key = rtrim(ltrim($key)); + try{ + $com = explode('*/',$key)[0].'*/'; + $key = str_replace('/@','',$key); + $keyArray = explode('/:',$key); + $num = substr($keyArray[0],0,1); + $idArray = explode('嗯',$keyArray[1]); + $id = substr($idArray[0],-$num); + $id = hexdec($id); + $type_ = substr($keyArray[0],1); + $uidArray = explode('*/',$idArray[1]); + $uid = hexdec($uidArray[0]); + $type = $this->productType[$type_]; + return compact('type','id','uid','com'); + } catch (\Exception $exception){ + return []; + } + } +} diff --git a/crmeb/services/CopyProductService.php b/crmeb/services/CopyProductService.php new file mode 100644 index 00000000..369b7b94 --- /dev/null +++ b/crmeb/services/CopyProductService.php @@ -0,0 +1,542 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use stdClass; +use think\facade\Cache; +/** + * 复制主流商城商品 + * Class CopyProductService + * @package crmeb\services + */ +class CopyProductService +{ + //接口地址 + protected static $api = [ + 'taobao' => 'https://api03.6bqb.com/taobao/detail', //https://api03.6bqb.com/app/taobao/detail + 'tmall' => 'https://api03.6bqb.com/tmall/detail', + 'jd' => 'https://api03.6bqb.com/jd/detail', + 'pdd' => 'https://api03.6bqb.com/pdd/detail', + 'suning' => 'https://api03.6bqb.com/suning/detail', + 'alibaba' => 'https://api03.6bqb.com/alibaba/detail' + ]; + protected static $apiKey = ''; + //商品默认字段 + protected static $productInfo = [ + 'cate_id' => '', + 'store_name' => '', + 'store_info' => '', + 'unit_name' => '件', + 'price' => 0, + 'keyword' => '', + 'ficti' => 0, + 'ot_price' => 0, + 'give_integral' => 0, + 'postage' => 0, + 'cost' => 0, + 'image' => '', + 'slider_image' => '', + 'video_link' => '', + 'add_time' => 0, + 'stock' => 0, + 'description' => '', + 'description_images' => [], + 'soure_link' => '', + 'temp_id' => '', + 'items' => [], + 'attrs' => [], + 'info' => [], + ]; + + /** + * 整合 + * @param $url + * @param $method + * @param $data + * @return string + */ + public static function makeUrl(string $url, string $method, array $data) + { + $param = ''; + if (strtolower($method) == 'get' && $data) { + foreach ($data as $key => $value) { + $param .= '&' . $key . '=' . $value; + } + } + return $url . '?apikey=' . self::$apiKey . $param; + } + + /** + * @param bool $status + * @param string $msg + * @param array $data + */ + public static function setReturn(bool $status = true, string $msg = 'SUCCESS', array $data = []) + { + return ['status' => $status, 'msg' => $msg, 'data' => $data]; + } + + /** + * + * @param array $data + */ + public static function getInfo(string $type = 'taobao', array $data = [], string $apikey = '') + { + if (!$apikey) { + return self::setReturn(false, '请先去设置复制商品apiKey'); + } + $url = self::$api[$type] ?? ''; + $action = $type . 'Info'; + $deal_action = $type . 'Deal'; + $method = 'get'; + self::$apiKey = $apikey; + if (!$data || !$url || !is_callable(self::class, $action) || !is_callable(self::class, $deal_action)) { + return self::setReturn(false, '暂不支持该平台商品复制'); + } + switch ($type) { + case 'taobao': + case 'tmall': + case 'jd': + case 'pdd': + $method = 'get'; + if (!isset($data['itemid']) || !$data['itemid']) + return self::setReturn(false, '缺少商品ID'); + break; + case 'suning': + $method = 'get'; + if (!isset($data['itemid']) || !$data['itemid']) + return self::setReturn(false, '缺少商品ID'); + if (!isset($data['shopid']) || !$data['shopid']) + return self::setReturn(false, '缺少商户ID'); + break; + } + $url = self::makeUrl($url, $method, $data); + if ($cache_info = Cache::get(md5($url))) { + return self::setReturn(true, 'SUCCESS', $cache_info); + } + + /* + * 测试 节省次数用 + */ +// if (!$info = Cache::get('info'.md5($url))) { +// $info = self::$action($url, $data); +// Cache::set('info'.md5($url),$info); +// } + + $info = self::$action($url, $data); + if (!$info) return self::setReturn(false, '获取商品失败'); + $info = json_decode($info, true); + if (!$info || (!in_array($info['retcode'], ['0000']))) { + return self::setReturn(false, $info['data'], $info); + } + $result = $info['data']; + /* + 可能存在下一页 但是api中没有分页参数 暂留 + */ +// if (isset($info['hasNext']) && $info['hasNext']) { +// $data['page'] = $info['page'] + 1; +// } + + $result = self::$deal_action($result); + if ($result['items']) { + foreach ($result['items'] as $k => $item) { + if ($item['value'] == '') unset($result['items'][$k]); + } + $result['spec_type'] = 1; + $attr = array_values($result['items']); + $result['info'] = self::formatAttr($attr); + }else{ + $result['spec_type'] = 0; + $result['info'] = null; + } + if (!$result['image'] && $result['slider_image']) $result['image'] = $result['slider_image'][0] ?? ''; + if($result['description']){ + $result['description'] = str_replace('data-lazyload','src',$result['description']); + $pattern = '//'; + $replacement = '',$result['description']); + } + Cache::set(md5($url), $result, 3600 * 24); + return self::setReturn(true, 'SUCCESS', $result); + } + + /** + * 获取淘宝商品 + * @param $url + * @param $data + * @param string $method + * @return bool|string + */ + public static function taobaoInfo(string $url, array $data, string $method = 'get') + { + $info = HttpService::request($url, $method, $data); + $result = false; + if ($info) { + $result = $info; + } + return $result; + } + + /** + * 处理获取淘宝的商品 + * @param $data + * @return mixed + */ + public static function taobaoDeal(array $data) + { + $info = $data['item'] ?? []; + $result = self::$productInfo; + if ($info) { + $result['store_name'] = $info['title'] ?? ''; + $result['store_info'] = $info['subTitle'] ?? ''; + $result['slider_image'] = $info['images'] ?? ''; + $result['description'] = $info['desc'] ?? ''; + $result['description_images'] = $info['descImgs'] ?? []; + $items = []; + if (isset($info['props']) && $info['props']) { + foreach ($info['props'] as $key => $prop) { + $item['value'] = $prop['name']; + $item['detail'] = []; + foreach ($prop['values'] as $name) { + $item['detail'][] = $name['name']; + } + $items[] = $item; + } + } + $result['items'] = $items; + } + return $result; + } + + + /** + * 获取天猫商品 + * @param $url + * @param $data + * @param string $method + * @return bool|string + */ + public static function tmallInfo(string $url, array $data, string $method = 'get') + { + $info = HttpService::request($url, $method, $data); + $result = false; + if ($info) { + $result = $info; + } + return $result; + } + + /** + * 处理天猫商品 + * @param $data + * @return mixed + */ + public static function tmallDeal(array $data) + { + $info = $data['item'] ?? []; + $result = self::$productInfo; + if ($info) { + $result['store_name'] = $info['title'] ?? ''; + $result['store_info'] = $info['subTitle'] ?? ''; + $result['slider_image'] = $info['images'] ?? ''; + $result['description'] = $info['desc'] ?? ''; + $result['description_images'] = $info['descImgs'] ?? []; + $items = []; + if (isset($info['props']) && $info['props']) { + foreach ($info['props'] as $key => $prop) { + $item['value'] = $prop['name']; + $item['detail'] = []; + foreach ($prop['values'] as $name) { + $item['detail'][] = $name['name']; + } + $items[] = $item; + } + } + $result['items'] = $items; + } + return $result; + } + + /** + * 获取京东商品 + * @param $url + * @param $data + * @param string $method + * @return bool|string + */ + public static function jdInfo(string $url, array $data, string $method = 'get') + { + $info = HttpService::request($url, $method, $data); + $result = false; + if ($info) { + $result = $info; + } + return $result; + } + + /** + * 处理京东商品 + * @param $data + * @return mixed + */ + public static function jdDeal(array $data) + { + $info = $data['item'] ?? []; + $result = self::$productInfo; + if ($info) { + $result['store_name'] = $info['name'] ?? ''; + $result['store_info'] = $result['store_name']; + $result['price'] = $info['price'] ?? 0; + $result['ot_price'] = $info['originalPrice'] ?? 0; + $result['slider_image'] = $info['images'] ?? []; + $result['description'] = $info['desc'] ?? ''; + $result['description_images'] = $info['descImgs'] ?? []; + $items = []; + if (isset($info['skuProps']) && $info['skuProps']) { + foreach ($info['skuProps'] as $key => $prop) { + $item['value'] = $info['saleProp'][$key] ?? ''; + $item['detail'] = $prop; + $items[] = $item; + } + } + $result['items'] = $items; + } + return $result; + } + + /** + * 获取拼多多商品 + * @param $url + * @param $data + * @param string $method + * @return bool|string + */ + public static function pddInfo(string $url, array $data, string $method = 'get') + { + $info = HttpService::request($url, $method, $data); + $result = false; + if ($info) { + $result = $info; + } + return $result; + } + + /** + * 处理拼多多商品 + * @param $data + * @return mixed + */ + public static function pddDeal(array $data) + { + $info = $data['item'] ?? []; + $result = self::$productInfo; + if ($info) { + $result['store_name'] = $info['goodsName'] ?? ''; + $result['store_info'] = $info['goodsDesc'] ?? ''; + $result['image'] = $info['thumbUrl'] ?? ''; + $result['slider_image'] = $info['banner'] ?? []; + $result['video_link'] = $info['video']['videoUrl'] ?? ''; + $result['price'] = $info['maxNormalPrice'] ?? 0; + $result['ot_price'] = $info['marketPrice'] ?? 0; + $descImgs = []; + if (isset($info['detail']) && $info['detail']) { + foreach ($info['detail'] as $img) { + if (isset($img['url']) && $img['url']) $descImgs[] = $img['url']; + } + } + $result['description_images'] = $descImgs; + $items = []; + if (isset($info['skus']) && $info['skus']) { + $i = $y = 0; + foreach ($info['skus'] as $sku) { + foreach ($sku['specs'] as $key => $spec) { + if ($i == 0) $items[$y]['value'] = $spec['spec_key']; + $items[$y]['detail'][] = $spec['spec_value']; + $y++; + } + $i++; + } + } + foreach ($items as $k => $item) { + $items[$k]['detail'] = array_unique($item['detail']); + } + $result['items'] = $items; + } + return $result; + } + + /** + * 获取苏宁商品 + * @param $url + * @param $data + * @param string $method + * @return bool|string + */ + public static function suningInfo(string $url, array $data, string $method = 'get') + { + $info = HttpService::request($url, $method, $data); + $result = false; + if ($info) { + $result = $info; + } + return $result; + } + + /** + * 处理苏宁商品 + * @param $data + * @return mixed + */ + public static function suningDeal(array $data) + { + $result = self::$productInfo; + if ($data) { + $result['store_name'] = $data['title'] ?? ''; + $result['store_info'] = $result['store_name']; + $result['slider_image'] = $data['images'] ?? []; + $result['price'] = $data['price'] ?? 0; + $result['desc'] = $data['desc'] ?? ''; + $items = []; + if (isset($data['passSubList']) && $data['passSubList']) { + $i = 0; + foreach ($data['passSubList'] as $passSUb) { + $j = 0; + foreach ($passSUb as $key => $sub) { + if ($i == 0) $items[$j]['value'] = $key; + foreach ($sub as $value) { + if (isset($value['characterValueDisplayName']) && $value['characterValueDisplayName']) + $items[$j]['detail'][] = $value['characterValueDisplayName']; + } + $j++; + } + $i++; + } + } + foreach ($items as $k => $item) { + $items[$k]['detail'] = array_unique($item['detail']); + } + $result['items'] = $items; + } + return $result; + } + + /** + * + * @param string $url + * @param array $data + * @param string $method + * @return bool|string + */ + public static function alibabaInfo(string $url, array $data, string $method = 'get') + { + $info = HttpService::request($url, $method, $data); + $result = false; + if ($info) { + $result = $info; + } + return $result; + } + + /** + * @param array $data + * @return array + */ + public static function alibabaDeal(array $data) + { + $result = self::$productInfo; + if ($data) { + $result['store_name'] = $data['title'] ?? ''; + $result['store_info'] = $result['store_name']; + $result['slider_image'] = $data['images'] ?? []; + $result['price'] = $data['price'] ?? 0; + $result['description'] = $data['desc'] ?? ''; + $items = []; + if (isset($data['skuProps']) && $data['skuProps']) { + $i = 0; + foreach ($data['skuProps'] as $passSUb) { + $items[$i]['value'] = $passSUb['prop']; + $items[$i]['detail'] = array_column($passSUb['value'], 'name'); + $i++; + } + } + foreach ($items as $k => $item) { + $items[$k]['detail'] = array_unique($item['detail']); + } + $result['items'] = $items; + } + return $result; + } + + /** + * 格式化规格 + * @param $attr + * @return array + */ + public static function formatAttr(array $attr) + { + $value = attr_format($attr)[1]; + $valueNew = []; + $count = 0; + foreach ($value as $key => $item) { + $detail = $item['detail']; + sort($item['detail'], SORT_STRING); + $suk = implode(',', $item['detail']); + $sukValue[$suk]['image'] = ''; + $sukValue[$suk]['price'] = 0; + $sukValue[$suk]['cost'] = 0; + $sukValue[$suk]['ot_price'] = 0; + $sukValue[$suk]['stock'] = 0; + $sukValue[$suk]['bar_code'] = ''; + $sukValue[$suk]['weight'] = 0; + $sukValue[$suk]['volume'] = 0; + $sukValue[$suk]['brokerage'] = 0; + $sukValue[$suk]['brokerage_two'] = 0; + + foreach (array_keys($detail) as $k => $title) { + if ($title == '') continue; + $header[$k]['title'] = $title; + $header[$k]['align'] = 'center'; + $header[$k]['minWidth'] = 120; + } + foreach (array_values($detail) as $k => $v) { + if ($v == '') continue; + $valueNew[$count]['value' . ($k + 1)] = $v; + $header[$k]['key'] = 'value' . ($k + 1); + } + $valueNew[$count]['detail'] = $detail; + $valueNew[$count]['image'] = $sukValue[$suk]['image'] ?? ''; + $valueNew[$count]['price'] = $sukValue[$suk]['price'] ? floatval($sukValue[$suk]['price']) : 0; + $valueNew[$count]['cost'] = $sukValue[$suk]['cost'] ? floatval($sukValue[$suk]['cost']) : 0; + $valueNew[$count]['ot_price'] = isset($sukValue[$suk]['ot_price']) ? floatval($sukValue[$suk]['ot_price']) : 0; + $valueNew[$count]['stock'] = $sukValue[$suk]['stock'] ? intval($sukValue[$suk]['stock']) : 0; + $valueNew[$count]['bar_code'] = $sukValue[$suk]['bar_code'] ?? ''; + $valueNew[$count]['weight'] = $sukValue[$suk]['weight'] ? floatval($sukValue[$suk]['weight']) : 0; + $valueNew[$count]['volume'] = $sukValue[$suk]['volume'] ? floatval($sukValue[$suk]['volume']) : 0; + $valueNew[$count]['brokerage'] = $sukValue[$suk]['brokerage'] ? floatval($sukValue[$suk]['brokerage']) : 0; + $valueNew[$count]['brokerage_two'] = $sukValue[$suk]['brokerage_two'] ? floatval($sukValue[$suk]['brokerage_two']) : 0; + $count++; + } + $header[] = ['title' => '图片', 'slot' => 'image', 'align' => 'center', 'minWidth' => 80]; + $header[] = ['title' => '售价', 'slot' => 'price', 'align' => 'center', 'minWidth' => 95]; + $header[] = ['title' => '成本价', 'slot' => 'cost', 'align' => 'center', 'minWidth' => 95]; + $header[] = ['title' => '原价', 'slot' => 'ot_price', 'align' => 'center', 'minWidth' => 95]; + $header[] = ['title' => '库存', 'slot' => 'stock', 'align' => 'center', 'minWidth' => 95]; + $header[] = ['title' => '商品编号', 'slot' => 'bar_code', 'align' => 'center', 'minWidth' => 120]; + $header[] = ['title' => '重量(KG)', 'slot' => 'weight', 'align' => 'center', 'minWidth' => 95]; + $header[] = ['title' => '体积(m³)', 'slot' => 'volume', 'align' => 'center', 'minWidth' => 95]; + $header[] = ['title' => '操作', 'slot' => 'action', 'align' => 'center', 'minWidth' => 70]; + $info = ['attr' => $attr, 'value' => $valueNew, 'header' => $header]; + return $info; + } +} diff --git a/crmeb/services/CrmebServeServices.php b/crmeb/services/CrmebServeServices.php new file mode 100644 index 00000000..8d1a9538 --- /dev/null +++ b/crmeb/services/CrmebServeServices.php @@ -0,0 +1,143 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + + +use app\common\repositories\system\config\ConfigValueRepository; +use crmeb\services\express\Express; +use crmeb\services\product\Product; +use crmeb\services\serve\Serve; +use crmeb\services\sms\Sms; +use think\facade\Cache; + +/** + * 平台服务入口 + * Class ServeServices + * @package crmeb\services + */ +class CrmebServeServices +{ + + /** + * SmsTemplateApplyServices constructor. + * @param FormBuilder $builder + */ + public function __construct() + { + + } + + /** + * 获取配置 + * @return array + */ + public function getConfig(array $config = []) + { + return array_merge([ + 'account' => systemConfig('serve_account'), + 'secret' => systemConfig('serve_token') + ], $config); + } + + /** + * 短信 + * @return Sms + */ + public function sms(array $config = []) + { + $account = systemConfig('sms_account'); + if ($account){ + $password = md5($account.systemConfig('sms_token')); + $res = $this->user()->login($account, $password); + + if($res){ + Cache::set('serve_account', $account); + $arr = [ + 'serve_account' => $account, + 'serve_token' => $password, + ]; + app()->make(ConfigValueRepository::class)->setFormData($arr, 0); + + Cache::delete('sms_account'); + + request()->clearCache(); + } + } + return app()->make(Sms::class, [$this->getConfig($config)]); + } + + /** + * 复制商品 + * @return Product + */ + public function copy(array $config = []) + { + return app()->make(Product::class, [$this->getConfig($config)]); + } + + /** + * 电子面单 + * @return Express + */ + public function express(array $config = []) + { + return app()->make(Express::class, [$this->getConfig($config)]); + } + + /** + * 用户 + * @return Serve + */ + public function user(array $config = []) + { + return app()->make(Serve::class, [$this->getConfig($config)]); + } + + /** + * 获取短信模板 + * @param int $page + * @param int $limit + * @param int $type + * @return array + */ + public function getSmsTempsList(int $page, int $limit, int $type) + { + $list = $this->sms()->temps($page, $limit, $type); + foreach ($list['data'] as &$item) { + $item['templateid'] = $item['temp_id']; + switch ((int)$item['temp_type']) { + case 1: + $item['type'] = '验证码'; + break; + case 2: + $item['type'] = '通知'; + break; + case 30: + $item['type'] = '营销短信'; + break; + } + } + return $list; + } + + /** + * TODO 退出 + * @author Qinii + * @day 9/11/21 + */ + public function logout() + { + Cache::delete('sms_account'); + Cache::delete('serve_account'); + app()->make(ConfigValueRepository::class)->clear(['serve_account','serve_token'], 0); + } +} diff --git a/crmeb/services/DeliverySevices.php b/crmeb/services/DeliverySevices.php new file mode 100644 index 00000000..203aeea8 --- /dev/null +++ b/crmeb/services/DeliverySevices.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use crmeb\interfaces\DeliveryInterface; +use crmeb\services\delivery\Delivery; +use crmeb\services\delivery\storage\Dada; +use crmeb\services\delivery\store\Uupt; + +/** + * Class BaseExpress + * @package crmeb\basic + */ +class DeliverySevices +{ + const DELIVERY_TYPE_UU = 2; + const DELIVERY_TYPE_DADA = 1; + + public static function create( $gateway = self::DELIVERY_TYPE_DADA) + { + $gateway = (int)$gateway; + switch ($gateway) { + case 1: + $config = [ + 'app_key' => systemConfig('dada_app_key'), + 'app_secret' => systemConfig('dada_app_sercret'), + 'source_id' => systemConfig('dada_source_id'), + ]; + break; + case 2: + $config = [ + 'app_key' => systemConfig('uupt_appkey'), + 'app_id' => systemConfig('uupt_app_id'), + 'open_id' => systemConfig('uupt_open_id'), + ]; + break; + } + return new Delivery($gateway, $config); + } +} diff --git a/crmeb/services/DownloadImageService.php b/crmeb/services/DownloadImageService.php new file mode 100644 index 00000000..ee3ff44e --- /dev/null +++ b/crmeb/services/DownloadImageService.php @@ -0,0 +1,101 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use think\exception\ValidateException; + +class DownloadImageService +{ + + //存储位置 + protected $path = 'attach'; + + protected $rules = ['thumb', 'thumbWidth', 'thumHeight', 'path']; + + /** + * 获取即将要下载的图片扩展名 + * @param string $url + * @param string $ex + * @return array|string[] + */ + public function getImageExtname($url = '', $ex = 'jpg') + { + $_empty = ['file_name' => '', 'ext_name' => $ex]; + if (!$url) return $_empty; + if (strpos($url, '?')) { + $_tarr = explode('?', $url); + $url = trim($_tarr[0]); + } + $arr = explode('.', $url); + if (!is_array($arr) || count($arr) <= 1) return $_empty; + $ext_name = trim($arr[count($arr) - 1]); + $ext_name = !$ext_name ? $ex : $ext_name; + return ['file_name' => md5($url) . '.' . $ext_name, 'ext_name' => $ext_name]; + } + + /** + * @param $url + * @param string $name + * @param int $upload_type + * @return mixed + * @author xaboy + * @day 2020/8/1 + */ + public function downloadImage($url, $path = 'def', $name = '', $upload_type = null) + { + if (!$name) { + //TODO 获取要下载的文件名称 + $downloadImageInfo = $this->getImageExtname($url); + $name = $downloadImageInfo['file_name']; + if (!$name) throw new ValidateException('上传图片不存在'); + } + checkSuffix($url); + ob_start(); + readfile($url); + $content = ob_get_contents(); + ob_end_clean(); + $size = strlen(trim($content)); + if (!$content || $size <= 2) throw new ValidateException('图片流获取失败'); + $upload = UploadService::create($upload_type); + if ($upload->to($path)->stream($content, $name) === false) { + throw new ValidateException('图片下载失败'); + } + $imageInfo = $upload->getUploadInfo(); + $date['path'] = $imageInfo['dir']; + $date['name'] = $imageInfo['name']; + $date['size'] = $imageInfo['size']; + $date['mime'] = $imageInfo['type']; + return $date; + } + + /** + * @param $name + * @param $arguments + * @return $this + */ + public function __call($name, $arguments) + { + if (in_array($name, $this->rules)) { + if ($name === 'path') { + $this->{$name} = $arguments[0] ?? 'attach'; + } else { + $this->{$name} = $arguments[0] ?? null; + } + return $this; + } else { + throw new \RuntimeException('Method does not exist' . __CLASS__ . '->' . $name . '()'); + } + } +} diff --git a/crmeb/services/ExcelService.php b/crmeb/services/ExcelService.php new file mode 100644 index 00000000..0a6599b0 --- /dev/null +++ b/crmeb/services/ExcelService.php @@ -0,0 +1,759 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use app\common\repositories\store\order\StoreImportDeliveryRepository; +use app\common\repositories\store\order\StoreOrderProfitsharingRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\ExcelRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\system\financial\FinancialRepository; +use app\common\repositories\system\merchant\FinancialRecordRepository; +use app\common\repositories\system\merchant\MerchantIntentionRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserExtractRepository; +use app\common\repositories\user\UserVisitRepository; +use think\Exception; +use think\facade\Db; + +class ExcelService +{ + + public function getAll($data) + { + set_time_limit(0); + ini_set('memory_limit', '-1'); + $this->{$data['type']}($data['where'], $data['excel_id']); + } + + /** + * TODO 导出操作 + * @param $id + * @param $path + * @param $header + * @param $title + * @param array $export + * @param string $filename + * @param array $end + * @param string $suffix + * @author Qinii + * @day 3/17/21 + */ + public function export($id, $path, $header, $title, $export = [], $filename = '',$end = [],$suffix = 'xlsx') + { + try{ + $_path = SpreadsheetExcelService::instance() + ->createOrActive($id) + ->setExcelHeader($header,count($title['mark']) + 2) + ->setExcelTile($title) + ->setExcelContent($export) + ->setExcelEnd($end) + ->excelSave($filename, $suffix, $path); + + app()->make(ExcelRepository::class)->update($id,[ + 'name' => $filename.'.'.$suffix, + 'status' => 1, + 'path' => '/'.$_path + ]); + }catch (Exception $exception){ + app()->make(ExcelRepository::class)->update($id,[ + 'name' => $filename.'.'.$suffix, + 'status' => 2, + 'message' => $exception->getMessage() + ]); + } + } + + /** + * TODO 搜索记录导出 + * @param array $where + * @param int $id + * @author xaboy + * @day 6/10/21 + */ + public function searchLog(array $where, int $id) + { + $header = ['序号', '用户ID', '用户昵称', '用户类型', '搜索词', '搜索时间', '首次访问时间']; + $user_type = [ + 'h5' => 'H5', + 'wechat' => '公众号', + 'routine' => '小程序', + ]; + $export = []; + $title = []; + $query = app()->make(UserVisitRepository::class)->search($where)->with(['user' => function ($query) { + $query->field('uid,nickname,avatar,user_type,create_time'); + }])->order('create_time DESC'); + $count = $query->count(); + $logs = $query->select(); + foreach ($logs as $log) { + $export[] = [ + $log['user_visit_id'], + $log['user'] ? $log['user']['uid'] : '未登录', + $log['user'] ? $log['user']['nickname'] : '未知', + $log['user'] ? ($user_type[$log['user']['user_type']] ?? $log['user']['user_type']) : '未知', + $log['content'], + $log['create_time'], + $log['user'] ? $log['user']['create_time'] : '未知', + ]; + } + $filename = '搜索记录_' . date('YmdHis'); + $foot = []; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 导出订单 + * @param array $where + * @param int $id + * @author Qinii + * @day 2020-08-10 + */ + public function order(array $where, int $page, int $limit ) + { + $paytype = [0 => '余额', 1 => '微信', 2 => '小程序', 3 => 'H5', 4 => '支付宝', 5 => '支付宝扫码', 6 => '微信扫码',]; + $make = app()->make(StoreOrderRepository::class); + $status = $where['status']; + $del = $where['mer_id'] > 0 ? 0 : null; + unset($where['status']); + $query = $make->search($where, $del)->where($make->getOrderType($status))->with([ + 'orderProduct', + 'merchant' => function ($query) {return $query->field('mer_id,mer_name');}, + 'user', + 'spread', + ])->order('order_id ASC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select()->append(['refund_price']); + $export = []; + foreach ($list as $item) { + $product = []; + foreach ($item['orderProduct'] as $value) { + $product[] = [ + $value['cart_info']['product']['store_name'], + $value['cart_info']['productAttr']['sku'] ?: '无', + $value['product_num'].' '. $value['unit_name'], + $value['cart_info']['productAttr']['price'] + ]; + } + $one = [ + $item['merchant']['mer_name'], + $item['order_sn'], + $item['order_type'] ? '核销订单':'普通订单', + $item['spread']['nickname'] ?? '无', + $item['user']['nickname'] ?? $item['uid'], + $product, + $item['coupon_price'] , + $item['pay_postage'], + $value['product_price'], + $item['refund_price'], + $item['real_name'], + $item['user_phone'], + $item['user_address'] ?: '', + $item['delivery_id'] ?: '', + $item['create_time'], + $paytype[$item['pay_type']], + $item['paid'] ? '已支付':'未支付', + $item['remark'] ?: '', + ]; + $export[] = $one; + } + $header = ['商户名称','订单编号','订单类型','推广人','用户信息', '商品名称','商品规格','商品数量','商品价格','优惠','实付邮费(元)','实付金额(元)','已退款金额(元)', '收货人','收货人电话','收货地址','物流/电话','下单时间','支付方式','支付状态','商家备注']; + $filename = '订单列表_'.date('YmdHis'); + $title = ['订单列表','导出时间:'.date('Y-m-d H:i:s',time())]; + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 流水记录导出 + * @param array $where + * @param int $id + * @author Qinii + * @day 2020-08-10 + */ + public function financial(array $where,int $page,int $limit) + { + $_key = [ + 'mer_accoubts' => '财务对账', + 'sys_accoubts' => '财务对账', + 'refund_order' => '退款订单', + 'brokerage_one' => '一级分佣', + 'brokerage_two' => '二级分佣', + 'refund_brokerage_one' => '返还一级分佣', + 'refund_brokerage_two' => '返还二级分佣', + 'order' => '订单支付', + 'order_platform_coupon' => '平台优惠券补贴', + 'refund_platform_coupon' => '退回平台优惠券', + 'order_svip_coupon' => '付费会员卷', + 'refund_svip_coupon' => '退回付费会员卷', + ]; + $make = app()->make(FinancialRecordRepository::class); + $query = $make->search($where)->with([ + 'merchant', + 'orderInfo', + 'refundOrder' + ]); + + $header = ['商户名称','交易流水单号','类型','总订单号','订单号/退款单号','用户名','用户ID','交易类型','收入/支出','金额','创建时间']; + $title = [ + '流水列表', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $export = []; + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + foreach ($list as $v) { + $wx = (substr($v['order_sn'],0,2) === 'wx'); + $export[] = [ + $v['merchant']['mer_name'], + $v['financial_record_sn'], + $wx ? '订单' : '退款单', + $wx ? $v['orderInfo']['groupOrder']['group_order_sn'] : '' , + $wx ? $v['order_sn'] : $v['refundOrder']['refund_order_sn'] , + $v['user_info'], + $v['user_id'], + $_key[$v['financial_type']], + $v['financial_pm'] ? '收入' : '支出', + ($v['financial_pm'] ? '+ ' : '- ') . $v['number'], + $v['create_time'], + ]; + } + + $filename = '流水列表_'.date('YmdHis'); + $foot =[]; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 获取待发货订单 发货信息 + * @param array $where + * @param int $id + * @author Qinii + * @day 3/13/21 + */ + public function delivery(array $where,int $page, int $limit) + { + $make = app()->make(StoreOrderRepository::class); + $where['order_type'] = 0; + $query = $make->search($where)->with(['orderProduct'])->order('order_id ASC'); + $header = ['订单编号','物流公司','物流编码','物流单号', '发货地址','用户信息','手机号','商品信息','支付时间']; + $title = [ + '批量发货单', + '生成时间:' . date('Y-m-d H:i:s',time()), + ]; + $filename = '批量发货单_'.date('YmdHis'); + $export = []; + $count = $query->count(); + $data = $query->page($page,$limit)->select(); + foreach ($data as $item){ + $product = ''; + foreach ($item['orderProduct'] as $value){ + $product = $product.$value['cart_info']['product']['store_name'].'【'. $value['cart_info']['productAttr']['sku'] .'】【' . $value['product_num'].'】'.PHP_EOL; + } + $export[] = [ + $item['order_sn'] ?? '', + '', + $item['delivery_name']??"", + $item['delivery_id']??"", + $item['user_address']??"", + $item['real_name'] ?? '', + $item['user_phone'] ?? '', + $product, + $item['pay_time'] ?? '', + ]; + } + + $foot = []; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 导出 发货导入记录 + * @param array $where + * @param int $id + * @author Qinii + * @day 3/17/21 + */ + public function importDelivery(array $where,int $page,int $limit) + { + $make = app()->make(StoreImportDeliveryRepository::class); + $query = $make->getSearch($where)->order('create_time ASC'); + $title = [ + '发货记录', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['订单编号','物流公司','物流单号', '发货状态','备注']; + $filename = '发货单记录_'.date('YmdHis'); + $export = []; + $count = $query->count(); + $data = $query->page($page,$limit)->select(); + foreach ($data as $item){ + $export[] = [ + $item['order_sn'], + $item['delivery_name'], + $item['delivery_id'], + $item['status'], + $item['mark'], + ]; + } + $foot = []; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 平台/商户 导出日月账单信息 + * @param array $where + * @param int $id + * @author Qinii + * @day 3/25/21 + */ + public function exportFinancial(array $where,int $page, int $limit) + { + /* + order 收入 公共 新订单 + brokerage_one 支出 公共 一级佣金 + brokerage_two 支出 公共 二级佣金 + order_charge 支出 商户 手续费 + order_true 支出 平台 商户入账 + refund_order 支出 公共 退款 + refund_brokerage_one 收入 公共 返还一级佣金 + refund_brokerage_two 收入 公共 返还二级佣金 + refund_charge 收入 商户 返还手续费 + refund_true 收入 平台 商户返还入账 + presell 收入 公共 新订单 + presell_charge 支出 商户 手续费 + presell_true 支出 平台 商户入账 + */ + $financialType = [ + 'order' => '订单支付', + 'presell' => '预售订单(尾款)', + 'brokerage_one' => '一级佣金', + 'brokerage_two' => '二级佣金', + 'order_charge' => '手续费', + 'order_true' => '商户入账', + 'refund_order' => '退款', + 'refund_charge' => '返还手续费', + 'refund_true' => '商户返还入账', + 'presell_charge'=> '预售订单(手续费)', + 'presell_true' => '商户入账', + 'refund_brokerage_one' => '返还一级佣金', + 'refund_brokerage_two' => '返还二级佣金', + 'mer_presell' => '预售订单(总额)', + 'order_presell' => '预售订单(定金)', + 'refund_platform_coupon' => '退回优惠券补贴', + 'order_platform_coupon' => '优惠券补贴', + ]; + $sys_pm_1 = ['order','presell','order_charge','order_presell','presell_charge','refund_brokerage_one','refund_brokerage_two']; + $mer_pm_1 = ['order','presell','refund_charge','refund_brokerage_one','refund_brokerage_two','mer_presell','order_platform_coupon']; + $date_ = $where['date'];unset($where['date']); + $make = app()->make(FinancialRecordRepository::class); + + $query = $make->search($where)->with(['orderInfo','refundOrder','merchant.merchantCategory']); + + if($where['type'] == 1){ + $title_ = '日账单'; + $start_date = $date_.' 00:00:00'; + $end_date = $date_.' 23:59:59'; + $query->whereDay('create_time',$date_); + }else{ + $title_ = '月账单'; + $start_date = (date('Y-m-01', strtotime($date_))); + $end_date = date('Y-m-d', strtotime("$start_date +1 month -1 day")); + $query->whereMonth('create_time',$date_); + } + + + + $income = $make->countIncome($where['type'],$where,$date_); + $expend = $make->countExpend($where['type'],$where,$date_); + $refund = $make->countRefund($where['type'],$where,$date_); + $charge = bcsub($income['number'],$expend['number'],2); + $filename = $title_.'('.$date_.')'.time(); + $export = []; + $limit = 20; + $count = $query->count(); + $i = 1; + $order_make = app()->make(StoreOrderRepository::class); + //平台 + if(!$where['is_mer']){ + $header = ['商户类别','商户分类','商户名称','总订单号','订单编号','交易流水号','交易时间', '对方信息','交易类型','收支金额','备注']; + $list = $query->page($page, $limit)->order('create_time DESC')->select(); + foreach ($list as $value) { + $order = $order_make->get($value['order_id']); + $export[] = [ + $value['merchant']['is_trader'] ? '自营' : '非自营', + $value['merchant']['merchantCategory']['category_name'] ?? '平台', + $value['merchant']['mer_name'] ?? '平台', + $order['groupOrder']['group_order_sn'] ?? '无数据', + $value['order_sn'], + $value['financial_record_sn'], + $value['create_time'], + $value['user_info'], + $financialType[$value['financial_type']], + (in_array($value['financial_type'], $sys_pm_1) ? '+' : '-') . $value['number'], + '' + ]; + } + $foot = [ + '合计:平台应入账手续费 '.$charge, + '收入合计: '.'订单支付'.$income['count'].'笔,'.'实际支付金额共:'.$income['number'].'元;', + '支出合计: '.'佣金支出'.$expend['count_brokerage'].'笔,支出金额:'.$expend['number_brokerage'].'元;商户入账支出'.$expend['count_order'].'笔,支出金额:'.$expend['number_order'].'元;退款手续费'.$expend['count_charge'].'笔,支出金额'.$expend['number_charge'].'元;合计支出'.$expend['number'], + ]; + //商户 + }else{ + $header = ['序号','总订单号','子订单编号','交易流水号','交易时间', '对方信息','交易类型','收支金额','备注']; + $mer_name = ''; + $list = $query->page($page, $limit)->order('create_time DESC')->select(); + foreach ($list as $key => $value) { + $order = $order_make->get($value['order_id']); + $export[] = [ + $i, + $order['groupOrder']['group_order_sn'] ?? '无数据', + $value['order_sn'], + $value['financial_record_sn'], + $value['create_time'], + $value['user_info'], + $financialType[$value['financial_type']], + (in_array($value['financial_type'], $mer_pm_1) ? '+' : '-') . $value['number'], + '' + ]; + $i++; + $mer_name = $mer_name ? $mer_name : ($value['merchant']['mer_name'] ?? ''); + } + + $count_brokeage = $expend['count_brokerage'] + $expend['count_refund_brokerage']; + $number_brokeage = bcsub($expend['number_brokerage'],$expend['number_refund_brokerage'],2); + $count_charge = $expend['count_charge']+$expend['count_order_charge']; + $number_charge = bcsub($expend['number_order_charge'],$expend['number_charge'],2); + $foot = [ + '合计:商户应入金额 '.$charge, + '收入合计: '.'订单支付'.$income['count'].'笔,'.'实际支付金额共:'.$income['number'].'元;', + '支出合计: '.'佣金支出'.$count_brokeage.'笔,支出金额:'.$number_brokeage.'元;退款'.$expend['count_refund'].'笔,支出金额:'.$expend['number_refund'].'元;平台手续费'.$count_charge.'笔,支出金额:'.$number_charge.'元;合计支出金额:'.$expend['number'].'元;', + //'商户应入金额 '.$charge, + ]; + $mer_name = '商户名称:'.$mer_name; + } + + $title = [ + $title_, + $mer_name ?? '平台', + '结算账期:【' .$start_date.'】至【'.$end_date.'】', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 退款单导出 + * @param array $where + * @param int $id + * @author Qinii + * @day 6/10/21 + */ + public function refundOrder(array $where,int $page, int $limit) + { + $query = app()->make(StoreRefundOrderRepository::class)->search($where) + ->where('is_system_del', 0)->with([ + 'order' => function ($query) { + $query->field('order_id,order_sn,activity_type,real_name,user_address'); + }, + 'refundProduct.product', + 'user' => function ($query) { + $query->field('uid,nickname,phone'); + }, + 'merchant' => function ($query) { + $query->field('mer_id,mer_name'); + }, + ])->order('StoreRefundOrder.create_time DESC'); + + $title = [ + '退款订单', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['商户名称','退款单号','申请时间','最新更新时间', '退款金额','退货件量','退货商品信息','退款类型','订单状态','拒绝理由','退货人','退货地址','相关订单号','退货物流公司','退货物流单号','备注']; + $filename = '退款订单'.time(); + + $status = [ + 0 => '待审核', + 1 => '待退货', + 2 => '待收货', + 3 => '已退款', + -1=> '审核未通过', + ]; + $count= $query->count(); + $data = $query->page($page,$limit)->select()->toArray(); + foreach ($data as $datum){ + $product = ''; + foreach ($datum['refundProduct'] as $value){ + $product .= '【'.$value['product']['cart_info']['product']['product_id'].'】'.$value['product']['cart_info']['product']['store_name'].'*'.$value['refund_num'].$value['product']['cart_info']['product']['unit_name'].PHP_EOL; + } + $export[] = [ + $datum['merchant']['mer_name'], + $datum['refund_order_sn'], + $datum['create_time'], + $datum['status_time'] ?? ' ', + $datum['refund_price'], + $datum['refund_num'], + $product, + ($datum['refund_type'] == 1 ) ? '仅退款' : '退款退货', + $status[$datum['status']], + $datum['fail_message'], + $datum['order']['real_name'], + $datum['order']['user_address'], + $datum['order']['order_sn'], + $datum['delivery_type'], + $datum['delivery_id'], + $datum['mark'], + ]; + } + + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 积分日志导出 + * @param $where + * @param $id + * @author Qinii + * @day 6/10/21 + */ + public function integralLog($where,int $page, int $limit) + { + $title = [ + '积分日志', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['用户ID','用户昵称','积分标题','变动积分', '当前积分余额','备注','时间']; + $filename = '积分日志'.time(); + $export = []; + $query = app()->make(UserBillRepository::class)->searchJoin($where)->order('a.create_time DESC'); + $count = $query->count(); + $list = $query->page($page,$limit)->select(); + foreach ($list as $item) { + $export[] = [ + $item['uid'], + $item['nickname'], + $item['title'], + $item['number'], + $item['balance'], + $item['mark'], + $item['create_time'], + ]; + } + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + public function intention($where,int $page, int $limit) + { + $title = [ + '申请列表', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['商户姓名','联系方式','备注','店铺名称','店铺分类','时间']; + $filename = '申请列表'.time(); + $export = []; + $query = app()->make(MerchantIntentionRepository::class)->search($where)->with(['merchantCategory', 'merchantType'])->order('a.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as $item) { + $export[] = [ + $item['name'], + $item['phone'], + $item['mark'], + $item['mer_name'], + $item['category_name'], + $item['create_time'], + ]; + } + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 转账记录 + * @param array $where + * @param int $id + * @author Qinii + * @day 9/28/21 + */ + public function financialLog(array $where, int $page, int $limit) + { + $title = [ + '转账记录', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['商户名称','申请时间','转账金额','到账状态','审核状态','拒绝理由','商户余额','转账信息']; + $filename = '转账记录_'.time(); + $export = []; + $query = app()->make(FinancialRepository::class)->search($where)->with('merchant'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as $item) { + if ($item->financial_type == 1) { + $acount = '姓名:'.$item->financial_account->name.PHP_EOL; + $acount .= '银行名称:'.$item->financial_account->bank.PHP_EOL; + $acount .= '银行卡号:'.$item->financial_account->bank_code; + } + if ($item->financial_type == 2) { + $acount = '姓名:'.$item->financial_account->name.PHP_EOL; + $acount .= '微信号:'.$item->financial_account->wechat.PHP_EOL; + $acount .= '收款二维码地址:'.$item->financial_account->wechat_code; + } + if ($item->financial_type == 3) { + $acount = '姓名:'.$item->financial_account->name.PHP_EOL; + $acount .= '支付宝号:'.$item->financial_account->alipay.PHP_EOL; + $acount .= '收款二维码地址:'.$item->financial_account->alipay_code; + } + $export[] = [ + $item->merchant->mer_name, + $item->create_time, + $item->extract_money, + $item->financial_status == 1 ? '已转账' : '未转账', + $item->status == 1 ? '通过' : ($item->status == 0 ? '待审核' : '拒绝'), + $item->refusal, + $item->mer_money, + $acount, + ]; + } + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 用户提现申请 + * @param array $where + * @param int $id + * @author Qinii + * @day 9/28/21 + */ + public function extract(array $where, int $page, int $limit) + { + $title = [ + '提现申请', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $type = [ + '银行卡', + '微信', + '支付宝', + '微信零钱', + ]; + $header = ['用户名','用户UID','提现金额','余额','审核状态','拒绝理由','提现方式','转账信息']; + $filename = '提现申请_'.time(); + $path = 'extract'; + $export = []; + $query = app()->make(UserExtractRepository::class)->search($where)->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as $item) { + $acount = ''; + if ($item->extract_type == 0) { + $acount .= '银行地址:'.$item->bank_address.PHP_EOL; + $acount .= '银行卡号:'.$item->bank_code; + } + if ($item->extract_type == 2) { + $acount .= '微信号:'.$item->wechat.PHP_EOL; + $acount .= '收款二维码地址:'.$item->extract_pic; + } + if ($item->extract_type == 1) { + $acount .= '支付宝号:'.$item->alipay.PHP_EOL; + $acount .= '收款二维码地址:'.$item->extract_pic; + } + $export[] = [ + $item->real_name, + $item->uid, + $item->extract_price, + $item->balance, + $item->status == 1 ? '通过' : ($item->status == 0 ? '待审核' : '拒绝'), + $item->fail_msg, + $type[$item->extract_type], + $acount, + ]; + } + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 分账管理 + * @param array $where + * @param int $id + * @author Qinii + * @day 9/28/21 + */ + public function profitsharing(array $where, int $page, int $limit) + { + $title = [ + '分账明细', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['订单编号','商户名称','订单类型','状态','分账时间','订单金额']; + $filename = '分账明细_'.time(); + $export = []; + $query = app()->make(StoreOrderProfitsharingRepository::class)->search($where)->with('order','merchant')->order('create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as $item) { + $info = '分账金额:'. $item->profitsharing_price.PHP_EOL; + if(isset($item->profitsharing_price) && $item->profitsharing_price > 0) $info .= '退款金额:'. $item->profitsharing_refund.PHP_EOL; + $info .= '分账给商户金额:'. $item->profitsharing_mer_price; + $export[] = [ + $item->order->order_sn ?? '', + $item->merchant->mer_name, + $item->typeName, + $item->statusName, + $item->profitsharing_time, + $info + ]; + } + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } + + /** + * TODO 资金记录 + * @param array $where + * @param int $id + * @author Qinii + * @day 9/28/21 + */ + public function bill(array $where, int $page, int $limit) + { + $title = [ + '资金记录', + '生成时间:' . date('Y-m-d H:i:s',time()) + ]; + $header = ['用户ID','昵称','金额','明细类型','备注','时间']; + $filename = '资金记录_'.time(); + $export = []; + $query = app()->make(UserBillRepository::class) + ->searchJoin($where)->order('a.create_time DESC'); + $count = $query->count(); + $list = $query->page($page, $limit)->select(); + foreach ($list as $item) { + $export[] = [ + $item->uid, + $item->user->nickname??'', + $item->number, + $item->title, + $item->mark, + $item->create_time, + ]; + } + $export = array_reverse($export); + $foot = ''; + return compact('count','header','title','export','foot','filename'); + } +} diff --git a/crmeb/services/ExpressService.php b/crmeb/services/ExpressService.php new file mode 100644 index 00000000..d696cd10 --- /dev/null +++ b/crmeb/services/ExpressService.php @@ -0,0 +1,123 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\model\store\order\StoreOrder; +use app\common\repositories\store\shipping\ExpressRepository; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Config; + +class ExpressService +{ + const API = 'https://wuliu.market.alicloudapi.com/kdi'; + + public static function query($no, $type = '',$form = []) + { + $express = systemConfig('crmeb_serve_express'); + + if($express == 2){ + //一号通 + return self::serve($no, $type,$form); + } else { + //阿里云 + return self::ali($no, $type); + } + } + + /** + * TODO 一号通查询 + * @param $no + * @param $type + * @return array + * @author Qinii + * @day 8/28/21 + */ + public static function serve($no,$type,$form) + { + $res = app()->make(CrmebServeServices::class)->express()->query($no,'',$form); + if (!$res) $res = app()->make(CrmebServeServices::class)->express()->query($no,$type,$form); + $cacheTime = 1800; + if(!empty($res)){ + if($res['status'] == 3){ + $cacheTime = 0; + } + } + $list = $res['content'] ?? []; + return compact('cacheTime','list'); + } + + /** + * TODO 阿里云查询 + * @param $no + * @param $re + * @return array|bool + * @author Qinii + * @day 8/28/21 + */ + public static function ali($no, $re) + { + //阿里云 + $appCode = systemConfig('express_app_code'); + if (!$appCode) return false; + $type = ''; + + $res = HttpService::getRequest(self::API, compact('no', 'type'), ['Authorization:APPCODE ' . $appCode]); + if (!$res) throw new ValidateException('未查询到快递信息,请确认单号及余额是否充足'); + $result = json_decode($res, true) ?: null; + + if(!is_null($result) && $result['status'] != 200){ + if (in_array($result['status'],[201,203,204,207,205])){ + throw new ValidateException($result['msg']); + } + } + $cacheTime = 1800; + if (is_array($result) && isset($result['result']) && isset($result['result']['deliverystatus']) && $result['result']['deliverystatus'] >= 3){ + $cacheTime = 0; + } + $list = $result['result']['list'] ?? []; + return compact('cacheTime','list'); + } + + /** + * TODO + * @param $sn 快递号 + * @param $name 快递公司 + * @param $phone 收货人手机号 + * @return array|bool|mixed + * @author Qinii + * @day 8/16/21 + */ + public static function express($sn,$name,$phone) + { + $has = Cache::has('express_' . $sn); + if ($has) { + $result = Cache::get('express_' . $sn); + } else { + $suffix = ''; + $is_shunfeng = strtoupper(substr($sn,0,2)); + if ($is_shunfeng == 'SF') { + $suffix = ':'.substr($phone,7); + } + $com = app()->make(ExpressRepository::class)->getSearch(['name' => $name])->value('code'); + $result = self::query($sn.$suffix, $com, ['phone' => $phone]); + if(!empty($result['list'])){ + Cache::set('express_' . $sn, $result['list'], $result['cacheTime']); + $result = $result['list']; + } + } + return $result ?? []; + } +} diff --git a/crmeb/services/FileService.php b/crmeb/services/FileService.php new file mode 100644 index 00000000..170c079d --- /dev/null +++ b/crmeb/services/FileService.php @@ -0,0 +1,1024 @@ + +// +---------------------------------------------------------------------- +namespace crmeb\services; + +use app\services\shipping\ExpressServices; +use think\exception\ValidateException; + +/** + * 文件操作类 + * Class FileService + * @package crmeb\services + */ +class FileService +{ + + /** + * 创建目录 + * @param string $dir + * @return bool + */ + public static function mkDir(string $dir) + { + $dir = rtrim($dir, '/') . '/'; + if (!is_dir($dir)) { + if (mkdir($dir, 0700) == false) { + return false; + } + return true; + } + return true; + } + + /** + * @param $filename 写入文件名 + * @param $writetext 保存内容 + * @param string $openmod 打开方式 + * @return bool + */ + public static function writeFile(string $filename, string $writetext, string $openmod = 'w') + { + if (@$fp = fopen($filename, $openmod)) { + flock($fp, 2); + fwrite($fp, $writetext); + fclose($fp); + return true; + } else { + return false; + } + } + + /** + * 删除目录下所有满足条件文件 + * @param $path 文件目录 + * @param $start 开始时间 + * @param $end 结束时间 + * return bool + */ + public static function del_where_dir($path, $start = '', $end = '') + { + if (!file_exists($path)) { + return false; + } + $dh = @opendir($path); + if ($dh) { + while (($d = readdir($dh)) !== false) { + if ($d == '.' || $d == '..') {//如果为.或.. + continue; + } + $tmp = $path . '/' . $d; + if (!is_dir($tmp)) {//如果为文件 + $file_time = filemtime($tmp); + if ($file_time) { + if ($start != '' && $end != '') { + if ($file_time >= $start && $file_time <= $end) { + @unlink($tmp); + } + } elseif ($start != '' && $end == '') { + if ($file_time >= $start) { + @unlink($tmp); + } + } elseif ($start == '' && $end != '') { + if ($file_time <= $end) { + @unlink($tmp); + } + } else { + @unlink($tmp); + } + } + } else {//如果为目录 + self::delDir($tmp, $start, $end); + } + } + //判断文件夹下是否 还有文件 + $count = count(scandir($path)); + closedir($dh); + if ($count <= 2) @rmdir($path); + } + return true; + } + + /** + * 删除目录 + * @param $dirName + * @return bool + */ + public static function delDir($dirName) + { + if (!file_exists($dirName)) { + return false; + } + + $dir = opendir($dirName); + while ($fileName = readdir($dir)) { + $file = $dirName . '/' . $fileName; + if ($fileName != '.' && $fileName != '..') { + if (is_dir($file)) { + self::delDir($file); + } else { + unlink($file); + } + } + } + closedir($dir); + return rmdir($dirName); + } + + + /** + * 拷贝目录 + * @param string $surDir + * @param string $toDir + * @return bool + */ + public function copyDir(string $surDir, string $toDir) + { + $surDir = rtrim($surDir, '/') . '/'; + $toDir = rtrim($toDir, '/') . '/'; + if (!file_exists($surDir)) { + return false; + } + + if (!file_exists($toDir)) { + $this->createDir($toDir); + } + $file = opendir($surDir); + while ($fileName = readdir($file)) { + $file1 = $surDir . '/' . $fileName; + $file2 = $toDir . '/' . $fileName; + if ($fileName != '.' && $fileName != '..') { + if (is_dir($file1)) { + $this->copyDir($file1, $file2); + } else { + copy($file1, $file2); + } + } + } + closedir($file); + return true; + } + + + /** + * 列出目录 + * @param $dir 目录名 + * @return array 列出文件夹下内容,返回数组 $dirArray['dir']:存文件夹;$dirArray['file']:存文件 + */ + static function getDirs($dir) + { + $dir = rtrim($dir, '/') . '/'; + $dirArray [][] = NULL; + if (false != ($handle = opendir($dir))) { + $i = 0; + $j = 0; + while (false !== ($file = readdir($handle))) { + if (is_dir($dir . $file)) { //判断是否文件夹 + $dirArray ['dir'] [$i] = $file; + $i++; + } else { + $dirArray ['file'] [$j] = $file; + $j++; + } + } + closedir($handle); + } + return $dirArray; + } + + /** + * 统计文件夹大小 + * @param $dir + * @return int 文件夹大小(单位 B) + */ + public static function getSize($dir) + { + $dirlist = opendir($dir); + $dirsize = 0; + while (false !== ($folderorfile = readdir($dirlist))) { + if ($folderorfile != "." && $folderorfile != "..") { + if (is_dir("$dir/$folderorfile")) { + $dirsize += self::getSize("$dir/$folderorfile"); + } else { + $dirsize += filesize("$dir/$folderorfile"); + } + } + } + closedir($dirlist); + return $dirsize; + } + + /** + * 检测是否为空文件夹 + * @param $dir + * @return bool + */ + static function emptyDir($dir) + { + return (($files = @scandir($dir)) && count($files) <= 2); + } + + /** + * 创建多级目录 + * @param string $dir + * @param int $mode + * @return boolean + */ + public function createDir(string $dir, int $mode = 0777) + { + return is_dir($dir) or ($this->createDir(dirname($dir)) and mkdir($dir, $mode)); + } + + /** + * 创建指定路径下的指定文件 + * @param string $path (需要包含文件名和后缀) + * @param boolean $over_write 是否覆盖文件 + * @param int $time 设置时间。默认是当前系统时间 + * @param int $atime 设置访问时间。默认是当前系统时间 + * @return boolean + */ + public function createFile(string $path, bool $over_write = FALSE, int $time = NULL, int $atime = NULL) + { + $path = $this->dirReplace($path); + $time = empty($time) ? time() : $time; + $atime = empty($atime) ? time() : $atime; + if (file_exists($path) && $over_write) { + $this->unlinkFile($path); + } + $aimDir = dirname($path); + $this->createDir($aimDir); + return touch($path, $time, $atime); + } + + /** + * 关闭文件操作 + * @param string $path + * @return boolean + */ + public function close(string $path) + { + return fclose($path); + } + + /** + * 读取文件操作 + * @param string $file + * @return boolean + */ + public static function readFile(string $file) + { + return @file_get_contents($file); + } + + /** + * 确定服务器的最大上传限制(字节数) + * @return int 服务器允许的最大上传字节数 + */ + public function allowUploadSize() + { + $val = trim(ini_get('upload_max_filesize')); + return $val; + } + + /** + * 字节格式化 把字节数格式为 B K M G T P E Z Y 描述的大小 + * @param int $size 大小 + * @param int $dec 显示类型 + * @return int + */ + public static function byteFormat($size, $dec = 2) + { + $a = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + $pos = 0; + while ($size >= 1024) { + $size /= 1024; + $pos++; + } + return round($size, $dec) . " " . $a[$pos]; + } + + /** + * 删除非空目录 + * 说明:只能删除非系统和特定权限的文件,否则会出现错误 + * @param string $dirName 目录路径 + * @param boolean $is_all 是否删除所有 + * @param boolean $delDir 是否删除目录 + * @return boolean + */ + public function removeDir(str $dir_path, bool $is_all = FALSE) + { + $dirName = $this->dirReplace($dir_path); + $handle = @opendir($dirName); + while (($file = @readdir($handle)) !== FALSE) { + if ($file != '.' && $file != '..') { + $dir = $dirName . '/' . $file; + if ($is_all) { + is_dir($dir) ? $this->removeDir($dir) : $this->unlinkFile($dir); + } else { + if (is_file($dir)) { + $this->unlinkFile($dir); + } + } + } + } + closedir($handle); + return @rmdir($dirName); + } + + /** + * 获取完整文件名 + * @param string $fn 路径 + * @return string + */ + public function getBasename(string $file_path) + { + $file_path = $this->dirReplace($file_path); + return basename(str_replace('\\', '/', $file_path)); + //return pathinfo($file_path,PATHINFO_BASENAME); + } + + /** + * 获取文件后缀名 + * @param string $file_name 文件路径 + * @return string + */ + public static function getExt(string $file) + { + $file = self::dirReplace($file); + return pathinfo($file, PATHINFO_EXTENSION); + } + + /** + * 取得指定目录名称 + * @param string $path 文件路径 + * @param int $num 需要返回以上级目录的数 + * @return string + */ + public function fatherDir(string $path, $num = 1) + { + $path = $this->dirReplace($path); + $arr = explode('/', $path); + if ($num == 0 || count($arr) < $num) return pathinfo($path, PATHINFO_BASENAME); + return substr(strrev($path), 0, 1) == '/' ? $arr[(count($arr) - (1 + $num))] : $arr[(count($arr) - $num)]; + } + + /** + * 删除文件 + * @param string $path + * @return boolean + */ + public function unlinkFile(string $path) + { + $path = $this->dirReplace($path); + if (file_exists($path)) { + return unlink($path); + } + } + + /** + * 文件操作(复制/移动) + * @param string $old_path 指定要操作文件路径(需要含有文件名和后缀名) + * @param string $new_path 指定新文件路径(需要新的文件名和后缀名) + * @param string $type 文件操作类型 + * @param boolean $overWrite 是否覆盖已存在文件 + * @return boolean + */ + public function handleFile(string $old_path, string $new_path, string $type = 'copy', bool $overWrite = FALSE) + { + $old_path = $this->dirReplace($old_path); + $new_path = $this->dirReplace($new_path); + if (file_exists($new_path) && $overWrite = FALSE) { + return FALSE; + } else if (file_exists($new_path) && $overWrite = TRUE) { + $this->unlinkFile($new_path); + } + + $aimDir = dirname($new_path); + $this->createDir($aimDir); + switch ($type) { + case 'copy': + return copy($old_path, $new_path); + break; + case 'move': + return @rename($old_path, $new_path); + break; + } + } + + /** + * 文件夹操作(复制/移动) + * @param string $old_path 指定要操作文件夹路径 + * @param string $aimDir 指定新文件夹路径 + * @param string $type 操作类型 + * @param boolean $overWrite 是否覆盖文件和文件夹 + * @return boolean + */ + public function handleDir(string $old_path, string $new_path, string $type = 'copy', bool $overWrite = FALSE) + { + $new_path = $this->checkPath($new_path); + $old_path = $this->checkPath($old_path); + if (!is_dir($old_path)) return FALSE; + + if (!file_exists($new_path)) $this->createDir($new_path); + + $dirHandle = opendir($old_path); + + if (!$dirHandle) return FALSE; + + $boolean = TRUE; + + while (FALSE !== ($file = readdir($dirHandle))) { + if ($file == '.' || $file == '..') continue; + + if (!is_dir($old_path . $file)) { + $boolean = $this->handleFile($old_path . $file, $new_path . $file, $type, $overWrite); + } else { + $this->handleDir($old_path . $file, $new_path . $file, $type, $overWrite); + } + } + switch ($type) { + case 'copy': + closedir($dirHandle); + return $boolean; + break; + case 'move': + closedir($dirHandle); + return @rmdir($old_path); + break; + } + } + + /** + * 替换相应的字符 + * @param string $path 路径 + * @return string + */ + public static function dirReplace(string $path) + { + return str_replace('//', '/', str_replace('\\', '/', $path)); + } + + /** + * 读取指定路径下模板文件 + * @param string $path 指定路径下的文件 + * @return string $rstr + */ + public static function getTempltes(string $path) + { + $path = self::dirReplace($path); + if (file_exists($path)) { + $fp = fopen($path, 'r'); + $rstr = fread($fp, filesize($path)); + fclose($fp); + return $rstr; + } else { + return ''; + } + } + + /** + * @param string $oldname 原始名称 + * @param string $newname 新名称 + * @return bool + */ + public function rename(string $oldname, string $newname) + { + if (($newname != $oldname) && is_writable($oldname)) { + return rename($oldname, $newname); + } + } + + /** + * 获取指定路径下的信息 + * @param string $dir 路径 + * @return ArrayObject + */ + public function getDirInfo(string $dir) + { + $handle = @opendir($dir);//打开指定目录 + $directory_count = 0; + while (FALSE !== ($file_path = readdir($handle))) { + if ($file_path != "." && $file_path != "..") { + //is_dir("$dir/$file_path") ? $sizeResult += $this->get_dir_size("$dir/$file_path") : $sizeResult += filesize("$dir/$file_path"); + $next_path = $dir . '/' . $file_path; + if (is_dir($next_path)) { + $directory_count++; + $result_value = self::getDirInfo($next_path); + $total_size += $result_value['size']; + $file_cout += $result_value['filecount']; + $directory_count += $result_value['dircount']; + } elseif (is_file($next_path)) { + $total_size += filesize($next_path); + $file_cout++; + } + } + } + closedir($handle);//关闭指定目录 + $result_value['size'] = $total_size; + $result_value['filecount'] = $file_cout; + $result_value['dircount'] = $directory_count; + return $result_value; + } + + /** + * 指定文件编码转换 + * @param string $path 文件路径 + * @param string $input_code 原始编码 + * @param string $out_code 输出编码 + * @return boolean + */ + public function changeFileCode(string $path, string $input_code, string $out_code) + { + if (is_file($path))//检查文件是否存在,如果存在就执行转码,返回真 + { + $content = file_get_contents($path); + $content = string::chang_code($content, $input_code, $out_code); + $fp = fopen($path, 'w'); + return fputs($fp, $content) ? TRUE : FALSE; + fclose($fp); + } + } + + /** + * 指定目录下指定条件文件编码转换 + * @param string $dirname 目录路径 + * @param string $input_code 原始编码 + * @param string $out_code 输出编码 + * @param boolean $is_all 是否转换所有子目录下文件编码 + * @param string $exts 文件类型 + * @return boolean + */ + public function changeDirFilesCode(string $dirname, string $input_code, string $out_code, bool $is_all = TRUE, string $exts = '') + { + if (is_dir($dirname)) { + $fh = opendir($dirname); + while (($file = readdir($fh)) !== FALSE) { + if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) { + continue; + } + $filepath = $dirname . '/' . $file; + + if (is_dir($filepath) && $is_all == TRUE) { + $files = $this->changeDirFilesCode($filepath, $input_code, $out_code, $is_all, $exts); + } else { + if ($this->getExt($filepath) == $exts && is_file($filepath)) { + $boole = $this->changeFileCode($filepath, $input_code, $out_code, $is_all, $exts); + if (!$boole) continue; + } + } + } + closedir($fh); + return TRUE; + } else { + return FALSE; + } + } + + /** + * 列出指定目录下符合条件的文件和文件夹 + * @param string $dirname 路径 + * @param boolean $is_all 是否列出子目录中的文件 + * @param string $exts 需要列出的后缀名文件 + * @param string $sort 数组排序 + * @return ArrayObject + */ + public function listDirInfo(string $dirname, bool $is_all = FALSE, string $exts = '', string $sort = 'ASC') + { + //处理多于的/号 + $new = strrev($dirname); + if (strpos($new, '/') == 0) { + $new = substr($new, 1); + } + $dirname = strrev($new); + + $sort = strtolower($sort);//将字符转换成小写 + + $files = []; + $subfiles = []; + + if (is_dir($dirname)) { + $fh = opendir($dirname); + while (($file = readdir($fh)) !== FALSE) { + if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) continue; + + $filepath = $dirname . '/' . $file; + + switch ($exts) { + case '*': + if (is_dir($filepath) && $is_all == TRUE) { + $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort)); + } + array_push($files, $filepath); + break; + case 'folder': + if (is_dir($filepath) && $is_all == TRUE) { + $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort)); + array_push($files, $filepath); + } elseif (is_dir($filepath)) { + array_push($files, $filepath); + } + break; + case 'file': + if (is_dir($filepath) && $is_all == TRUE) { + $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort)); + } elseif (is_file($filepath)) { + array_push($files, $filepath); + } + break; + default: + if (is_dir($filepath) && $is_all == TRUE) { + $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort)); + } elseif (preg_match("/\.($exts)/i", $filepath) && is_file($filepath)) { + array_push($files, $filepath); + } + break; + } + + switch ($sort) { + case 'asc': + sort($files); + break; + case 'desc': + rsort($files); + break; + case 'nat': + natcasesort($files); + break; + } + } + closedir($fh); + return $files; + } else { + return FALSE; + } + } + + /** + * 返回指定路径的文件夹信息,其中包含指定路径中的文件和目录 + * @param string $dir + * @return ArrayObject + */ + public function dirInfo(string $dir) + { + return scandir($dir); + } + + /** + * 判断目录是否为空 + * @param string $dir + * @return boolean + */ + public function isEmpty(string $dir) + { + $handle = opendir($dir); + while (($file = readdir($handle)) !== false) { + if ($file != '.' && $file != '..') { + closedir($handle); + return true; + } + } + closedir($handle); + return false; + } + + /** + * 返回指定文件和目录的信息 + * @param string $file + * @return ArrayObject + */ + public static function listInfo(string $file) + { + $dir = []; + $dir['filename'] = basename($file);//返回路径中的文件名部分。 + $dir['pathname'] = strstr(php_uname('s'), 'Windows') ? str_replace('\\', '\\\\', realpath($file)) : realpath($file);//返回绝对路径名。 + $dir['owner'] = fileowner($file);//文件的 user ID (所有者)。 + $dir['perms'] = fileperms($file);//返回文件的 inode 编号。 + $dir['inode'] = fileinode($file);//返回文件的 inode 编号。 + $dir['group'] = filegroup($file);//返回文件的组 ID。 + $dir['path'] = dirname($file);//返回路径中的目录名称部分。 + $dir['atime'] = fileatime($file);//返回文件的上次访问时间。 + $dir['ctime'] = filectime($file);//返回文件的上次改变时间。 + $dir['perms'] = fileperms($file);//返回文件的权限。 + $dir['size'] = self::byteFormat(filesize($file), 2);//返回文件大小。 + $dir['type'] = filetype($file);//返回文件类型。 + $dir['ext'] = is_file($file) ? pathinfo($file, PATHINFO_EXTENSION) : '';//返回文件后缀名 + $dir['mtime'] = filemtime($file);//返回文件的上次修改时间。 + $dir['isDir'] = is_dir($file);//判断指定的文件名是否是一个目录。 + $dir['isFile'] = is_file($file);//判断指定文件是否为常规的文件。 + $dir['isLink'] = is_link($file);//判断指定的文件是否是连接。 + $dir['isReadable'] = is_readable($file);//判断文件是否可读。 + $dir['isWritable'] = is_writable($file);//判断文件是否可写。 + $dir['isUpload'] = is_uploaded_file($file);//判断文件是否是通过 HTTP POST 上传的。 + return $dir; + } + + /** + * 返回关于打开文件的信息 + * @param $file + * @return ArrayObject + * 数字下标 关联键名(自 PHP 4.0.6) 说明 + * 0 dev 设备名 + * 1 ino 号码 + * 2 mode inode 保护模式 + * 3 nlink 被连接数目 + * 4 uid 所有者的用户 id + * 5 gid 所有者的组 id + * 6 rdev 设备类型,如果是 inode 设备的话 + * 7 size 文件大小的字节数 + * 8 atime 上次访问时间(Unix 时间戳) + * 9 mtime 上次修改时间(Unix 时间戳) + * 10 ctime 上次改变时间(Unix 时间戳) + * 11 blksize 文件系统 IO 的块大小 + * 12 blocks 所占据块的数目 + */ + public function openInfo(string $file) + { + $file = fopen($file, "r"); + $result = fstat($file); + fclose($file); + return $result; + } + + /** + * 改变文件和目录的相关属性 + * @param string $file 文件路径 + * @param string $type 操作类型 + * @param string $ch_info 操作信息 + * @return boolean + */ + public function change_file($file, $type, $ch_info) + { + switch ($type) { + case 'group' : + $is_ok = chgrp($file, $ch_info);//改变文件组。 + break; + case 'mode' : + $is_ok = chmod($file, $ch_info);//改变文件模式。 + break; + case 'ower' : + $is_ok = chown($file, $ch_info);//改变文件所有者。 + break; + } + } + + /** + * 取得文件路径信息 + * @param $full_path 完整路径 + * @return ArrayObject + */ + public function getFileType(string $path) + { + //pathinfo() 函数以数组的形式返回文件路径的信息。 + //---------$file_info = pathinfo($path); echo file_info['extension'];----------// + //extension取得文件后缀名【pathinfo($path,PATHINFO_EXTENSION)】-----dirname取得文件路径【pathinfo($path,PATHINFO_DIRNAME)】-----basename取得文件完整文件名【pathinfo($path,PATHINFO_BASENAME)】-----filename取得文件名【pathinfo($path,PATHINFO_FILENAME)】 + return pathinfo($path); + } + + /** + * 取得上传文件信息 + * @param $file file属性信息 + * @return array + */ + public function getUploadFileInfo($file) + { + $file_info = request()->file($file);//取得上传文件基本信息 + $info = []; + $info['type'] = strtolower(trim(stripslashes(preg_replace("/^(.+?);.*$/", "\\1", $file_info['type'])), '"'));//取得文件类型 + $info['temp'] = $file_info['tmp_name'];//取得上传文件在服务器中临时保存目录 + $info['size'] = $file_info['size'];//取得上传文件大小 + $info['error'] = $file_info['error'];//取得文件上传错误 + $info['name'] = $file_info['name'];//取得上传文件名 + $info['ext'] = $this->getExt($file_info['name']);//取得上传文件后缀 + return $info; + } + + /** + * 设置文件命名规则 + * @param string $type 命名规则 + * @param string $filename 文件名 + * @return string + */ + public function setFileName(string $type) + { + switch ($type) { + case 'hash' : + $new_file = md5(uniqid(mt_rand()));//mt_srand()以随机数md5加密来命名 + break; + case 'time' : + $new_file = time(); + break; + default : + $new_file = date($type, time());//以时间格式来命名 + break; + } + return $new_file; + } + + /** + * 文件保存路径处理 + * @return string + */ + public function checkPath($path) + { + return (preg_match('/\/$/', $path)) ? $path : $path . '/'; + } + + /** + * 文件下载 + * $save_dir 保存路径 + * $filename 文件名 + * @return array + */ + public static function downRemoteFile(string $url, string $save_dir = '', string $filename = '', int $type = 0) + { + + if (trim($url) == '') { + return ['file_name' => '', 'save_path' => '', 'error' => 1]; + } + if (trim($save_dir) == '') { + $save_dir = './'; + } + if (trim($filename) == '') {//保存文件名 + $ext = strrchr($url, '.'); + // if($ext!='.gif'&&$ext!='.jpg'){ + // return ['file_name'=>'','save_path'=>'','error'=>3]; + // } + $filename = time() . $ext; + } + if (0 !== strrpos($save_dir, '/')) { + $save_dir .= '/'; + } + //创建保存目录 + if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) { + return ['file_name' => '', 'save_path' => '', 'error' => 5]; + } + //获取远程文件所采用的方法 + if ($type) { + $ch = curl_init(); + $timeout = 5; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); + $img = curl_exec($ch); + curl_close($ch); + } else { + ob_start(); + readfile($url); + $img = ob_get_contents(); + ob_end_clean(); + } + //$size=strlen($img); + //文件大小 + $fp2 = fopen($save_dir . $filename, 'a'); + + fwrite($fp2, $img); + fclose($fp2); + unset($img, $url); + return ['file_name' => $filename, 'save_path' => $save_dir . $filename, 'error' => 0]; + } + + /** + * 解压zip文件 + * @param string $filename + * @param string $savename + * @return bool + */ + public static function zipOpen(string $filename, string $savename) + { + $zip = new \ZipArchive; + $zipfile = $filename; + $res = $zip->open($zipfile); + $toDir = $savename; + if (!file_exists($toDir)) mkdir($toDir, 0777); + $docnum = $zip->numFiles; + for ($i = 0; $i < $docnum; $i++) { + $statInfo = $zip->statIndex($i); + if ($statInfo['crc'] == 0 && $statInfo['comp_size'] != 2) { + //新建目录 + mkdir($toDir . '/' . substr($statInfo['name'], 0, -1), 0777); + } else { + //拷贝文件 + copy('zip://' . $zipfile . '#' . $statInfo['name'], $toDir . '/' . $statInfo['name']); + } + } + $zip->close(); + return true; + } + + /** + *设置字体格式 + * @param $title string 必选 + * return string + */ + public static function setUtf8($title) + { + return iconv('utf-8', 'gb2312', $title); + } + + /** + *检查指定文件是否能写入 + * @param $file string 必选 + * return boole + */ + public static function isWritable($file) + { + $file = str_replace('\\', '/', $file); + if (!file_exists($file)) return false; + return is_writable($file); + } + + /**读取excel文件内容 + * @param $filePath + * @param string $suffix + * @return bool + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function readExcel($filePath, $row_num = 1, $suffix = 'Xlsx') + { + if (!$filePath) return false; + $pathInfo = pathinfo($filePath, PATHINFO_EXTENSION); + if (!$pathInfo || $pathInfo != "xlsx") throw new ValidateException('必须上传xlsx格式文件'); + //加载读取模型 + $readModel = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($suffix); + // 创建读操作 + // 打开文件 载入excel表格 + try { + $spreadsheet = $readModel->load($filePath); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getHighestColumn(); + $highestRow = $sheet->getHighestRow(); + $lines = $highestRow - 1; + if ($lines <= 0) { + throw new ValidateException('数据不能为空'); + } + // 用于存储表格数据 + $data = []; + for ($i = $row_num; $i <= $highestRow; $i++) { + $t1 = $this->objToStr($sheet->getCellByColumnAndRow(1, $i)->getValue()) ?? ''; + $t2 = $this->objToStr($sheet->getCellByColumnAndRow(2, $i)->getValue()); + if ($t2) { + $data[] = [ + 'key' => $t1, + 'value' => $t2 + ]; + } + } + return $data; + } catch (\Exception $e) { + throw new ValidateException($e->getMessage()); + } + } + + /**对象转字符 + * @param $value + * @return mixed + */ + public function objToStr($value) + { + return is_object($value) ? $value->__toString() : $value; + } + + /** + * 压缩文件夹及文件 + * @param string $source 需要压缩的文件夹/文件路径 + * @param string $destination 压缩后的保存地址 + * @param string $folder 文件夹前缀,保存时需要去掉的父级文件夹 + * @return boolean + */ + function addZip($source, $destination, $folder = '') + { + if (!extension_loaded('zip') || !file_exists($source)) { + return false; + } + + $zip = new \ZipArchive; + if (!$zip->open($destination, $zip::CREATE)) { + return false; + } + $source = str_replace('\\', '/', $source); + $folder = str_replace('\\', '/', $folder); + if (is_dir($source) === true) { + $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST); + foreach ($files as $file) { + $file = str_replace('\\', '/', $file); + if (in_array(substr($file, strrpos($file, '/') + 1), array('.', '..'))) continue; + if (is_dir($file) === true) { + $zip->addEmptyDir(str_replace($folder . '/', '', $file . '/')); + } else if (is_file($file) === true) { + $zip->addFromString(str_replace($folder . '/', '', $file), file_get_contents($file)); + } + } + } else if (is_file($source) === true) { + $zip->addFromString(basename($source), file_get_contents($source)); + } + return $zip->close(); + } + +} diff --git a/crmeb/services/HttpService.php b/crmeb/services/HttpService.php new file mode 100644 index 00000000..6856066a --- /dev/null +++ b/crmeb/services/HttpService.php @@ -0,0 +1,138 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + +class HttpService +{ + //错误信息 + private static $curlError; + //header头信息 + private static $headerStr; + //请求状态 + private static $status; + + /** + * @return string + */ + public static function getCurlError() + { + return self::$curlError; + } + + /** + * @return mixed + */ + public static function getStatus() + { + return self::$status; + } + + /** + * 模拟GET发起请求 + * @param $url + * @param array $data + * @param bool $header + * @param int $timeout + * @return bool|string + */ + public static function getRequest($url, $data = array(), $header = false, $timeout = 10) + { + if (!empty($data)) { + $url .= (stripos($url, '?') === false ? '?' : '&'); + $url .= (is_array($data) ? http_build_query($data) : $data); + } + + return self::request($url, 'get', array(), $header, $timeout); + } + + /** + * curl 请求 + * @param $url + * @param string $method + * @param array $data + * @param bool $header + * @param int $timeout + * @return bool|string + */ + public static function request($url, $method = 'get', $data = array(), $header = false, $timeout = 15) + { + self::$status = null; + self::$curlError = null; + self::$headerStr = null; + + $curl = curl_init($url); + $method = strtoupper($method); + //请求方式 + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); + //post请求 + if ($method == 'POST') curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + //超时时间 + curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); + //设置header头 + if ($header !== false) curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + + curl_setopt($curl, CURLOPT_FAILONERROR, false); + //返回抓取数据 + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + //输出header头信息 + curl_setopt($curl, CURLOPT_HEADER, true); + //TRUE 时追踪句柄的请求字符串,从 PHP 5.1.3 开始可用。这个很关键,就是允许你查看请求header + curl_setopt($curl, CURLINFO_HEADER_OUT, true); + //https请求 + if (1 == strpos("$" . $url, "https://")) { + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + } + self::$curlError = curl_error($curl); + + list($content, $status) = [curl_exec($curl), curl_getinfo($curl), curl_close($curl)]; + self::$status = $status; + self::$headerStr = trim(substr($content, 0, $status['header_size'])); + $content = trim(substr($content, $status['header_size'])); + return (intval($status["http_code"]) === 200) ? $content : false; + } + + /** + * 模拟POST发起请求 + * @param $url + * @param array $data + * @param bool $header + * @param int $timeout + * @return bool|string + */ + public static function postRequest($url, array $data = array(), $header = false, $timeout = 10) + { + return self::request($url, 'post', $data, $header, $timeout); + } + + /** + * 获取header头字符串类型 + * @return mixed + */ + public static function getHeaderStr() + { + return self::$headerStr; + } + + /** + * 获取header头数组类型 + * @return array + */ + public static function getHeader() + { + $headArr = explode("\r\n", self::$headerStr); + return $headArr; + } + +} diff --git a/crmeb/services/ImageWaterMarkService.php b/crmeb/services/ImageWaterMarkService.php new file mode 100644 index 00000000..3be4d08b --- /dev/null +++ b/crmeb/services/ImageWaterMarkService.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use think\exception\ValidateException; + +class ImageWaterMarkService +{ + public function run($in_img, $water_text = '商城入驻专用其它无效', $font_size = 30, $water_w = 300, $water_h = 450, $angle = -45) + { + if (!is_file($in_img)) + throw new ValidateException('图片不存在'); + $font = public_path() . 'font/simsunb.ttf'; + $info = getimagesize($in_img); + //通过编号获取图像类型 + $type = image_type_to_extension($info[2], false); + //在内存中创建和图像类型一样的图像 + $fun = "imagecreatefrom" . $type; + //图片复制到内存 + $image = $fun($in_img); + //设置字体颜色和透明度 + $color = imagecolorallocatealpha($image, 190, 190, 190, 0.3); + $x_length = $info[0]; + $y_length = $info[1]; + //铺满屏幕 + for ($x = 10; $x < $x_length; $x) { + for ($y = 20; $y < $y_length; $y) { + imagettftext($image, $font_size, $angle, $x, $y, $color, $font, $water_text); + $y += $water_h; + } + $x += $water_w; + } + //浏览器输出 保存图片的时候 需要去掉 + //header("Content-type:".$info['mime']); + $fun = "image" . $type; +// $fun($image); + //保存图片 + $fun($image, $in_img); + //销毁图片 + imagedestroy($image); + } +} diff --git a/crmeb/services/JwtTokenService.php b/crmeb/services/JwtTokenService.php new file mode 100644 index 00000000..8c316adc --- /dev/null +++ b/crmeb/services/JwtTokenService.php @@ -0,0 +1,87 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use crmeb\exceptions\AuthException; +use Firebase\JWT\BeforeValidException; +use Firebase\JWT\ExpiredException; +use Firebase\JWT\JWT; +use Firebase\JWT\SignatureInvalidException; +use think\facade\Config; +use UnexpectedValueException; + +class JwtTokenService +{ + /** + * @param int $id + * @param string $type + * @param $exp + * @param array $params + * @return array + * @author xaboy + * @day 2020/10/13 + */ + public function createToken(int $id, string $type, $exp, array $params = []) + { + $time = time(); + $host = app('request')->host(); + $params += [ + 'iss' => $host, + 'aud' => $host, + 'iat' => $time, + 'nbf' => $time, + 'exp' => $exp, + ]; + $params['jti'] = [$id, $type]; + $token = JWT::encode($params, Config::get('app.app_key', 'default')); + $params['token'] = $token; + $params['out'] = $exp - time(); + return $params; + } + + /** + * @param string $token + * @return object + * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed + * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf' + * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat' + * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim + * @throws UnexpectedValueException Provided JWT was invalid + * @author xaboy + * @day 2020-04-09 + */ + public function parseToken(string $token) + { + return JWT::decode($token, Config::get('app.app_key', 'default'), array('HS256')); + } + + /** + * @param string $token + * @return object + * @author xaboy + * @day 2020-04-10 + */ + public function decode(string $token) + { + $tks = explode('.', $token); + if (count($tks) != 3) + throw new AuthException('Invalid token'); + + if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($tks[1]))) + throw new AuthException('Invalid token'); + + return $payload; + } +} diff --git a/crmeb/services/LockService.php b/crmeb/services/LockService.php new file mode 100644 index 00000000..9cd18011 --- /dev/null +++ b/crmeb/services/LockService.php @@ -0,0 +1,52 @@ +lock($key, $key, $ex); + return $fn(); + } finally { + $this->unlock($key, $key); + } + } + + public function tryLock($key, $value = '1', $ex = 6) + { + return Cache::store('redis')->handler()->set('lock_' . $key, $value, ["NX", "EX" => $ex]); + } + + public function lock($key, $value = '1', $ex = 6) + { + if ($this->tryLock($key, $value, $ex)) { + return true; + } + System::sleep(1); + return $this->lock($key, $value, $ex); + } + + public function unlock($key, $value = '1') + { + $script = <<< EOF +if (redis.call("get", "lock_" .. KEYS[1]) == ARGV[1]) then + return redis.call("del", "lock_" .. KEYS[1]) +else + return 0 +end +EOF; + return Cache::store('redis')->handler()->eval($script, [$key, $value], 1) > 0; + } +} \ No newline at end of file diff --git a/crmeb/services/MiniProgramService.php b/crmeb/services/MiniProgramService.php new file mode 100644 index 00000000..11c85288 --- /dev/null +++ b/crmeb/services/MiniProgramService.php @@ -0,0 +1,583 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use crmeb\exceptions\WechatException; +use crmeb\services\easywechat\broadcast\Client; +use crmeb\services\easywechat\broadcast\ServiceProvider; +use crmeb\services\easywechat\subscribe\ProgramProvider; +use EasyWeChat\Foundation\Application; +use EasyWeChat\Material\Temporary; +use EasyWeChat\MiniProgram\MiniProgram; +use EasyWeChat\Payment\Order; +use EasyWeChat\Payment\Payment; +use EasyWeChat\Support\Collection; +use Psr\Http\Message\ResponseInterface; +use think\exception\ValidateException; +use think\facade\Log; +use think\facade\Route; + +/** + * Class MiniProgramService + * @package crmeb\services + * @author xaboy + * @day 2020-05-11 + */ +class MiniProgramService +{ + /** + * @var MiniProgram + */ + protected $service; + + protected $config; + + /** + * MiniProgramService constructor. + * @param array $config + */ + public function __construct(array $config) + { + $this->config = $config; + $this->service = new Application($config); + $this->service->register(new ServiceProvider()); + $this->service->register(new ProgramProvider()); + $this->service->register(new \crmeb\services\easywechat\certficates\ServiceProvider); + $this->service->register(new \crmeb\services\easywechat\combinePay\ServiceProvider); + $this->service->register(new \crmeb\services\easywechat\msgseccheck\ServiceProvider); + $this->service->register(new \crmeb\services\easywechat\pay\ServiceProvider); + $this->service->register(new \crmeb\services\easywechat\miniPayment\ServiceProvider); + $this->service->register(new \crmeb\services\easywechat\batches\ServiceProvider); + } + + /** + * @return Client + * @author xaboy + * @day 2020/7/29 + */ + public function miniBroadcast() + { + return $this->service->miniBroadcast; + } + + /** + * @return array[] + * @author xaboy + * @day 2020/6/18 + */ + public static function getConfig() + { + $wechat = systemConfig(['site_url', 'routine_appId', 'routine_appsecret']); + $payment = systemConfig(['pay_routine_mchid', 'pay_routine_key', 'pay_routine_v3_key', 'pay_routine_serial_no_v3', 'pay_routine_client_cert', 'pay_routine_client_key', 'pay_weixin_open', 'wechat_service_merid', 'wechat_service_key', 'wechat_service_v3key', 'wechat_service_client_cert', 'wechat_service_client_key', 'wechat_service_serial_no','pay_routine_new_mchid']); + $config = [ + 'app_id' => $wechat['routine_appId'], + 'secret' => $wechat['routine_appsecret'], + 'mini_program' => [ + 'app_id' => $wechat['routine_appId'], + 'secret' => $wechat['routine_appsecret'], + 'token' => '', + 'aes_key' => '', + ], + 'payment' => [ + 'app_id' => $wechat['routine_appId'], + 'merchant_id' => trim($payment['pay_routine_mchid']), + 'key' => trim($payment['pay_routine_key']), + 'apiv3_key' => trim($payment['pay_routine_v3_key']), + 'serial_no' => trim($payment['pay_routine_serial_no_v3']), + 'cert_path' => (app()->getRootPath() . 'public' . $payment['pay_routine_client_cert']), + 'key_path' => (app()->getRootPath() . 'public' . $payment['pay_routine_client_key']), + 'notify_url' => $wechat['site_url'] . Route::buildUrl('routineNotify')->build(), + 'pay_routine_client_key' => $payment['pay_routine_client_key'], + 'pay_routine_client_cert' => $payment['pay_routine_client_cert'], + ], + 'service_payment' => [ + 'merchant_id' => trim($payment['wechat_service_merid']), + 'key' => trim($payment['wechat_service_key']), + 'type' => 'routine', + 'cert_path' => (app()->getRootPath() . 'public' . $payment['wechat_service_client_cert']), + 'key_path' => (app()->getRootPath() . 'public' . $payment['wechat_service_client_key']), + 'pay_weixin_client_cert' => $payment['wechat_service_client_cert'], + 'pay_weixin_client_key' => $payment['wechat_service_client_key'], + 'serial_no' => trim($payment['wechat_service_serial_no']), + 'apiv3_key' => trim($payment['wechat_service_v3key']), + ], + 'pay_routine_new_mchid' => $payment['pay_routine_new_mchid'], + ]; + + $config['is_v3'] = !empty($config['payment']['apiv3_key']); + return $config; + } + + public function isV3() + { + return $this->config['is_v3'] ?? false; + } + + public function v3Pay() + { + return $this->service->v3Pay; + } + + + /** + * @return MiniProgramService + * @author xaboy + * @day 2020/6/2 + */ + public static function create() + { + return new self(self::getConfig()); + } + + /** + * 支付 + * @return Payment + */ + public function paymentService() + { + return $this->service->payment; + } + + /** + * 小程序接口 + * @return MiniProgram + */ + public function miniProgram() + { + return $this->service->mini_program; + } + + /** + * @return \EasyWeChat\Material\Material|mixed + * @author xaboy + * @day 2020/7/29 + */ + public function material() + { + return $this->service->mini_program->material_temporary; + } + + /** + * @param $sessionKey + * @param $iv + * @param $encryptData + * @return mixed + * @author xaboy + * @day 2020/6/18 + */ + public function encryptor($sessionKey, $iv, $encryptData) + { + return $this->miniProgram()->encryptor->decryptData($sessionKey, $iv, $encryptData); + } + + /** + * 上传临时素材接口 + * @return Temporary + */ + public function materialTemporaryService() + { + return $this->miniProgram()->material_temporary; + } + + /** + * 客服消息接口 + */ + public function staffService() + { + return $this->miniProgram()->staff; + } + + /** + * @param $code + * @return mixed + * @author xaboy + * @day 2020/6/18 + */ + public function getUserInfo($code) + { + $userInfo = $this->miniProgram()->sns->getSessionKey($code); + return $userInfo; + } + + /** + * @return \EasyWeChat\MiniProgram\QRCode\QRCode + * @author xaboy + * @day 2020/6/18 + */ + public function qrcodeService() + { + return $this->miniProgram()->qrcode; + } + + /** + * 生成支付订单对象 + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Order + */ + protected function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $total_fee = bcmul($total_fee, 100, 0); + $order = array_merge(compact('openid', 'out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options); + if ($order['detail'] == '') unset($order['detail']); + return new Order($order); + } + + /** + * 获得下单ID + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return mixed + */ + public function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $order = $this->paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options); + // 获取配置 判断是否为新支付 + if (isset($this->config['pay_routine_new_mchid']) && $this->config['pay_routine_new_mchid']) { + $result = $this->service->minipay->createorder($order); + if ($result->errcode === 0) { + return $result->payment_params; + } else { + throw new ValidateException('微信支付错误返回:' . $result->return_msg); + } + } else { + if ($this->v3Pay()) { + if ($trade_type == 'MWEB') $trade_type = 'H5'; + $payFunction = 'pay'.ucfirst($trade_type); + return $this->service->v3Pay->{$payFunction}($order); + } else { + $result = $this->paymentService()->prepare($order); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result->prepay_id; + } else { + if ($result->return_code == 'FAIL') { + throw new ValidateException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new ValidateException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new ValidateException('没有获取微信支付的预支付ID,请重新发起支付!'); + } + } + } + } + } + + /** + * 获得jsSdk支付参数 + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return array|string + */ + public function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $paymentPrepare = $this->paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options); + if ($this->isV3()) { + return $paymentPrepare; + } + return $this->paymentService()->configForJSSDKPayment($paymentPrepare); + } + + /** + * 使用商户订单号退款 + * @param $orderNo + * @param $refundNo + * @param $totalFee + * @param null $refundFee + * @param null $opUserId + * @param string $refundReason + * @param string $type + * @param string $refundAccount + * @return Collection|ResponseInterface + */ + public function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '', $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS',$openId = null, $transactionId = null) + { + if (empty($this->config['payment']['pay_routine_client_key']) || empty($this->config['payment']['pay_routine_client_cert'])) { + throw new \Exception('请配置微信支付证书'); + } + $totalFee = floatval($totalFee); + $refundFee = floatval($refundFee); + if ($this->config['pay_routine_new_mchid']) { + return $this->service->minipay->refund($orderNo, $refundNo, $totalFee, $refundFee,$openId,$transactionId); + } else { + if ($this->isV3()) { + return $this->service->v3Pay->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason); + } else { + return $this->paymentService()->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason); + } + } + } + + /** + * 发送订阅消息 + * @param string $touser 接收者(用户)的 openid + * @param string $templateId 所需下发的订阅模板id + * @param array $data 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } } + * @param string $link 击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + * @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException + */ + public function sendSubscribeTemlate(string $touser, string $templateId, array $data, string $link = '') + { + return $this->miniprogram()->now_notice->to($touser)->template($templateId)->andData($data)->withUrl($link)->send(); + } + + + /** + * @param $orderNo + * @param array $opt + * @return bool + * @author xaboy + * @day 2020/6/18 + */ + public function payOrderRefund($orderNo, array $opt) + { + if (!isset($opt['pay_price'])) throw new ValidateException('缺少pay_price'); + $totalFee = floatval(bcmul($opt['pay_price'], 100, 0)); + $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'], 100, 0)) : null; + $refundReason = isset($opt['refund_message']) ? $opt['refund_message'] : '无'; + $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo; + $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null; + $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no'; + $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS'; + $openId = $opt['open_id'] ?? null; + $transactionId = $opt['transaction_id'] ?? null; + try { + $res = ($this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount, $openId, $transactionId)); + if (isset($res->return_code) && $res->return_code== 'FAIL') + throw new ValidateException('退款失败:' . $res->return_msg); + if (isset($res->err_code)) + throw new ValidateException('退款失败:' . $res->err_code_des); + } catch (\Exception $e) { + throw new ValidateException($e->getMessage()); + } + return true; + } + + /** + * @return \Symfony\Component\HttpFoundation\Response + * @throws \EasyWeChat\Core\Exceptions\FaultException + * @author xaboy + * @day 2020/6/18 + */ + public function handleNotify() + { + $this->service->payment = new PaymentService($this->service->merchant); + return $this->service->payment->handleNotify(function ($notify, $successful) { + Log::info('小程序支付回调' . var_export($notify, 1)); + if (!$successful) return; + try { + event('pay_success_' . $notify['attach'], ['order_sn' => $notify['out_trade_no'], 'data' => $notify]); + } catch (\Exception $e) { + Log::info('小程序支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + public function handleNotifyV3() + { + return $this->service->v3Pay->handleNotify(function ($notify, $successful) { + Log::info('小程序支付回调' . var_export($notify, 1)); + if (!$successful) return; + try { + event('pay_success_' . $notify['attach'], ['order_sn' => $notify['out_trade_no'], 'data' => $notify]); + } catch (\Exception $e) { + Log::info('小程序支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + /** + * @return easywechat\combinePay\Client + */ + public function combinePay() + { + return $this->service->combinePay; + } + + public function handleCombinePayNotify($type) + { + return $this->service->combinePay->handleNotify(function ($notify, $successful) use ($type) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $type, ['order_sn' => $notify['combine_out_trade_no'], 'data' => $notify, 'is_combine' => 1]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + + /** + * 获取模版标题的关键词列表 + * @param string $tid + * @return mixed + */ + public function getSubscribeTemplateKeyWords(string $tid) + { +// try { + $res = $this->miniprogram()->now_notice->getPublicTemplateKeywords($tid); + if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['data'])) { + return $res['data']; + } else { + throw new ValidateException($res['errmsg']); + } +// } catch (\Throwable $e) { +// throw new ValidateException($e); +// } + } + + /** + * 添加订阅消息模版 + * @param string $tid + * @param array $kidList + * @param string $sceneDesc + * @return mixed + */ + public function addSubscribeTemplate(string $tid, array $kidList, string $sceneDesc = '') + { + try { + $res = $this->miniprogram()->now_notice->addTemplate($tid, $kidList, $sceneDesc); + if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['priTmplId'])) { + return $res['priTmplId']; + } else { + throw new ValidateException($res['errmsg']); + } + } catch (\Throwable $e) { + throw new ValidateException($e); + } + } + + public function getPrivateTemplates() + { + try{ + $res = $this->miniprogram()->now_notice->getPrivateTemplates(); + if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['priTmplId'])) { + return $res['priTmplId']; + } else { + throw new ValidateException($res['errmsg']); + } + } catch (\Throwable $e) { + throw new ValidateException($e); + } + } + + public function msgSecCheck($userInfo,$content,$scene,$type = 0) + { + //$media_type 1:音频;2:图片 + //scene 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志) + if (!in_array($scene,[1,2,3,4])) { + throw new ValidateException('使用场景类型错误'); + } + if (!isset($userInfo->wechat->routine_openid)) return ; + $openid = $userInfo->wechat->routine_openid; + if ($type) { + return $this->service->msgSec->mediaSecCheck($content,$scene,$openid,$type); + } else { + return $this->service->msgSec->msgSecCheck($content,$scene,$openid); + } + } + + /** + * TODO V3的商家到零钱 + * @author Qinii + * @day 2023/3/13 + */ + public function companyPay($data) + { + $transfer_detail_list[] = [ + 'out_detail_no' => $data['sn'], + 'transfer_amount' => $data['price'] * 100, + 'transfer_remark' => $data['mark'] ?? '', + //openid是微信用户在公众号appid下的唯一用户标识 + 'openid' => $data['openid'], + ]; + //商家到零钱 + $ret = [ + //商户系统内部的商家批次单号 + 'out_batch_no' => $data['sn'], + //该笔批量转账的名称 + 'batch_name' => $data['batch_name'], + //转账说明,UTF8编码,最多允许32个字符 + 'batch_remark' => $data['mark'] ?? '', + //转账金额单位为“分” + 'total_amount' => $data['price'] * 100, + //转账总笔数一个转账批次单最多发起三千笔转账 + 'total_num' => 1, + //该批次转账使用的转账场景,可在「商家转账到零钱 - 产品设置」中查看详情,如不填写则使用商家的默认转账场景 + 'transfer_detail_list' => $transfer_detail_list, + ]; + $result = $this->service->batches->send($ret); + return $result; + } + + /** + * TODO V2的企业到零钱 + * @param $data + * @return mixed + * @author Qinii + * @day 2023/3/13 + */ + public function merchantPay($data) + { + $ret = [ + 'partner_trade_no' => $data['sn'], //随机字符串作为订单号,跟红包和支付一个概念。 + 'openid' => $data['openid'], //收款人的openid + 'check_name' => 'NO_CHECK', //文档中有三种校验实名的方法 NO_CHECK OPTION_CHECK FORCE_CHECK + //'re_user_name'=>'张三', //OPTION_CHECK FORCE_CHECK 校验实名的时候必须提交 + 'amount' => $data['price'] * 100, //单位为分 + 'desc' => $data['mark'] ?? '', + 'spbill_create_ip' => request()->ip(), //发起交易的IP地址 + ]; + $result = $this->service->merchant_pay->send($ret); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result; + } else { + if ($result->return_code == 'FAIL') { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new WechatException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } + } + } + +} diff --git a/crmeb/services/MysqlBackupService.php b/crmeb/services/MysqlBackupService.php new file mode 100644 index 00000000..bb03e0ce --- /dev/null +++ b/crmeb/services/MysqlBackupService.php @@ -0,0 +1,521 @@ + +// +---------------------------------------------------------------------- + +// +---------------------------------------------------------------------- +// | origin:tp5er\tp5-databackup +// +---------------------------------------------------------------------- +namespace crmeb\services; + +use think\facade\Db; + +class MysqlBackupService +{ + /** + * 文件指针 + * @var resource + */ + private $fp; + /** + * 备份文件信息 part - 卷号,name - 文件名 + * @var array + */ + private $file; + /** + * 当前打开文件大小 + * @var integer + */ + private $size = 0; + + /** + * 数据库配置 + * @var integer + */ + private $dbconfig = array(); + /** + * 备份配置 + * @var integer + */ + private $config = array( + 'path' => './Data/', + //数据库备份路径 + 'part' => 20971520, + //数据库备份卷大小 + 'compress' => 0, + //数据库备份文件是否启用压缩 0不压缩 1 压缩 + 'level' => 9, + ); + + /** + * 数据库备份构造方法 + * + * @param array $file 备份或还原的文件信息 + * @param array $config 备份配置信息 + */ + public function __construct($config = []) + { + $this->config['path'] = app()->getRootPath() . 'backup/'; + $this->config = array_merge($this->config, $config); + //初始化文件名 + $this->setFile(); + //初始化数据库连接参数 + $this->setDbConn(); + //检查文件是否可写 + if (!$this->checkPath($this->config['path'])) { + throw new \Exception("The current directory is not writable"); + } + } + + /** + * 设置脚本运行超时时间 + * 0表示不限制,支持连贯操作 + */ + public function setTimeout($time = null) + { + if (!is_null($time)) { + set_time_limit($time) || ini_set("max_execution_time", $time); + } + return $this; + } + + /** + * 设置数据库连接必备参数 + * + * @param array $dbconfig 数据库连接配置信息 + * @return $this + */ + public function setDbConn($dbconfig = []) + { + if (empty($dbconfig)) { + $this->dbconfig = config('database.connections.' . config('database.default')); + //$this->dbconfig = Config::get('database'); + } else { + $this->dbconfig = $dbconfig; + } + return $this; + } + + /** + * 设置备份文件名 + * + * @param null $file + * @return $this + */ + public function setFile($file = null) + { + if (is_null($file)) { + $this->file = ['name' => date('Ymd-His'), 'part' => 1]; + } else { + if (!array_key_exists("name", $file) && !array_key_exists("part", $file)) { + $this->file = $file['1']; + } else { + $this->file = $file; + } + } + return $this; + } + + //数据类连接 + public static function connect() + { + return Db::connect(); + } + + /** + * 数据库表列表 + * + * @param null $table + * @param int $type + * @return array + * @throws \think\db\exception\BindParamException + * @throws \think\exception\PDOException + */ + public function dataList(?string $table = null, int $type = 1) + { + $db = self::connect(); + if (is_null($table)) { + $list = $db->query("SHOW TABLE STATUS"); + } else { + if ($type) { + $list = $db->query("SHOW FULL COLUMNS FROM {$table}"); + } else { + $list = $db->query("show columns from {$table}"); + } + } + return array_map('array_change_key_case', $list); + //$list; + } + + /** + * 数据库备份文件列表 + * + * @return array + */ + public function fileList() + { + if (!is_dir($this->config['path'])) { + mkdir($this->config['path'], 0755, true); + } + $path = realpath($this->config['path']); + $flag = \FilesystemIterator::KEY_AS_FILENAME; + $glob = new \FilesystemIterator($path, $flag); + $list = array(); + foreach ($glob as $name => $file) { + if (preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql(?:\\.gz)?$/', $name)) { + $info['filename'] = $name; + $name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d'); + $date = "{$name[0]}-{$name[1]}-{$name[2]}"; + $time = "{$name[3]}:{$name[4]}:{$name[5]}"; + $part = $name[6]; + if (isset($list["{$date} {$time}"])) { + $info = $list["{$date} {$time}"]; + $info['part'] = max($info['part'], $part); + $info['size'] = $info['size'] + $file->getSize(); + } else { + $info['part'] = $part; + $info['size'] = $file->getSize(); + } + $extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION)); + $info['compress'] = $extension === 'SQL' ? '-' : $extension; + $info['time'] = strtotime("{$date} {$time}"); + $list["{$date} {$time}"] = $info; + } + } + return $list; + } + + /** + * @param string $type + * @param int $time + * @return array|false|string + * @throws \Exception + */ + public function getFile($type = '', $time = 0) + { + // + if (!is_numeric($time)) { + throw new \Exception("{$time} Illegal data type"); + } + switch ($type) { + case 'time': + $name = date('Ymd-His', $time) . '-*.sql*'; + $path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name; + return glob($path); + break; + case 'timeverif': + $name = date('Ymd-His', $time) . '-*.sql*'; + $path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name; + $files = glob($path); + $list = array(); + foreach ($files as $name) { + $basename = basename($name); + $match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d'); + $gz = preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql.gz$/', $basename); + $list[$match[6]] = array($match[6], $name, $gz); + } + $last = end($list); + if (count($list) === $last[0]) { + return $list; + } else { + throw new \Exception("File {$files['0']} may be damaged, please check again"); + } + break; + case 'pathname': + return "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql"; + break; + case 'filename': + return "{$this->file['name']}-{$this->file['part']}.sql"; + break; + case 'filepath': + return $this->config['path']; + break; + default: + $arr = array('pathname' => "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql", 'filename' => "{$this->file['name']}-{$this->file['part']}.sql", 'filepath' => $this->config['path'], 'file' => $this->file); + return $arr; + } + } + + /** + * 删除备份文件 + * @param $time + * @return mixed + * @throws \Exception + */ + public function delFile($time) + { + if ($time) { + $file = $this->getFile('time', $time); + array_map("unlink", $this->getFile('time', $time)); + if (count($this->getFile('time', $time))) { + throw new \Exception("File {$time} deleted failed"); + } else { + return $time; + } + } else { + throw new \Exception("{$time} Time parameter is incorrect"); + } + } + + /** + * 下载备份 + * + * @param $time + * @param int $part + * @throws \Exception + */ + public function downloadFile($time, $part = 0) + { + $file = $this->getFile('time', $time); + $fileName = $file[$part]; + if (file_exists($fileName)) { + ob_end_clean(); + header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Length: ' . filesize($fileName)); + header('Content-Disposition: attachment; filename=' . basename($fileName)); + readfile($fileName); + } else { + throw new \Exception("{$time} File is abnormal"); + } + } + + public function import($start) + { + //还原数据 + $db = self::connect(); + if ($this->config['compress']) { + $gz = gzopen($this->file[1], 'r'); + $size = 0; + } else { + $size = filesize($this->file[1]); + $gz = fopen($this->file[1], 'r'); + } + $sql = ''; + if ($start) { + $this->config['compress'] ? gzseek($gz, $start) : fseek($gz, $start); + } + for ($i = 0; $i < 1000; $i++) { + $sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz); + if (preg_match('/.*;$/', trim($sql))) { + if (false !== $db->execute($sql)) { + $start += strlen($sql); + } else { + return false; + } + $sql = ''; + } elseif ($this->config['compress'] ? gzeof($gz) : feof($gz)) { + return 0; + } + } + return array($start, $size); + } + + /** + * 写入初始数据 + * + * @return boolean true - 写入成功,false - 写入失败 + */ + public function Backup_Init() + { + $sql = "-- -----------------------------\n"; + $sql .= "-- Think MySQL Data Transfer \n"; + $sql .= "-- \n"; + $sql .= "-- Host : " . $this->dbconfig['hostname'] . "\n"; + $sql .= "-- Port : " . $this->dbconfig['hostport'] . "\n"; + $sql .= "-- Database : " . $this->dbconfig['database'] . "\n"; + $sql .= "-- \n"; + $sql .= "-- Part : #{$this->file['part']}\n"; + $sql .= "-- Date : " . date("Y-m-d H:i:s") . "\n"; + $sql .= "-- -----------------------------\n\n"; + $sql .= "SET FOREIGN_KEY_CHECKS = 0;\n\n"; + return $this->write($sql); + } + + /** + * 备份表结构 + * + * @param string $table + * @param int $start + * @return bool|int + * @throws \think\db\exception\BindParamException + * @throws \think\exception\PDOException + */ + public function backup(string $table, int $start) + { + $db = self::connect(); + // 备份表结构 + if (0 == $start) { + $result = $db->query("SHOW CREATE TABLE `{$table}`"); + $sql = "\n"; + $sql .= "-- -----------------------------\n"; + $sql .= "-- Table structure for `{$table}`\n"; + $sql .= "-- -----------------------------\n"; + $sql .= "DROP TABLE IF EXISTS `{$table}`;\n"; + $sql .= trim($result[0]['Create Table']) . ";\n\n"; + if (false === $this->write($sql)) { + return false; + } + } + //数据总数 + $result = $db->query("SELECT COUNT(*) AS count FROM `{$table}`"); + $count = $result['0']['count']; + //备份表数据 + if ($count) { + //写入数据注释 + if (0 == $start) { + $sql = "-- -----------------------------\n"; + $sql .= "-- Records of `{$table}`\n"; + $sql .= "-- -----------------------------\n"; + $this->write($sql); + } + //备份数据记录 + $result = $db->query("SELECT * FROM `{$table}` LIMIT :MIN, 1000", ['MIN' => intval($start)]); + foreach ($result as $row) { + $row = array_map('addslashes', $row); + $sql = "INSERT INTO `{$table}` VALUES ('" . str_replace(array("\r", "\n"), array('\\r', '\\n'), implode("', '", $row)) . "');\n"; + if (false === $this->write($sql)) { + return false; + } + } + //还有更多数据 + if ($count > $start + 1000) { + //return array($start + 1000, $count); + return $this->backup($table, $start + 1000); + } + } + //备份下一表 + return 0; + } + + /** + * 优化表 + * + * @param array|string $tables + * @throws \think\db\exception\BindParamException + * @throws \think\exception\PDOException + */ + public function optimize($tables) + { + if ($tables) { + $db = self::connect(); + if (is_array($tables)) { + $tables = implode('`,`', $tables); + $list = $db->query("OPTIMIZE TABLE `{$tables}`"); + } else { + $list = $db->query("OPTIMIZE TABLE `{$tables}`"); + } + if (!$list) { + throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!"); + } + } else { + throw new \Exception("Please specify the table to be repaired!"); + } + } + + /** + * 修复表 + * + * @param string|null $tables + * @return array + * @throws \think\db\exception\BindParamException + * @throws \think\exception\PDOException + */ + public function repair(?string $tables = null) + { + if ($tables) { + $db = self::connect(); + if (is_array($tables)) { + $tables = implode('`,`', $tables); + $list = $db->query("REPAIR TABLE `{$tables}`"); + } else { + $list = $db->query("REPAIR TABLE `{$tables}`"); + } + if ($list) { + return $list; + } else { + throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!"); + } + } else { + throw new \Exception("Please specify the table to be repaired!"); + } + } + + /** + * 写入SQL语句 + * + * @param string $sql 要写入的SQL语句 + * @return boolean true - 写入成功,false - 写入失败! + */ + private function write(string $sql) + { + $size = strlen($sql); + //由于压缩原因,无法计算出压缩后的长度,这里假设压缩率为50%, + //一般情况压缩率都会高于50%; + $size = $this->config['compress'] ? $size / 2 : $size; + $this->open($size); + return $this->config['compress'] ? @gzwrite($this->fp, $sql) : @fwrite($this->fp, $sql); + } + + /** + * 打开一个卷,用于写入数据 + * + * @param integer $size 写入数据的大小 + */ + private function open(int $size) + { + if ($this->fp) { + $this->size += $size; + if ($this->size > $this->config['part']) { + $this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp); + $this->fp = null; + $this->file['part']++; + session('backup_file', $this->file); + $this->Backup_Init(); + } + } else { + $backuppath = $this->config['path']; + $filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql"; + if ($this->config['compress']) { + $filename = "{$filename}.gz"; + $this->fp = @gzopen($filename, "a{$this->config['level']}"); + } else { + $this->fp = @fopen($filename, 'a'); + } + $this->size = filesize($filename) + $size; + } + } + + /** + * 检查目录是否可写 + * + * @param string $path + * @return bool + */ + protected function checkPath(string $path) + { + if (is_dir($path)) { + return true; + } + if (mkdir($path, 0755, true)) { + return true; + } else { + return false; + } + } + + /** + * 析构方法,用于关闭文件资源 + */ + public function __destruct() + { + $this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp); + } +} diff --git a/crmeb/services/PayService.php b/crmeb/services/PayService.php new file mode 100644 index 00000000..3bbadc1d --- /dev/null +++ b/crmeb/services/PayService.php @@ -0,0 +1,100 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\model\user\User; +use app\common\repositories\wechat\WechatUserRepository; +use think\exception\ValidateException; +use think\facade\Cache; + +class PayService +{ + protected $type; + protected $options; + protected $affect; + + public function __construct(string $type, array $options, string $affect = 'order') + { + $this->type = $type; + $this->affect = $affect; + $this->options = $options; + } + + public function pay(?User $user) + { + $method = 'pay' . ucfirst($this->type); + if (!method_exists($this, $method)) { + throw new ValidateException('不支持该支付方式'); + } + return $this->{$method}($user); + } + + public function payWeixin(User $user) + { + $wechatUserRepository = app()->make(WechatUserRepository::class); + $openId = $wechatUserRepository->idByOpenId($user['wechat_user_id']); + if (!$openId) + throw new ValidateException('请关联微信公众号!'); + $config = WechatService::create()->jsPay($openId, $this->options['order_sn'], $this->options['pay_price'], $this->options['attach'], $this->options['body']); + return compact('config'); + } + + public function payWeixinQr(?User $user) + { + $config = WechatService::create()->paymentPrepare('', $this->options['order_sn'], $this->options['pay_price'], $this->options['attach'], $this->options['body'], '', 'NATIVE'); + return ['config' => $config['code_url']]; + } + + public function payRoutine(User $user) + { + $wechatUserRepository = app()->make(WechatUserRepository::class); + $openId = $wechatUserRepository->idByRoutineId($user['wechat_user_id']); + if (!$openId) + throw new ValidateException('请关联微信小程序!'); + $config = MiniProgramService::create()->jsPay($openId, $this->options['order_sn'], $this->options['pay_price'], $this->options['attach'], $this->options['body']); + return compact('config'); + } + + public function payH5(User $user) + { + $config = WechatService::create()->paymentPrepare(null, $this->options['order_sn'], $this->options['pay_price'], $this->options['attach'], $this->options['body'], '', 'MWEB'); + return compact('config'); + } + + public function payWeixinApp(User $user) + { + $config = WechatService::create()->jsPay(null, $this->options['order_sn'], $this->options['pay_price'], $this->options['attach'], $this->options['body'], '', 'APP'); + return compact('config'); + } + + public function payAlipay(User $user) + { + $url = AlipayService::create($this->affect)->wapPaymentPrepare($this->options['order_sn'], $this->options['pay_price'], $this->options['body'], $this->options['return_url']); + $pay_key = md5($url); + Cache::store('file')->set('pay_key' . $pay_key, $url, 3600); + return ['config' => $url, 'pay_key' => $pay_key]; + } + + public function payAlipayQr(? User $user) + { + $url = AlipayService::create($this->affect)->qrPaymentPrepare($this->options['order_sn'], $this->options['pay_price'], $this->options['body']); + return ['config' => $url]; + } + + public function payAlipayApp(User $user) + { + $config = AlipayService::create($this->affect)->appPaymentPrepare($this->options['order_sn'], $this->options['pay_price'], $this->options['body']); + return compact('config'); + } +} diff --git a/crmeb/services/PaymentService.php b/crmeb/services/PaymentService.php new file mode 100644 index 00000000..e6a988d5 --- /dev/null +++ b/crmeb/services/PaymentService.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use EasyWeChat\Payment\Notify; +use EasyWeChat\Payment\Payment; +use Symfony\Component\HttpFoundation\Request; + +class PaymentService extends Payment +{ + public function getNotify() + { + $request = \request(); + $request = new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent()); + return new Notify($this->merchant, $request); + } +} diff --git a/crmeb/services/PrinterService.php b/crmeb/services/PrinterService.php new file mode 100644 index 00000000..37a7275a --- /dev/null +++ b/crmeb/services/PrinterService.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + +use crmeb\services\printer\AccessToken; +use crmeb\basic\BaseStorage; + +/** + * Class BasePrinter + * @package crmeb\basic + */ +abstract class PrinterService extends BaseStorage +{ + + /** + * token句柄 + * @var AccessToken + */ + protected $accessToken; + + /** + * 打印内容 + * @var string + */ + protected $printerContent; + + /** + * BasePrinter constructor. + * @param string $name + * @param AccessToken $accessToken + * @param string $configFile + */ + public function __construct(string $name, AccessToken $accessToken, string $configFile) + { + $this->accessToken = $accessToken; + $this->initialize([]); + } + + /** + * 开始打印 + * @param array|null $systemConfig + * @return mixed + */ + abstract public function startPrinter(); + + /** + * 设置打印内容 + * @param array $config + * @return mixed + */ + abstract public function setPrinterContent(array $config); + +} diff --git a/crmeb/services/QrcodeService.php b/crmeb/services/QrcodeService.php new file mode 100644 index 00000000..cd850cc1 --- /dev/null +++ b/crmeb/services/QrcodeService.php @@ -0,0 +1,192 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\repositories\system\attachment\AttachmentRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\wechat\RoutineQrcodeRepository; +use Endroid\QrCode\QrCode; +use think\facade\Config; + +class QrcodeService +{ + + /** + * 获取二维码 + * @param $url + * @param $name + * @return array|bool|string + */ + public function getQRCodePath($url, $name) + { + if (!strlen(trim($url)) || !strlen(trim($name))) return false; + try { + $uploadType = systemConfig('upload_type'); + //TODO 没有选择默认使用本地上传 + if (!$uploadType) $uploadType = 1; + $uploadType = (int)$uploadType; + $siteUrl = systemConfig('site_url'); + if (!$siteUrl) return '请前往后台设置->系统设置->网站域名 填写您的域名格式为:http://域名'; + $info = []; + $outfile = Config::get('qrcode.cache_dir'); + $code = new QrCode($url); + if ($uploadType === 1) { + if (!is_dir('./public/' . $outfile)) + mkdir('./public/' . $outfile, 0777, true); + $code->writeFile('./public/' . $outfile . '/' . $name); + $info["code"] = 200; + $info["name"] = $name; + $info["dir"] = rtrim($siteUrl, '/') . '/' . $outfile . '/' . $name; + $info["time"] = time(); + $info['size'] = 0; + $info['type'] = 'image/png'; + $info["image_type"] = 1; + $info['thumb_path'] = $info["dir"]; + return $info; + } else { + $upload = UploadService::create($uploadType); + $res = $upload->to('/public/' . $outfile)->validate()->stream($code->writeString(), $name); + if ($res === false) { + return $upload->getError(); + } + $info = $upload->getUploadInfo(); + $info['image_type'] = $uploadType; + return $info; + } + } catch (\Exception $e) { + return $e->getMessage(); + } + } + + + /** + * 获取二维码完整路径,不存在则自动生成 + * @param string $name 路径名 + * @param string $link 需要生成二维码的跳转路径 + * @param bool $force 是否返回false + * @return bool|mixed|string + */ + public function getWechatQrcodePath(string $name, string $link, bool $force = false, $key = '') + { + try { + $imageInfo = app()->make(AttachmentRepository::class)->getWhere(['attachment_name' => $name]); + if (!$imageInfo) { + $siteUrl = systemConfig('site_url'); + $codeUrl = tidy_url($link, null, $siteUrl); + + if ($key && systemConfig('open_wechat_share')) { + $qrcode = WechatService::create(false)->qrcodeService(); + $codeUrl = $qrcode->forever('_scan_url_' . $key)->url; + } + + $imageInfo = $this->getQRCodePath($codeUrl, $name); + if (is_string($imageInfo) && $force) + return false; + if (is_array($imageInfo)) { + $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl); + app()->make(AttachmentRepository::class)->create($imageInfo['image_type'], -1, 0, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $url = $imageInfo['dir']; + } else { + $url = ''; + } + } else $url = $imageInfo['attachment_src']; + return $url; + } catch (\Throwable $e) { + if ($force) + return false; + else + return ''; + } + } + + /** + * 获取小程序分享二维码 + * @param int $id + * @param int $uid + * @param int $type 1 = 拼团,2 = 秒杀 + * @param array $parame + * @return bool|string + */ + public function hotQrcodePath(int $id, int $uid, int $type, array $parame = []) + { + $page = ''; + $namePath = ''; + $data = 'id=' . $id . '&spid=' . $uid; + switch ($type) { + case 1: + $page = 'pages/activity/goods_combination_details/index'; + $namePath = 'combination_' . $id . '_' . $uid . '.jpg'; + break; + case 2: + $page = 'pages/activity/goods_seckill_details/index'; + $namePath = 'seckill_' . $id . '_' . $uid . '.jpg'; + if (isset($parame['stop_time']) && $parame['stop_time']) { + $data .= '&time=' . $parame['stop_time']; + $namePath = $parame['stop_time'] . $namePath; + } + break; + } + if (!$page || !$namePath) { + return false; + } + + return $this->getRoutineQrcodePath($namePath, $page, $data); + } + + /** + * @param $namePath + * @param $page + * @param $data + * @return bool|int|mixed|string + * @author xaboy + * @day 2020/6/18 + */ + public function getRoutineQrcodePath($namePath, $page, $data) + { + + try { + $imageInfo = app()->make(AttachmentRepository::class)->getWhere(['attachment_name' => $namePath]); + if (!$imageInfo) { + $res = app()->make(RoutineQrcodeRepository::class)->getPageCode($page, $data, 280); + if (!$res) return false; + $uploadType = (int)systemConfig('upload_type') ?: 1; + $upload = UploadService::create($uploadType); + $res = $upload->to('routine/product')->validate()->stream($res, $namePath); + if ($res === false) { + return false; + } + $imageInfo = $upload->getUploadInfo(); + $imageInfo['image_type'] = $uploadType; + $imageInfo['dir'] = tidy_url($imageInfo['dir'], 0); + $remoteImage = remoteImage($imageInfo['dir']); + if (!$remoteImage['status']) return false; + app()->make(AttachmentRepository::class)->create($uploadType, -1, 0, [ + 'attachment_category_id' => 0, + 'attachment_name' => $imageInfo['name'], + 'attachment_src' => $imageInfo['dir'] + ]); + $url = $imageInfo['dir']; + } else $url = $imageInfo['attachment_src']; + return $url; + } catch (\Throwable $e) { + return false; + } + } + +} diff --git a/crmeb/services/RedisCacheService.php b/crmeb/services/RedisCacheService.php new file mode 100644 index 00000000..2b88609f --- /dev/null +++ b/crmeb/services/RedisCacheService.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use think\facade\Cache; + +/** + * crmeb 缓存类 + * Class CacheService + * @package crmeb\services + * @mixin \Redis + * @mixin \think\cache\driver\Redis + */ +class RedisCacheService +{ + + /** + * @var \Redis + */ + protected $handler; + + /** + * @var \think\cache\driver\Redis + */ + protected $driver; + + /** + * @param int $admin + * @param string $tag + */ + public function __construct() + { + $this->driver = Cache::store('redis'); + $this->handler = $this->driver->handler(); + } + + public function handler() + { + return $this->handler; + } + + public function driver() + { + return $this->driver; + } + + public function __call($name, $arguments) + { + if (method_exists($this->driver, $name)) { + return call_user_func_array([$this->driver, $name], $arguments); + } + return call_user_func_array([$this->handler, $name], $arguments); + } + +} diff --git a/crmeb/services/RoutineTemplateService.php b/crmeb/services/RoutineTemplateService.php new file mode 100644 index 00000000..67fb5a7e --- /dev/null +++ b/crmeb/services/RoutineTemplateService.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\services\template\Template; + +/** + * Class WechatTemplateService + * @package crmeb\services + * @author xaboy + * @day 2020-04-20 + */ +class RoutineTemplateService +{ + + /** + * 发送模板消息 + * @param string $tempCode + * @param int $uid 用户uid + * @param array $data 模板内容 + * @param string $link 跳转链接 + * @return bool + */ + public function sendTemplate(string $tempCode, $uid, array $data, string $link = '') + { + try { + $openid = app()->make(WechatUserRepository::class)->idByOpenId((int)$uid); + if (!$openid) return true; + $template = new Template('subscribe'); + return $template->to($openid)->url($link)->send($tempCode, $data); + } catch (\Exception $e) { + return true; + } + } +} diff --git a/crmeb/services/SmsService.php b/crmeb/services/SmsService.php new file mode 100644 index 00000000..ef0a14cf --- /dev/null +++ b/crmeb/services/SmsService.php @@ -0,0 +1,299 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services; + +use app\common\repositories\store\broadcast\BroadcastRoomRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\ProductTakeRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use crmeb\services\sms\Sms; +use think\facade\Cache; + +class SmsService +{ + const SMS_YUNXIN = 1; + const SMS_ALIYUN = 2; + + public static function create() + { + $gateway = (int)systemConfig('sms_use_type') ?: 1; + switch ($gateway) { + case 1: + $name = 'yunxin'; + $config = [ + 'account' => systemConfig('serve_account'), + 'secret' => systemConfig('serve_token') + ]; + break; + case 2: + $name = 'aliyun'; + $config = []; + break; + } + return new Sms($name, $config); + } + + /** + * @Author:Qinii + * @Date: 2020/9/19 + * @param $phone + * @param $code + * @param $type + * @return bool + */ + public function checkSmsCode($phone, $code, $type) + { + if (!env('DEVELOPMENT',false)) { + $sms_key = $this->sendSmsKey($phone, $type); + if (!$cache_code = Cache::get($sms_key)) return false; + if ($code != $cache_code) return false; + Cache::delete($sms_key); + } + return true; + } + + /** + * @Author:Qinii + * @Date: 2020/9/19 + * @param $phone + * @param string $type + * @return string + */ + public function sendSmsKey($phone, $type = 'login') + { + switch ($type) { + case 'login': //登录 + return 'api_login_' . $phone; + break; + case 'binding': //绑定手机号 + return 'api_binding_' . $phone; + break; + case 'intention': //申请入住 + return 'merchant_intention_' . $phone; + break; + case 'change_pwd': //修改密码 + return 'change_pwd_' . $phone; + break; + case 'change_phone': //修改手机号 + return 'change_phone_' . $phone; + break; + default: + return 'crmeb_' . $phone; + break; + } + } + + public static function sendMessage($data) + { + $tempId = $data['tempId']; + $id = $data['id']; + switch ($tempId) { + //发货提醒 -2.1 + case 'DELIVER_GOODS_CODE': + $order = app()->make(StoreOrderRepository::class)->get($id); + if (!$order || !$order->user_phone) return; + $nickname = $order->user->nickname; + $store_name = $order->orderProduct[0]['cart_info']['product']['store_name'] . (count($order->orderProduct) ? '等' : ''); + $order_id = $order->order_sn; + + self::create()->send($order->user_phone, $tempId, compact('nickname', 'store_name', 'order_id')); + break; + //确认收货短信提醒 -2.1 + case 'ORDER_TAKE_SUCCESS': + $order = app()->make(StoreOrderRepository::class)->get($id); + if (!$order || !$order->user_phone) return; + $order_id = $order->order_sn; + $store_name = $order->orderProduct[0]['cart_info']['product']['store_name'] . (count($order->orderProduct) ? '等' : ''); + + self::create()->send($order->user_phone, $tempId, compact('store_name', 'order_id')); + break; + //用户支付成功提醒 -2.1 + case 'ORDER_PAY_SUCCESS': + $order = app()->make(StoreGroupOrderRepository::class)->get($id); + $pay_price = $order->pay_price; + $order_id = $order->group_order_sn; + self::create()->send($order->user_phone, $tempId, compact('pay_price', 'order_id')); + break; + //改价提醒 -2.1 + case 'PRICE_REVISION_CODE': + $order = app()->make(StoreOrderRepository::class)->get($id); + if (!$order || !$order->user_phone) return; + $pay_price = $order->pay_price; + $order_id = $order->order_sn; + self::create()->send($order->user_phone, $tempId, compact('pay_price', 'order_id')); + break; + //提醒付款通知 -2.1 + case 'ORDER_PAY_FALSE': + $order = app()->make(StoreGroupOrderRepository::class)->get($id); + if (!$order || !$order->user_phone) return; + $order_id = $order->group_order_sn; + + self::create()->send($order->user_phone, $tempId, compact('order_id')); + break; + //商家拒绝退款提醒 -2.1 + case 'REFUND_FAIL_CODE': + $order = app()->make(StoreRefundOrderRepository::class)->get($id); + if (!$order || !$order->order->user_phone) return; + $order_id = $order->order->order_sn; + $store_name = $order->refundProduct[0]->product['cart_info']['product']['store_name'] . (count($order->refundProduct) ? '等' : ''); + + self::create()->send($order->order->user_phone, $tempId, compact('order_id', 'store_name')); + break; + //商家同意退款提醒 -2.1 + case 'REFUND_SUCCESS_CODE': + //notbreak; + //退款确认提醒 -2.1 + case 'REFUND_CONFORM_CODE': + $order = app()->make(StoreRefundOrderRepository::class)->get($id); + if (!$order || !$order->order->user_phone) return; + $order_id = $order->order->order_sn; + $store_name = $order->refundProduct[0]->product['cart_info']['product']['store_name'] . (count($order->refundProduct) ? '等' : ''); + + self::create()->send($order->order->user_phone, $tempId, compact('order_id', 'store_name')); + break; + //管理员 支付成功提醒 -2.1 + case 'ADMIN_PAY_SUCCESS_CODE': + $order = app()->make(StoreGroupOrderRepository::class)->get($id); + if (!$order) return; + foreach ($order->orderList as $_order) { + self::sendMerMessage($_order->mer_id, $tempId, ['order_id' => $_order->order_sn]); + } + break; + //管理员退款单提醒 -2.1 + case 'ADMIN_RETURN_GOODS_CODE': + //notbreak + //退货信息提醒 + case 'ADMIN_DELIVERY_CODE': + $order = app()->make(StoreRefundOrderRepository::class)->get($id); + if (!$order) return; + self::sendMerMessage($order->mer_id, $tempId, ['order_id' => $order->refund_order_sn]); + break; + //管理员确认收货提醒 2.1 + case 'ADMIN_TAKE_DELIVERY_CODE': + $order = app()->make(StoreOrderRepository::class)->get($id); + if (!$order) return; + self::sendMerMessage($order->mer_id, $tempId, ['order_id' => $order->order_sn]); + break; + //直播审核通过主播通知 2.1 + case 'BROADCAST_ROOM_CODE': + $room = app()->make(BroadcastRoomRepository::class)->get($id); + if (!$room) return; + self::create()->send($room->phone, $tempId, [ + 'wechat' => $room->anchor_wechat, + 'date' => date('Y年m月d日 H时i分', strtotime($room->start_time)) + ]); + break; + //直播未通过通知 2.1 + case 'BROADCAST_ROOM_FAIL': + $room = app()->make(BroadcastRoomRepository::class)->get($id); + if (!$room) return; + self::create()->send($room->phone, $tempId, [ + 'wechat' => $room->anchor_wechat + ]); + break; + //预售尾款支付通知 2.1 + case 'PAY_PRESELL_CODE': + $order = app()->make(StoreOrderRepository::class)->get($id); + if (!$order || !$order->user_phone || !$order->pay_time) return; + self::create()->send($order->user_phone, $tempId, [ + 'date' => date('Y-m-d', strtotime($order->pay_time)), + 'product_name' => $order->orderProduct[0]['cart_info']['product']['store_name'] ?? '' + ]); + break; + //入驻申请通过提醒 2.1 + case 'APPLY_MER_SUCCESS': + self::create()->send($id['phone'], $tempId, [ + 'date' => $id['date'], + 'mer' => $id['mer'], + 'phone' => $id['phone'], + 'pwd' => $id['pwd'], + 'site_name' => systemConfig('site_name'), + ]); + break; + //入驻申请未通过提醒 2.1 + case 'APPLY_MER_FAIL': + self::create()->send($id['phone'], $tempId, [ + 'date' => $id['date'], + 'mer' => $id['mer'], + 'site' => systemConfig('site_name'), + ]); + break; + //到货提醒通知 2.1 + case 'PRODUCT_INCREASE': + $product = app()->make(ProductRepository::class)->getWhere(['product_id' => $id], '*', ['attrValue']); + if (!$product) return ; + $unique[] = 1; + foreach ($product['attrValue'] as $item) { + if ($item['stock'] > 0) $unique[] = $item['unique']; + } + $make = app()->make(ProductTakeRepository::class); + $query = $make->getSearch(['product_id' => $id, 'status' => 0, 'type' => 1])->where('unique', 'in', $unique); + $ret = $query->select(); + if (!$ret) return ; + foreach ($ret as $item) { + if ($item->user->phone) { + self::create()->send($item->user->phone, $tempId, [ + 'product' => $product->store_name, + 'site' => systemConfig('site_name'), + ]); + $tak_id[] = $item->product_take_id; + } + } + if (!empty($tak_id)) app()->make(ProductTakeRepository::class)->updates($tak_id, ['status' => 1]); + break; + //积分即将到期提醒 2.1 + case 'INTEGRAL_INVALID': + self::create()->send($id['phone'], $tempId, [ + 'integral' => $id['integral'], + 'date' => date('m月d日', strtotime($id['date'])), + 'site' => systemConfig('site_name'), + ]); + break; + //保证金退回申请通过通知 2.1 + case 'REFUND_MARGIN_SUCCESS': + //nobreak; + //保证金退回申请未通过通知 2.1 + case 'REFUND_MARGIN_FAIL': + self::create()->send($id['phone'], $tempId, ['name' => $id['name'], 'time' => $id['time'],]); + break; + //分账商户申请通过 2.1 + case 'APPLYMENTS_SUCCESS': + //nobreak; + //商户申请分账待验证 + case 'APPLYMENTS_SIGN': + //nobreak; + //商户申请分账未通过 + case 'APPLYMENTS_FAIL': + self::create()->send($id['phone'], $tempId, ['mer_name' => $id['mer_name']]); + break; + //付费会员支付成功 + case 'SVIP_PAY_SUCCESS': + self::create()->send($id['phone'], $tempId, ['store_name' => systemConfig('site_name'),'date' => $id['date']]); + break; + } + } + + public static function sendMerMessage($merId, string $tempId, array $data) + { + $noticeServiceInfo = app()->make(StoreServiceRepository::class)->getNoticeServiceInfo($merId); + $yunxinSmsService = self::create(); + foreach ($noticeServiceInfo as $service) { + if (!$service['phone']) continue; + $yunxinSmsService->send($service['phone'], $tempId, array_merge(['admin_name' => $service['nickname']], $data)); + } + } + + +} diff --git a/crmeb/services/SpreadsheetExcelService.php b/crmeb/services/SpreadsheetExcelService.php new file mode 100644 index 00000000..a838f175 --- /dev/null +++ b/crmeb/services/SpreadsheetExcelService.php @@ -0,0 +1,386 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use think\exception\ValidateException; + +class SpreadsheetExcelService +{ + // + private static $instance = null; + //PHPSpreadsheet实例化对象 + private static $spreadsheet = null; + //sheet实例化对象 + private static $sheet = null; + private static $createsheet = null; + //表头计数 + protected static $count; + //表头占行数 + protected static $topNumber = 3; + //表能占据表行的字母对应self::$cellkey + protected static $cells; + //表头数据 + protected static $data = []; + //文件名 + protected static $title = '订单导出'; + //行宽 + protected static $width = 20; + //行高 + protected static $height = 50; + //保存文件目录 + protected static $path = 'phpExcel/'; + //总行数 + protected static $colum = 3; + //设置style + private static $styleArray = [ +// 'borders' => [ +// 'allBorders' => [ +// // PHPExcel_Style_Border里面有很多属性,想要其他的自己去看 +// // 'style' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,//边框是粗的 +// // 'style' => \PHPExcel_Style_Border::BORDER_DOUBLE,//双重的 +// // 'style' => \PHPExcel_Style_Border::BORDER_HAIR,//虚线 +// // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUM,//实粗线 +// // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT,//虚粗线 +// // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT,//点虚粗线 +// 'style' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,//细边框 +// // 'color' => ['argb' => 'FFFF0000'], +// ], +// ], + 'font' => [ + 'bold' => true + ], + 'alignment' => [ + 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, + 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER + ] + ]; + + private function __construct(){} + + private function __clone(){} + + public static function instance() + { + if (self::$instance === null) { + self::$instance = new self(); + self::$spreadsheet = $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); + } + return self::$instance; + } + + public function createOrActive($i = null) + { + if($i){ + self::$sheet = self::$spreadsheet->createSheet(); + }else{ + self::$sheet = self::$spreadsheet->getActiveSheet(); + } + return $this; + } + + /** + *设置字体格式 + * @param $title string 必选 + * return string + */ + public static function setUtf8($title) + { + return iconv('utf-8', 'gb2312', $title); + } + /** + * 创建保存excel目录 + * return string + */ + public static function savePath() + { + if(!is_dir(self::$path)){ + if (mkdir(self::$path, 0700) == false) { + return false; + } + } + //年月一级目录 + $mont_path = self::$path.date('Ym'); + if(!is_dir($mont_path)){ + if (mkdir($mont_path, 0700) == false) { + return false; + } + } + //日二级目录 + $day_path = $mont_path.'/'.date('d'); + if(!is_dir($day_path)){ + if (mkdir($day_path, 0700) == false) { + return false; + } + } + return $day_path; + } + /** + * 设置标题 + * @param $title string || array ['title'=>'','name'=>'','info'=>[]] + * @param $Name string + * @param $info string || array; + * @param $funName function($style,$A,$A2) 自定义设置头部样式 + * @return $this + */ + public function setExcelTile(array $data) + { + //设置参数 + if (is_array($data)) { + if (isset($data['title'])) $title = $data['title']; + if (isset($data['sheets'])) $sheets = $data['sheets']; + } + empty($title) ? $title = self::$title : self::$title = $title; + + if (empty($sheets)) $sheets = time(); + + //设置Excel属性 + self::$spreadsheet->getProperties() + ->setCreator("Neo") + ->setLastModifiedBy("Neo") + ->setTitle(self::setUtf8($title)) + ->setSubject($sheets) + ->setDescription("") + ->setKeywords($sheets) + ->setCategory(""); + self::$sheet->setTitle($sheets); + + self::$sheet->mergeCells('A1:' . self::$cells . '1'); //合并表头单元格 + self::$sheet->getRowDimension('A')->setRowHeight(40); //设置行高 + self::$sheet->setCellValue('A1', $title); //负值 + self::$sheet->getStyle('A1')->getFont()->setName('黑体'); + self::$sheet->getStyle('A1')->getFont()->setSize(20); + self::$sheet->getStyle('A1')->getFont()->setBold(true); + self::$sheet->getStyle('A1')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); //设置左对齐 + + if(isset($data['mark']) && !empty($data['mark'])){ + foreach ($data['mark'] as $k => $v){ + $i = $k + 2; + self::$sheet->mergeCells('A'.$i.':' . self::$cells . $i); + self::$sheet->setCellValue('A'.$i, $v); + + self::$sheet->getStyle('A'.$i)->getFont()->setName('宋体'); + self::$sheet->getStyle('A'.$i)->getFont()->setSize(16); + self::$sheet->getStyle('A'.$i)->getFont()->setBold(true); + self::$sheet->getStyle('A'.$i)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT); + } + } + + return $this; + } + + /** + * 设置第二行标题内容 + * @param $info array (['name'=>'','site'=>'','phone'=>123] || ['我是表名','我是地址','我是手机号码'] ) || string 自定义 + * @return string + */ + private static function setCellInfo($info) + { + $content = ['操作者:', '导出日期:' . date('Y-m-d', time()), '地址:', '电话:']; + if (is_array($info) && !empty($info)) { + if (isset($info['name'])) { + $content[0] .= $info['name']; + } else { + $content[0] .= isset($info[0]) ? $info[0] : ''; + } + if (isset($info['site'])) { + $content[2] .= $info['site']; + } else { + $content[2] .= isset($info[1]) ? $info[1] : ''; + } + if (isset($info['phone'])) { + $content[3] .= $info['phone']; + } else { + $content[3] .= isset($info[2]) ? $info[2] : ''; + } + return implode(' ', $content); + } else if (is_string($info)) { + return empty($info) ? implode(' ', $content) : $info; + } + } + /** + * 设置头部信息 + * @param $data array + * @return $this + */ + public function setExcelHeader($data,$topNumber) + { + $span = 'A'; + self::$topNumber = $topNumber; + foreach ($data as $key => $value) { + self::$sheet->getColumnDimension($span)->setWidth(self::$width); + self::$sheet->setCellValue($span.self::$topNumber, $value); + self::$sheet->getStyle($span.self::$topNumber)->getFont()->setSize(16); + $span++; + } + $span = chr(ord($span) -1); + self::$sheet->getRowDimension(self::$topNumber)->setRowHeight(25); + self::$sheet->getStyle('A1:' . $span.self::$topNumber)->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + self::$cells = $span; + + return $this; + } + + /** + * + * execl数据导出 + * @param $data 需要导出的数据 格式和以前的可是一样 + * + * 特殊处理:合并单元格需要先对数据进行处理 + */ + public function setExcelContent($data = []) + { + if (!empty($data) && is_array($data)) { + $column = self::$topNumber+1; + // 行写入 + foreach ($data as $key => $rows) { + $span = 'A'; + // 列写入 + foreach ($rows as $keyName => $value) { + self::$sheet->setCellValue($span . $column, $value); + $span++; + } + $column++; + } + $span = chr(ord($span) -1); + self::$colum = $column; + self::$sheet->getDefaultRowDimension()->setRowHeight(self::$height); + //设置内容字体样式 + self::$sheet->getStyle('A'.self::$topNumber .':'. $span.$column)->applyFromArray(self::$styleArray); + //设置边框 + self::$sheet->getStyle('A1:' . $span.$column )->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + //设置自动换行 + self::$sheet->getStyle('A4:' . $span.$column)->getAlignment()->setWrapText(true); + } + return $this; + } + + public function setExcelEnd(array $data) + { + if(!empty($data)){ + foreach ($data as $key => $value){ + $i = self::$colum + $key ; + self::$sheet->mergeCells('A'.$i.':' . self::$cells.$i); + self::$sheet->setCellValue('A'.$i, $value); + + self::$sheet->getStyle('A'.$i)->getFont()->setName('宋体'); + self::$sheet->getStyle('A'.$i)->getFont()->setSize(16); + self::$sheet->getStyle('A'.$i)->getFont()->setBold(true); + self::$sheet->getStyle('A'.$i)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT); + } + self::$sheet->getStyle('A1:' .self::$cells.$i)->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + } + return $this; + } + + + /** + * 保存表格数据 + * @param $filename 文件名称 + * @param $suffix 文件后缀名 + * @param $path 是否保存文件文件 + * @return 保存文件:return string + */ + public function excelSave($fileName = '',$suffix = 'xlsx',$path) + { + if(empty($fileName)) $fileName = date('YmdHis').time(); + if(empty($suffix)) $suffix = 'xlsx'; + // 重命名表(UTF8编码不需要这一步) + if (mb_detect_encoding($fileName) != "UTF-8") $fileName = iconv("utf-8", "gbk//IGNORE", $fileName); + + $save_path = self::$path.$path; + $root_path = app()->getRootPath().'public/'.$save_path; + if(!is_dir($root_path)) mkdir($root_path, 0755,true); + $spreadsheet = self::$spreadsheet; + $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet); + $writer->save($root_path.'/'.$fileName.'.'.$suffix); + + return $save_path.'/'.$fileName.'.'.$suffix; + } + + /** + * TODO + * @param $filePath 文件路径 + * @param array $sql 需要入库的字段 => excel表的列 例 [order_sn => 'B'] + * @param array $where 每条入库的条件 同上 + * @param int $startRow 有效数据从第几行开始 + * @return array + * @author Qinii + * @day 3/15/21 + */ + public function _import($filePath,array $sql,$where = [],$startRow = 1) + { + if(!file_exists($filePath)) return ; + $ext = ucfirst(pathinfo($filePath, PATHINFO_EXTENSION)); + $ret = []; + if (in_array($ext, ['Xlsx', 'Xls'])) { + $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($ext); + $spreadsheet = $reader->load($filePath); + $sheet = $spreadsheet->getActiveSheet(); + $row_count = $sheet->getHighestDataRow();//取得总行数 + for ($row = $startRow; $row <= $row_count; $row++) { + $con = []; + $item = []; + $one = []; +// $getK = $sheet->getCell('A'.$row)->getValue(); +// if ($getK) { +// $getV = $sheet->getCell('B'.$row)->getValue(); +// $one[] = [$getK => $getV]; +// } + if (!empty($where)) { + foreach ($where as $k => $v) { + $con_value = $sheet->getCell($v . $row)->getValue(); + if ($con_value) { + $con[$k] = $con_value; + } + } + if (!empty($con)) $one['where'] = $con; + } + if ($con && !empty($sql)) { + foreach ($sql as $key => $value) { + $key_value = $sheet->getCell($value . $row)->getValue(); + $item[$key] = $key_value ?? ''; + } + if (!empty($item)) $one['value'] = $item; + } + if ($one) $ret[] = $one; + } + } + + return $ret; + } + + /** + * TODO 检测导入格式 + * @param $filePath + * @param array $check + * @return bool + * @author Qinii + * @day 5/7/21 + */ + public function checkImport($filePath,$check = []) + { + $ext = ucfirst(pathinfo($filePath, PATHINFO_EXTENSION)); + $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($ext); + $spreadsheet = $reader->load($filePath); + $sheet = $spreadsheet->getActiveSheet(); + if(!empty($check)){ + foreach ($check as $s => $c){ + $_c = $sheet->getCell($s)->getValue(); + if($_c !== $c) throw new ValidateException('表格"'.$s.'"不是"'.$c.'"不可导入'); + } + } + return true; + } + +} diff --git a/crmeb/services/SwooleTaskService.php b/crmeb/services/SwooleTaskService.php new file mode 100644 index 00000000..00a8779b --- /dev/null +++ b/crmeb/services/SwooleTaskService.php @@ -0,0 +1,160 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use Swoole\Server; +use think\facade\Log; + +/** + * Class SwooleTaskService + * @package crmeb\services + * @author xaboy + * @day 2020-04-15 + */ +class SwooleTaskService +{ + /** + * @var string + */ + protected $type; + + /** + * @var array + */ + protected $data; + + /** + * @var Server + */ + protected $server; + + /** + * @var + */ + protected $callback; + + /** + * SwooleTaskService constructor. + * @param string $type + */ + public function __construct(string $type) + { + $this->type = $type; + $this->server = app('swoole.server'); + } + + /** + * @param array $data + * @return $this + * @author xaboy + * @day 2020-04-15 + */ + public function setData(array $data) + { + $this->data = $data; + + return $this; + } + + /** + * @param int $workId + * @return mixed + * @author xaboy + * @day 2020-04-15 + */ + public function push(int $workId = -1) + { + try { + + return $this->server->task(['type' => $this->type, 'data' => $this->data], $workId); + } catch (\Exception $e) { + Log::info('发送 Task 失败' . $e->getMessage()); + } + } + + /** + * @param string $type + * @return static + * @author xaboy + * @day 2020/5/25 + */ + public static function create(string $type) + { + return new static($type); + } + + public static function user($uid, $data) + { + $type = 'user'; + return self::create('message')->setData(compact('type', 'uid', 'data'))->push(); + } + + public static function admin(string $msgType, array $msgData, $uid = []) + { + return self::create('admin')->setData([ + 'uid' => $uid, + 'data' => [ + 'type' => $msgType, + 'data' => $msgData + ] + ])->push(); + } + + public static function merchant(string $msgType, array $msgData, int $merId, $uid = []) + { + return self::create('merchant')->setData([ + 'uid' => $uid, + 'mer_id' => $merId, + 'data' => [ + 'type' => $msgType, + 'data' => $msgData + ] + ])->push(); + } + + + /** + * @param $merId + * @param array $result + * @return mixed + * @author xaboy + * @day 2020/5/25 + */ + public static function log($merId, array $result) + { + return self::create('log')->setData(compact('merId', 'result'))->push(); + } + + /** + * @param int $uid + * @param int $type_id + * @param string $type + * @param string $content + * @return mixed + * @author xaboy + * @day 2020/6/25 + */ + public static function visit(int $uid, int $type_id, string $type, string $content = '') + { + return self::create('visit')->setData(compact('uid', 'type', 'type_id', 'content'))->push(); + } + + + public static function __callStatic($name, $arguments) + { + return self::create($name)->setData($arguments[0])->push(); + } + +} diff --git a/crmeb/services/TimerService.php b/crmeb/services/TimerService.php new file mode 100644 index 00000000..053e6867 --- /dev/null +++ b/crmeb/services/TimerService.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use Swoole\Timer; +use think\facade\Log; + +class TimerService +{ + public function tick($limit, $fn) + { + Timer::tick($limit, function () use ($fn) { + try { + $fn(); + } catch (\Throwable $e) { + Log::error('定时器报错[' . class_basename($this) . ']: ' . $e->getMessage()); + } + }); + } +} diff --git a/crmeb/services/UpdateAuthInit.php b/crmeb/services/UpdateAuthInit.php new file mode 100644 index 00000000..0e1981b1 --- /dev/null +++ b/crmeb/services/UpdateAuthInit.php @@ -0,0 +1,173 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + +use app\common\repositories\system\config\ConfigClassifyRepository; +use app\common\repositories\system\groupData\GroupDataRepository; +use app\common\repositories\system\groupData\GroupRepository; +use crmeb\interfaces\RouteParserInterface; +use think\Exception; +use think\exception\ValidateException; +use think\facade\Log; + +class UpdateAuthInit implements RouteParserInterface +{ + public function create($route, $method = 'config') + { + return $this->{$method}($route); + } + + public function config($route) + { + $resp[] = $route; + $append = $route['option']['_append'] ?? []; + try { + $data = app()->make(ConfigClassifyRepository::class)->getSearch(['status' => 1]) + ->field('classify_name _alias,classify_key _params') + ->select()->toArray(); + + foreach ($data as $k => $v) { + if ($v['_params'] == 'distribution_tabs') continue; + $v['_path'] = '/systemForm/Basics/'.$v['_params']; + $v['_name'] = $route['name']; + $v['_alias'] = $route['option']['_alias']; + $v['_repeat'] = true; + $v['_append'] = $append; + $resp[]['option'] = $v; + } + + }catch (Exception $e) { + throw new ValidateException('配置路由执行失败:' .$e->getMessage()); + } + return $resp; + } + + public function groupData($route) + { + $resp[] = $route; + $append = $route['option']['_append'] ?? []; + try { + $data = app()->make(GroupRepository::class)->getSearch([]) + ->field('group_name _alias,group_id _params') + ->select()->toArray(); + foreach ($data as $k => $v) { + $v['_path'] = '/group/config/'.$v['_params']; + $v['_name'] = $route['name']; + $v['_alias'] = $route['option']['_alias']; + $v['_repeat'] = true; + $v['_append'] = $append; + $resp[]['option'] = $v; + $v['_path'] = '/group/topic/'.$v['_params']; + $resp[]['option'] = $v; + } + }catch (Exception $e) { + throw new ValidateException('组合数据路由执行失败:' .$e->getMessage()); + } + return $resp; + } + + public function agreement($route) + { + $resp[] = $route; + try { + $resp = [ + [ + 'option' => [ + '_name' =>'systemAgreeSave', + '_path' =>'/marketing/presell/agreement', + '_alias' => '预售协议', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' =>'systemAgreeSave', + '_path' =>'/promoter/commission', + '_alias' => '佣金说明', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' =>'systemAgreeSave', + '_path' =>'/promoter/distribution', + '_alias' => '等级规则', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' =>'systemAgreeSave', + '_path' =>'/marketing/Platform_coupon/instructions', + '_alias' => '使用说明', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' =>'systemAgreeSave', + '_path' =>'/user/agreement', + '_alias' => '用户协议', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' =>'systemAgreeSave', + '_path' =>'/user/member/description', + '_alias' => '会员等级规则', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' => 'systemAgreeSave', + '_path' => '/setting/agreements', + '_alias' => '商户入住申请协议', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' => 'systemAgreeSave', + '_path' => '/merchant/type/description', + '_alias' => '店铺类型说明 ', + '_repeat'=> true, + '_auth' => true, + ], + ], + [ + 'option' => [ + '_name' => 'systemAgreeSave', + '_path' => '/accounts/invoiceDesc', + '_alias' => '发票说明 ', + '_repeat'=> true, + '_auth' => true, + ], + ], + ]; + }catch (Exception $e) { + throw new ValidateException('协议路由执行失败:' .$e->getMessage()); + } + return $resp; + } + +} diff --git a/crmeb/services/UploadService.php b/crmeb/services/UploadService.php new file mode 100644 index 00000000..fffd152f --- /dev/null +++ b/crmeb/services/UploadService.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + +use crmeb\services\upload\Upload; + +/** + * Class UploadService + * @package crmeb\services + */ +class UploadService +{ + + /** + * @param $type + * @return Upload + */ + public static function create($type = null) + { + if (is_null($type)) { + $type = (int)systemConfig('upload_type') ?: 1; + } + $type = (int)$type; + + switch ($type) { + case 1: //本地 + $prefix = 'local'; + break; + case 2://七牛 + $prefix = 'qiniu'; + break; + case 3:// oss 阿里云 + break; + case 4:// cos 腾讯云 + $prefix = 'tengxun'; + break; + case 5: + $prefix = 'obs'; + break; + case 6: + $prefix = 'uc'; + break; + } + + //获取配置 + $accessKey = isset($prefix) ? $prefix.'_accessKey' : 'accessKey'; + $secretKey = isset($prefix) ? $prefix.'_secretKey' : 'secretKey'; + $auploadUrl = isset($prefix) ? $prefix.'_uploadUrl' : 'uploadUrl'; + $storage_name = isset($prefix) ? $prefix.'_storage_name' : 'storage_name'; + $storage_region = isset($prefix) ? $prefix.'_storage_region' : 'storage_region'; + $cdn = isset($prefix) ? $prefix.'_cdn' : 'oss_cdn'; + $thumb_status = isset($prefix) ? $prefix.'_thumb_status' : 'thumb_status'; + $thumb_rate = isset($prefix) ? $prefix.'_thumb_rate' : 'thumb_rate'; + + $data = systemConfig([$accessKey, $secretKey, $auploadUrl, $storage_name, $storage_region, $cdn,$thumb_status,$thumb_rate]); + if ($data[$cdn]) { + if (substr( $data[$cdn],0,4) !== 'http') { + $data[$cdn] = 'https'.$data[$cdn]; + } + } + $config = [ + 'accessKey' => $data[$accessKey], + 'secretKey' => $data[$secretKey], + 'uploadUrl' => $data[$auploadUrl], + 'storageName' => $data[$storage_name], + 'storageRegion' => $data[$storage_region], + 'cdn' => rtrim($data[$cdn],'/'), + 'thumb_status' => $data[$thumb_status], + 'thumb_rate' => $data[$thumb_rate], + ]; + + return new Upload($type, $config); + } +} diff --git a/crmeb/services/VicWordService.php b/crmeb/services/VicWordService.php new file mode 100644 index 00000000..2f046271 --- /dev/null +++ b/crmeb/services/VicWordService.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use Lizhichao\Word\VicWord; + +class VicWordService +{ + + public function getWord($str) + { + $data = [$str]; + if (systemConfig('vic_word_status')) { + ini_set('memory_limit', '-1'); + $vicWord = new VicWord(); + $word = $vicWord->getAutoWord($str); + foreach ($word as $item) { + if ($item[2] === '0' || is_numeric($item[0])) { + continue; + } + $data[] = $item[0]; + } + } + return $data; + } +} diff --git a/crmeb/services/WechatService.php b/crmeb/services/WechatService.php new file mode 100644 index 00000000..a696e5c4 --- /dev/null +++ b/crmeb/services/WechatService.php @@ -0,0 +1,1072 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\wechat\WechatQrcodeRepository; +use app\common\repositories\wechat\WechatReplyRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\exceptions\WechatException; +use crmeb\utils\ApiErrorCode; +use EasyWeChat\Core\Exceptions\FaultException; +use EasyWeChat\Core\Exceptions\InvalidArgumentException; +use EasyWeChat\Core\Exceptions\RuntimeException; +use EasyWeChat\Foundation\Application; +use EasyWeChat\Message\Article; +use EasyWeChat\Message\Image; +use EasyWeChat\Message\Material; +use EasyWeChat\Message\News; +use EasyWeChat\Message\Text; +use EasyWeChat\Message\Video; +use EasyWeChat\Message\Voice; +use EasyWeChat\Payment\Order; +use EasyWeChat\Server\BadRequestException; +use EasyWeChat\Support\Collection; +use Exception; +use Symfony\Component\HttpFoundation\Request; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Event; +use think\facade\Log; +use think\facade\Route; +use think\Response; + +/** + * Class WechatService + * @package crmeb\services + * @author xaboy + * @day 2020-04-20 + */ +class WechatService +{ + /** + * @var Application + */ + protected $application; + + protected $config; + + /** + * WechatService constructor. + * @param $config + */ + public function __construct(array $config) + { + $this->config = $config; + $this->application = new Application($config); + $this->application->register(new \crmeb\services\easywechat\certficates\ServiceProvider()); + $this->application->register(new \crmeb\services\easywechat\merchant\ServiceProvider); + $this->application->register(new \crmeb\services\easywechat\combinePay\ServiceProvider); + $this->application->register(new \crmeb\services\easywechat\pay\ServiceProvider); + $this->application->register(new \crmeb\services\easywechat\batches\ServiceProvider); + } + + /** + * @return array + * @author xaboy + * @day 2020-04-24 + */ + public static function getConfig($isApp) + { + /** @var ConfigValueRepository $make */ + $make = app()->make(ConfigValueRepository::class); + $wechat = $make->more([ + 'wechat_appid', 'wechat_appsecret', 'wechat_token', 'wechat_encodingaeskey', 'wechat_encode', 'wecaht_app_appid', 'wechat_app_appsecret' + ], 0); + + if ($isApp ?? request()->isApp()) { + $wechat['wechat_appid'] = trim($wechat['wecaht_app_appid']); + $wechat['wechat_appsecret'] = trim($wechat['wechat_app_appsecret']); + } + $payment = $make->more(['site_url', 'pay_weixin_mchid', 'pay_weixin_client_cert', 'pay_weixin_client_key', 'pay_weixin_key', 'pay_weixin_v3_key', 'pay_weixin_open','pay_wechat_serial_no_v3', 'wechat_service_merid', 'wechat_service_key', 'wechat_service_v3key', 'wechat_service_client_cert', 'wechat_service_client_key', 'wechat_service_serial_no'], 0); + $config = [ + 'app_id' => trim($wechat['wechat_appid']), + 'secret' => trim($wechat['wechat_appsecret']), + 'token' => trim($wechat['wechat_token']), + 'routine_appId' => systemConfig('routine_appId'), + 'guzzle' => [ + 'timeout' => 10.0, // 超时时间(秒) + 'verify' => false + ], + 'debug' => false, + ]; + if ($wechat['wechat_encode'] > 0 && $wechat['wechat_encodingaeskey']) + $config['aes_key'] = trim($wechat['wechat_encodingaeskey']); + $is_v3 = false; + if (isset($payment['pay_weixin_open']) && $payment['pay_weixin_open'] == 1) { + $config['payment'] = [ + 'merchant_id' => trim($payment['pay_weixin_mchid']), + 'key' => trim($payment['pay_weixin_key']), + 'apiv3_key' => trim($payment['pay_weixin_v3_key']), + 'serial_no' => trim($payment['pay_wechat_serial_no_v3']), + 'cert_path' => (app()->getRootPath() . 'public' . $payment['pay_weixin_client_cert']), + 'key_path' => (app()->getRootPath() . 'public' . $payment['pay_weixin_client_key']), + 'notify_url' => $payment['site_url'] . Route::buildUrl('wechatNotify')->build(), + 'pay_weixin_client_cert' => $payment['pay_weixin_client_cert'], + 'pay_weixin_client_key' => $payment['pay_weixin_client_key'], + ]; + if ($config['payment']['apiv3_key']) { + $is_v3 = true; + } + } + $config['is_v3'] = $is_v3; + $config['service_payment'] = [ + 'merchant_id' => trim($payment['wechat_service_merid']), + 'type' => 'wechat', + 'key' => trim($payment['wechat_service_key']), + 'cert_path' => (app()->getRootPath() . 'public' . $payment['wechat_service_client_cert']), + 'key_path' => (app()->getRootPath() . 'public' . $payment['wechat_service_client_key']), + 'pay_weixin_client_cert' => $payment['wechat_service_client_cert'], + 'pay_weixin_client_key' => $payment['wechat_service_client_key'], + 'serial_no' => trim($payment['wechat_service_serial_no']), + 'apiv3_key' => trim($payment['wechat_service_v3key']), + ]; + return $config; + } + + /** + * @return self + * @author xaboy + * @day 2020-04-24 + */ + public static function create($isApp = null) + { + return new self(self::getConfig($isApp)); + } + + public function isV3() + { + return $this->config['is_v3'] ?? false; + } + + public function v3Pay() + { + return $this->application->v3Pay; + } + + /** + * @return Application + * @author xaboy + * @day 2020-04-20 + */ + public function getApplication() + { + return $this->application; + } + + /** + * @param \think\Request $request + * @return Response + * @throws BadRequestException + * @throws InvalidArgumentException + * @author xaboy + * @day 2020-04-26 + */ + public function serve(\think\Request $request) + { + $this->serverRequest($request); + $this->wechatEventHook(); + return response($this->application->server->serve()->getContent()); + } + + protected function serverRequest(\think\Request $request) + { + $this->application->server->setRequest(new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent())); + } + + /** + * @throws InvalidArgumentException + * @author xaboy + * @day 2020-04-20 + */ + public function wechatEventHook() + { + $this->application->server->setMessageHandler(function ($message) { + $openId = $message->FromUserName; + $message->EventKey = str_replace('qrscene_', '', $message->EventKey); + $userInfo = $this->getUserInfo($openId); + /** @var WechatUserRepository $wechatUserRepository */ + $wechatUserRepository = app()->make(WechatUserRepository::class); + $users = $wechatUserRepository->syncUser($openId, $userInfo, true); + + $scanLogin = function () use ($message, $users) { + $ticket = $message->EventKey; + if (strpos($ticket, '_sys_scan_login.') === 0) { + $key = str_replace('_sys_scan_login.', '', $ticket); + if(Cache::has('_scan_login' . $key)){ + Cache::set('_scan_login' . $key, $users[1]['uid']); + } + } + }; + + $response = null; + /** @var WechatReplyRepository $make * */ + $make = app()->make(WechatReplyRepository::class); + event('wechat.message', compact('message')); + switch ($message->MsgType) { + case 'event': + event('wechat.event', compact('message')); + switch (strtolower($message->Event)) { + case 'subscribe': + $scanLogin(); + $response = $this->qrKeyByMessage($message->EventKey) ?: $make->reply('subscribe'); + if (isset($message->EventKey) && $message->EventKey) { + /** @var WechatQrcodeRepository $qr */ + $qr = app()->make(WechatQrcodeRepository::class); + if ($qrInfo = $qr->ticketByQrcode($message->Ticket)) { + $qrInfo->incTicket(); + if (strtolower($qrInfo['third_type']) == 'spread' && $users) { + $spreadUid = $qrInfo['third_id']; + if ($users[1]['uid'] == $spreadUid) + return '自己不能推荐自己'; + else if ($users[1]['spread_uid']) + return '已有推荐人!'; + try { + $users[1]->setSpread($spreadUid); + } catch (Exception $e) { + return '绑定推荐人失败'; + } + } + } + } + event('wechat.event.subscribe', compact('message')); + break; + case 'unsubscribe': + $wechatUserRepository->unsubscribe($openId); + event('wechat.event.unsubscribe', compact('message')); + break; + case 'scan': + $scanLogin(); + $response = $this->qrKeyByMessage($message->EventKey) ?: $make->reply('subscribe'); + /** @var WechatQrcodeRepository $qr */ + $qr = app()->make(WechatQrcodeRepository::class); + if ($message->EventKey && ($qrInfo = $qr->ticketByQrcode($message->Ticket))) { + $qrInfo->incTicket(); + if (strtolower($qrInfo['third_type']) == 'spread' && $users) { + $spreadUid = $qrInfo['third_id']; + if ($users[1]['uid'] == $spreadUid) + return '自己不能推荐自己'; + else if ($users[1]['spread_uid']) + return '已有推荐人!'; + try { + $users[1]->setSpread($spreadUid); + } catch (Exception $e) { + return '绑定推荐人失败'; + } + } + } + event('wechat.event.scan', compact('message')); + break; + case 'location': + event('wechat.event.location', compact('message')); + break; + case 'click': + $response = $make->reply($message->EventKey); + event('wechat.event.click', compact('message')); + break; + case 'view': + event('wechat.event.view', compact('message')); + break; + case 'funds_order_pay': + if (($count = strpos($message['order_info']['trade_no'], '_')) !== false) { + $trade_no = substr($message['order_info']['trade_no'], $count + 1); + } else { + $trade_no = $message['order_info']['trade_no']; + } + $prefix = substr($trade_no, 0, 3); + //处理一下参数 + switch ($prefix) { + case StoreOrderRepository::TYPE_SN_ORDER: + $attach = 'order'; + break; + case StoreOrderRepository::TYPE_SN_PRESELL: + $attach = 'presell'; + break; + case StoreOrderRepository::TYPE_SN_USER_ORDER: + $attach = 'user_order'; + break; + case StoreOrderRepository::TYPE_SN_USER_RECHARGE: + $attach = 'user_recharge'; + break; + } + event('pay_success_' . $attach, ['order_sn' => $message['order_info']['trade_no'], 'data' => $message, 'is_combine' => 0]); + break; + } + break; + case 'text': + if (preg_match('/^(\/@[1-9]{1}).*\*\//', $message->Content)) { + $command = app()->make(CopyCommand::class)->getMassage($message->Content); + if (empty($command)) { + $response = self::textMessage('无效口令'); + } else { + if ($command['type'] == 30) $command['type'] = 3; + $key = '_scan_url_' . $command['type'] . '_' . $command['id'] . '_' . $command['uid']; + $response = $this->qrKeyByMessage($key); + } + } else { + $response = $make->reply($message->Content); + } + event('wechat.message.text', compact('message')); + break; + case 'image': + event('wechat.message.image', compact('message')); + break; + case 'voice': + event('wechat.message.voice', compact('message')); + break; + case 'video': + event('wechat.message.video', compact('message')); + break; + case 'location': + event('wechat.message.location', compact('message')); + break; + case 'link': + event('wechat.message.link', compact('message')); + break; + // ... 其它消息 + default: + event('wechat.message.other', compact('message')); + break; + } + + return $response ?? false; + }); + } + + /** + * @param $value + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function qrcodeForever($value) + { + return $this->application->qrcode->forever($value); + } + + /** + * @param $value + * @param int $expireSeconds + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function qrcodeTemp($value, $expireSeconds = 2592000) + { + return $this->application->qrcode->temporary($value, $expireSeconds); + } + + /** + * @param string $openid + * @param string $templateId + * @param array $data + * @param null $url + * @param null $defaultColor + * @return mixed + * @author xaboy + * @day 2020-04-20 + */ + public function sendTemplate(string $openid, string $templateId, array $data, $url = null, $defaultColor = null, $miniprogram = []) + { + $notice = $this->application->notice->to($openid)->template($templateId)->andData($data); + if ($url !== null) $notice->url($url); + if ($defaultColor !== null) $notice->defaultColor($defaultColor); + return $notice->send($miniprogram); + } + + /** + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Order + * @author xaboy + * @day 2020-04-20 + */ + protected function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $total_fee = bcmul($total_fee, 100, 0); + $order = array_merge(compact('out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options); + if (!is_null($openid)) $order['openid'] = $openid; + if ($order['detail'] == '') unset($order['detail']); + $order['spbill_create_ip'] = \request()->ip(); + return new Order($order); + } + + /** + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $order = $this->paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options); + if ($this->isV3()) { + if ($trade_type == 'MWEB') $trade_type = 'H5'; + $payFunction = 'pay'.ucfirst($trade_type); + return $this->application->v3Pay->{$payFunction}($order); + } else { + $result = $this->application->payment->prepare($order); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result; + } else { + if ($result->return_code == 'FAIL') { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new WechatException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new WechatException('没有获取微信支付的预支付ID,请重新发起支付!'); + } + } + } + } + + /** 扫码枪支付 + * @param $out_trade_no + * @param $total_fee + * @param $body + * @param $device_info + * @param $nonce_str + * @param $auth_code + * @return Collection|\Psr\Http\Message\ResponseInterface + */ + public function paymentMicropay($out_trade_no, $total_fee, $body, $device_info,$nonce_str,$auth_code) + { + $total_fee = bcmul($total_fee, 100, 0); + $order = array_merge(compact('out_trade_no', 'total_fee', 'body', 'device_info','nonce_str','auth_code')); + $order['spbill_create_ip'] = \request()->ip(); + $order= new Order($order); + $result = $this->application->payment->pay($order); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result; + } else { + if ($result->return_code == 'FAIL') { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new WechatException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new WechatException('没有获取微信支付的预支付ID,请重新发起支付!'); + } + } + } + /** + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return array|string + * @author xaboy + * @day 2020-04-20 + */ + public function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $paymentPrepare = $this->paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options); + if ($this->isV3()) { + return $paymentPrepare; + } + return $trade_type === 'APP' + ? $this->application->payment->configForAppPayment($paymentPrepare->prepay_id) + : $this->application->payment->configForJSSDKPayment($paymentPrepare->prepay_id); + } + + /** + * @param $orderNo + * @param $refundNo + * @param $totalFee + * @param null $refundFee + * @param null $opUserId + * @param string $refundReason + * @param string $type + * @param string $refundAccount + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '', $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS') + { + if (empty($this->config['payment']['pay_weixin_client_cert']) || empty($this->config['payment']['pay_weixin_client_key'])) { + throw new \Exception('请配置微信支付证书'); + } + $totalFee = floatval($totalFee); + $refundFee = floatval($refundFee); + if ($this->isV3()) { + return $this->application->v3Pay->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason); + } else { + return $this->application->payment->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason); + } + } + + /** + * @param $orderNo + * @param array $opt + * @author xaboy + * @day 2020-04-20 + */ + public function payOrderRefund($orderNo, array $opt) + { + if (!isset($opt['pay_price'])) throw new WechatException('缺少pay_price'); + $totalFee = floatval(bcmul($opt['pay_price'], 100, 0)); + $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'], 100, 0)) : null; + $refundReason = isset($opt['refund_message']) ? $opt['refund_message'] : '无'; + $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo; + $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null; + $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no'; + + //若传递此参数则使用对应的资金账户退款,否则默认使用未结算资金退款(仅对老资金流商户适用) + $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS'; + try { + $res = ($this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount)); + if (isset($res->return_code) && $res->return_code== 'FAIL') + throw new WechatException('退款失败:' . $res->return_msg); + if (isset($res->err_code)) + throw new WechatException('退款失败:' . $res->err_code_des); + } catch (Exception $e) { + throw new WechatException($e->getMessage()); + } + } + + /** + * array ( + * 'appid' => '****', + * 'attach' => 'user_recharge', + * 'bank_type' => 'COMM_CREDIT', + * 'cash_fee' => '1', + * 'fee_type' => 'CNY', + * 'is_subscribe' => 'Y', + * 'mch_id' => ''*****'', + * 'nonce_str' => '5ee9dac1bc302', + * 'openid' => '*****', + * 'out_trade_no' => ''*****'', + * 'result_code' => 'SUCCESS', + * 'return_code' => 'SUCCESS', + * 'sign' => '51'*****'', + * 'time_end' => '20200617165651', + * 'total_fee' => '1', + * 'trade_type' => 'JSAPI', + * 'transaction_id' => ''*****'', + * ) + * + * @throws FaultException + * @author xaboy + * @day 2020-04-20 + */ + public function handleNotify() + { + $this->application->payment = new PaymentService($this->application->merchant); + //TODO 微信支付 + return $this->application->payment->handleNotify(function ($notify, $successful) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $notify['attach'], ['order_sn' => $notify['out_trade_no'], 'data' => $notify, 'is_combine' => 0]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + public function handleNotifyV3() + { + return $this->application->v3Pay->handleNotify(function ($notify, $successful) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $notify['attach'], ['order_sn' => $notify['out_trade_no'], 'data' => $notify, 'is_combine' => 0]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + public function handleCombinePayNotify($type) + { + return $this->application->combinePay->handleNotify(function ($notify, $successful) use ($type) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $type, ['order_sn' => $notify['combine_out_trade_no'], 'data' => $notify, 'is_combine' => 1]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + /** + * @param string $url + * @return array|string + * @author xaboy + * @day 2020-04-20 + */ + public function jsSdk($url) + { + $apiList = ['editAddress', 'openAddress', 'updateTimelineShareData', 'updateAppMessageShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'onVoicePlayEnd', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'translateVoice', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard']; + $jsService = $this->application->js; + $jsService->setUrl($url); + try { + return $jsService->config($apiList, false, false, false); + } catch (Exception $e) { + Log::info('微信参数获取失败' . $e->getMessage()); + return []; + } + + } + + /** + * 回复文本消息 + * @param string $content 文本内容 + * @return Text + * @author xaboy + * @day 2020-04-20 + */ + public static function textMessage($content) + { + return new Text(compact('content')); + } + + /** + * 回复图片消息 + * @param string $media_id 媒体资源 ID + * @return Image + * @author xaboy + * @day 2020-04-20 + */ + public static function imageMessage($media_id) + { + return new Image(compact('media_id')); + } + + /** + * 回复视频消息 + * @param string $media_id 媒体资源 ID + * @param string $title 标题 + * @param string $description 描述 + * @param null $thumb_media_id 封面资源 ID + * @return Video + * @author xaboy + * @day 2020-04-20 + */ + public static function videoMessage($media_id, $title = '', $description = '...', $thumb_media_id = null) + { + return new Video(compact('media_id', 'title', 'description', 'thumb_media_id')); + } + + /** + * 回复声音消息 + * @param string $media_id 媒体资源 ID + * @return Voice + * @author xaboy + * @day 2020-04-20 + */ + public static function voiceMessage($media_id) + { + return new Voice(compact('media_id')); + } + + /** + * 回复图文消息 + * @param string|array $title 标题 + * @param string $description 描述 + * @param string $url URL + * @param string $image 图片链接 + * @return News|array + * @author xaboy + * @day 2020-04-20 + */ + public static function newsMessage($title, $description = '...', $url = '', $image = '') + { + if (is_array($title)) { + if (isset($title[0]) && is_array($title[0])) { + $newsList = []; + foreach ($title as $news) { + $newsList[] = self::newsMessage($news); + } + return $newsList; + } else { + $data = $title; + } + } else { + $data = compact('title', 'description', 'url', 'image'); + } + return new News($data); + } + + /** + * 回复文章消息 + * @param string|array $title 标题 + * @param string $thumb_media_id 图文消息的封面图片素材id(必须是永久 media_ID) + * @param string $source_url 图文消息的原文地址,即点击“阅读原文”后的URL + * @param string $content 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS + * @param string $author 作者 + * @param string $digest 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空 + * @param int $show_cover_pic 是否显示封面,0为false,即不显示,1为true,即显示 + * @param int $need_open_comment 是否打开评论,0不打开,1打开 + * @param int $only_fans_can_comment 是否粉丝才可评论,0所有人可评论,1粉丝才可评论 + * @return Article + * @author xaboy + * @day 2020-04-20 + */ + public static function articleMessage($title, $thumb_media_id, $source_url, $content = '', $author = '', $digest = '', $show_cover_pic = 0, $need_open_comment = 0, $only_fans_can_comment = 1) + { + $data = is_array($title) ? $title : compact('title', 'thumb_media_id', 'source_url', 'content', 'author', 'digest', 'show_cover_pic', 'need_open_comment', 'only_fans_can_comment'); + return new Article($data); + } + + /** + * 回复素材消息 + * @param string $type [mpnews、 mpvideo、voice、image] + * @param string $media_id 素材 ID + * @return Material + * @author xaboy + * @day 2020-04-20 + */ + public static function materialMessage($type, $media_id) + { + return new Material($type, $media_id); + } + + /** + * @param $to + * @param $message + * @return bool + * @throws InvalidArgumentException + * @throws RuntimeException + * @author xaboy + * @day 2020-04-20 + */ + public function staffTo($to, $message) + { + $staff = $this->application->staff; + $staff = is_callable($message) ? $staff->message($message()) : $staff->message($message); + $res = $staff->to($to)->send(); + return $res; + } + + /** + * @param $openid + * @return array + * @author xaboy + * @day 2020-04-20 + */ + public function getUserInfo($openid) + { + $userService = $this->application->user; + $userInfo = is_array($openid) ? $userService->batchGet($openid) : $userService->get($openid); + return $userInfo->toArray(); + } + + + /** + * 模板消息接口 + * @return \EasyWeChat\Notice\Notice + */ + public function noticeService() + { + return $this->application->notice; + } + + + /** + * 微信二维码生成接口 + * @return \EasyWeChat\QRCode\QRCode + */ + public function qrcodeService() + { + return $this->application->qrcode; + } + + public function storePay() + { + return $this->application->storePay; + } + + /** + * TODO V3的商家到零钱 + * @author Qinii + * @day 2023/3/13 + */ + public function companyPay($data) + { + $transfer_detail_list[] = [ + 'out_detail_no' => $data['sn'], + 'transfer_amount' => $data['price'] * 100, + 'transfer_remark' => $data['mark'] ?? '', + //openid是微信用户在公众号appid下的唯一用户标识 + 'openid' => $data['openid'], + ]; + //商家到零钱 + $ret = [ + //商户系统内部的商家批次单号 + 'out_batch_no' => $data['sn'], + //该笔批量转账的名称 + 'batch_name' => $data['batch_name'], + //转账说明,UTF8编码,最多允许32个字符 + 'batch_remark' => $data['mark'] ?? '', + //转账金额单位为“分” + 'total_amount' => $data['price'] * 100, + //转账总笔数一个转账批次单最多发起三千笔转账 + 'total_num' => 1, + //该批次转账使用的转账场景,可在「商家转账到零钱 - 产品设置」中查看详情,如不填写则使用商家的默认转账场景 + 'transfer_detail_list' => $transfer_detail_list, + ]; + $result = $this->application->batches->send($ret); + return $result; + } + + /** + * TODO V2的企业到零钱 + * @param $data + * @return mixed + * @author Qinii + * @day 2023/3/13 + */ + public function merchantPay($data) + { + $ret = [ + 'partner_trade_no' => $data['sn'], //随机字符串作为订单号,跟红包和支付一个概念。 + 'openid' => $data['openid'], //收款人的openid + 'check_name' => 'NO_CHECK', //文档中有三种校验实名的方法 NO_CHECK OPTION_CHECK FORCE_CHECK + //'re_user_name'=>'张三', //OPTION_CHECK FORCE_CHECK 校验实名的时候必须提交 + 'amount' => $data['price'] * 100, //单位为分 + 'desc' => $data['mark'] ?? '', + 'spbill_create_ip' => request()->ip(), //发起交易的IP地址 + ]; + $result = $this->application->merchant_pay->send($ret); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result; + } else { + if ($result->return_code == 'FAIL') { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new WechatException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } + } + } + + /** + * TODO 分账商户 + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function applyments() + { + return $this->application->sub_merchant; + } + + + /** + * TODO 上传图片 + * @param array $filed + * @return mixed + * @author Qinii + * @day 6/21/21 + */ + public function uploadImages(array $filed) + { + if (empty($filed)) throw new InvalidArgumentException('图片为空'); + foreach ($filed as $file) { + $item = $this->application->sub_merchant->upload($file['path'], $file['name']); + $data[] = [ + 'dir' => $file['dir'], + 'media_id' => $item['media_id'], + ]; + } + return $data; + } + + public function qrKeyByMessage($key) + { + if (strpos($key, '_scan_url_') === 0) { + $key = str_replace('_scan_url_', '', $key); + $data = explode('_', $key); + $siteUrl = rtrim(systemConfig('site_url'), '/'); + $make = app()->make(ProductRepository::class); + if ($data[0] === 'home') { + $share = systemConfig(['share_title', 'share_info', 'share_pic']); + $share['url'] = $siteUrl . '?spid=' . $data[1]; + } else if ($data[0] === 'mer') { + $ret = app()->make(MerchantRepository::class)->get($data[1]); + if (!$ret) return; + $share = [ + 'share_title' => $ret['mer_name'], + 'share_info' => $ret['mer_info'], + 'share_pic' => $ret['mer_avatar'], + 'url' => $siteUrl . '/pages/store/home/index?id=' . $data[1], + ]; + } else if ($data[0] === 'p0') { + $ret = $make->get($data[1]); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $ret['image'], + 'url' => $siteUrl . '/pages/goods_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p1') { + $ret = $make->get($data[1]); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $ret['image'], + 'url' => $siteUrl . '/pages/activity/goods_seckill_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p2') { + $ret = app()->make(ProductPresellRepository::class)->search(['product_presell_id' => $data[1]])->find(); + $res = $make->get($ret['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $res['image'], + 'url' => $siteUrl . '/pages/activity/presell_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p3') { + $ret = app()->make(ProductAssistSetRepository::class)->getSearch(['product_assist_set_id' => $data[1]])->find(); + $res = $make->get($ret['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $res['store_name'], + 'share_info' => $res['store_info'], + 'share_pic' => $res['image'], + 'url' => $siteUrl . '/pages/activity/assist_detail/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p4') { + $ret = app()->make(ProductGroupRepository::class)->get($data[1]); + $res = $make->get($ret['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $res['store_name'], + 'share_info' => $res['store_info'], + 'share_pic' => $res['image'], + 'url' => $siteUrl . '/pages/activity/combination_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p40') { + $res = app()->make(ProductGroupBuyingRepository::class)->getSearch(['group_buying_id' => $data[1]])->find(); + $ret = $make->get($res->productGroup['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $ret['image'], + 'url' => $siteUrl . '/pages/activity/combination_status/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else { + return; + } + return self::newsMessage($share['share_title'], $share['share_info'], $share['url'], $share['share_pic']); + } + } + + + /** + * @return easywechat\combinePay\Client + */ + public function combinePay() + { + return $this->application->combinePay; + } + + + + /** + * 获取模板列表 + * @return \EasyWeChat\Support\Collection + */ + public function getPrivateTemplates() + { + try { + return $this->application->notice->getPrivateTemplates(); + } catch (\Exception $e) { + throw new ValidateException($this->getMessage($e->getMessage())); + } + } + + /** + * 获得添加模版ID + * @param $template_id_short + */ + public function addTemplateId($template_id_short) + { + try { + return $this->application->notice->addTemplate($template_id_short); + } catch (\Exception $e) { + throw new ValidateException($this->getMessage($e->getMessage())); + } + } + + /* + * 根据模版ID删除模版 + */ + public function deleleTemplate($template_id) + { + try { + return $this->application->notice->deletePrivateTemplate($template_id); + } catch (\Exception $e) { + throw new ValidateException($this->getMessage($e->getMessage())); + } + + } + + /** + * 处理返回错误信息友好提示 + * @param string $message + * @return array|mixed|string + */ + public function getMessage(string $message) + { + if (strstr($message, 'Request AccessToken fail') !== false) { + $message = str_replace('Request AccessToken fail. response:', '', $message); + $message = json_decode($message, true) ?: []; + $errcode = $message['errcode'] ?? false; + if ($errcode) { + $message = ApiErrorCode::ERROR_WECHAT_MESSAGE[$errcode] ?? $message; + } + } + return $message; + } + +} diff --git a/crmeb/services/WechatService.php.bak b/crmeb/services/WechatService.php.bak new file mode 100644 index 00000000..1f401463 --- /dev/null +++ b/crmeb/services/WechatService.php.bak @@ -0,0 +1,1044 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\product\ProductAssistSetRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupRepository; +use app\common\repositories\store\product\ProductPresellRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\wechat\WechatQrcodeRepository; +use app\common\repositories\wechat\WechatReplyRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\exceptions\WechatException; +use crmeb\utils\ApiErrorCode; +use EasyWeChat\Core\Exceptions\FaultException; +use EasyWeChat\Core\Exceptions\InvalidArgumentException; +use EasyWeChat\Core\Exceptions\RuntimeException; +use EasyWeChat\Foundation\Application; +use EasyWeChat\Message\Article; +use EasyWeChat\Message\Image; +use EasyWeChat\Message\Material; +use EasyWeChat\Message\News; +use EasyWeChat\Message\Text; +use EasyWeChat\Message\Video; +use EasyWeChat\Message\Voice; +use EasyWeChat\Payment\Order; +use EasyWeChat\Server\BadRequestException; +use EasyWeChat\Support\Collection; +use Exception; +use Symfony\Component\HttpFoundation\Request; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Event; +use think\facade\Log; +use think\facade\Route; +use think\Response; + +/** + * Class WechatService + * @package crmeb\services + * @author xaboy + * @day 2020-04-20 + */ +class WechatService +{ + /** + * @var Application + */ + protected $application; + + protected $config; + + /** + * WechatService constructor. + * @param $config + */ + public function __construct(array $config) + { + $this->config = $config; + $this->application = new Application($config); + $this->application->register(new \crmeb\services\easywechat\certficates\ServiceProvider()); + $this->application->register(new \crmeb\services\easywechat\merchant\ServiceProvider); + $this->application->register(new \crmeb\services\easywechat\combinePay\ServiceProvider); + $this->application->register(new \crmeb\services\easywechat\pay\ServiceProvider); + $this->application->register(new \crmeb\services\easywechat\batches\ServiceProvider); + } + + /** + * @return array + * @author xaboy + * @day 2020-04-24 + */ + public static function getConfig($isApp) + { + /** @var ConfigValueRepository $make */ + $make = app()->make(ConfigValueRepository::class); + $wechat = $make->more([ + 'wechat_appid', 'wechat_appsecret', 'wechat_token', 'wechat_encodingaeskey', 'wechat_encode', 'wecaht_app_appid', 'wechat_app_appsecret' + ], 0); + + if ($isApp ?? request()->isApp()) { + $wechat['wechat_appid'] = trim($wechat['wecaht_app_appid']); + $wechat['wechat_appsecret'] = trim($wechat['wechat_app_appsecret']); + } + $payment = $make->more(['site_url', 'pay_weixin_mchid', 'pay_weixin_client_cert', 'pay_weixin_client_key', 'pay_weixin_key', 'pay_weixin_v3_key', 'pay_weixin_open','pay_wechat_serial_no_v3', 'wechat_service_merid', 'wechat_service_key', 'wechat_service_v3key', 'wechat_service_client_cert', 'wechat_service_client_key', 'wechat_service_serial_no'], 0); + $config = [ + 'app_id' => trim($wechat['wechat_appid']), + 'secret' => trim($wechat['wechat_appsecret']), + 'token' => trim($wechat['wechat_token']), + 'routine_appId' => systemConfig('routine_appId'), + 'guzzle' => [ + 'timeout' => 10.0, // 超时时间(秒) + 'verify' => false + ], + 'debug' => false, + ]; + if ($wechat['wechat_encode'] > 0 && $wechat['wechat_encodingaeskey']) + $config['aes_key'] = trim($wechat['wechat_encodingaeskey']); + $is_v3 = false; + if (isset($payment['pay_weixin_open']) && $payment['pay_weixin_open'] == 1) { + $config['payment'] = [ + 'merchant_id' => trim($payment['pay_weixin_mchid']), + 'key' => trim($payment['pay_weixin_key']), + 'apiv3_key' => trim($payment['pay_weixin_v3_key']), + 'serial_no' => trim($payment['pay_wechat_serial_no_v3']), + 'cert_path' => (app()->getRootPath() . 'public' . $payment['pay_weixin_client_cert']), + 'key_path' => (app()->getRootPath() . 'public' . $payment['pay_weixin_client_key']), + 'notify_url' => $payment['site_url'] . Route::buildUrl('wechatNotify')->build(), + 'pay_weixin_client_cert' => $payment['pay_weixin_client_cert'], + 'pay_weixin_client_key' => $payment['pay_weixin_client_key'], + ]; + if ($config['payment']['apiv3_key']) { + $is_v3 = true; + } + } + $config['is_v3'] = $is_v3; + $config['service_payment'] = [ + 'merchant_id' => trim($payment['wechat_service_merid']), + 'type' => 'wechat', + 'key' => trim($payment['wechat_service_key']), + 'cert_path' => (app()->getRootPath() . 'public' . $payment['wechat_service_client_cert']), + 'key_path' => (app()->getRootPath() . 'public' . $payment['wechat_service_client_key']), + 'pay_weixin_client_cert' => $payment['wechat_service_client_cert'], + 'pay_weixin_client_key' => $payment['wechat_service_client_key'], + 'serial_no' => trim($payment['wechat_service_serial_no']), + 'apiv3_key' => trim($payment['wechat_service_v3key']), + ]; + return $config; + } + + /** + * @return self + * @author xaboy + * @day 2020-04-24 + */ + public static function create($isApp = null) + { + return new self(self::getConfig($isApp)); + } + + public function isV3() + { + return $this->config['is_v3'] ?? false; + } + + public function v3Pay() + { + return $this->application->v3Pay; + } + + /** + * @return Application + * @author xaboy + * @day 2020-04-20 + */ + public function getApplication() + { + return $this->application; + } + + /** + * @param \think\Request $request + * @return Response + * @throws BadRequestException + * @throws InvalidArgumentException + * @author xaboy + * @day 2020-04-26 + */ + public function serve(\think\Request $request) + { + $this->serverRequest($request); + $this->wechatEventHook(); + return response($this->application->server->serve()->getContent()); + } + + protected function serverRequest(\think\Request $request) + { + $this->application->server->setRequest(new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent())); + } + + /** + * @throws InvalidArgumentException + * @author xaboy + * @day 2020-04-20 + */ + public function wechatEventHook() + { + $this->application->server->setMessageHandler(function ($message) { + $openId = $message->FromUserName; + $message->EventKey = str_replace('qrscene_', '', $message->EventKey); + $userInfo = $this->getUserInfo($openId); + /** @var WechatUserRepository $wechatUserRepository */ + $wechatUserRepository = app()->make(WechatUserRepository::class); + $users = $wechatUserRepository->syncUser($openId, $userInfo, true); + + $scanLogin = function () use ($message, $users) { + $ticket = $message->EventKey; + if (strpos($ticket, '_sys_scan_login.') === 0) { + $key = str_replace('_sys_scan_login.', '', $ticket); + if(Cache::has('_scan_login' . $key)){ + Cache::set('_scan_login' . $key, $users[1]['uid']); + } + } + }; + + $response = null; + /** @var WechatReplyRepository $make * */ + $make = app()->make(WechatReplyRepository::class); + event('wechat.message', compact('message')); + switch ($message->MsgType) { + case 'event': + event('wechat.event', compact('message')); + switch (strtolower($message->Event)) { + case 'subscribe': + $scanLogin(); + $response = $this->qrKeyByMessage($message->EventKey) ?: $make->reply('subscribe'); + if (isset($message->EventKey) && $message->EventKey) { + /** @var WechatQrcodeRepository $qr */ + $qr = app()->make(WechatQrcodeRepository::class); + if ($qrInfo = $qr->ticketByQrcode($message->Ticket)) { + $qrInfo->incTicket(); + if (strtolower($qrInfo['third_type']) == 'spread' && $users) { + $spreadUid = $qrInfo['third_id']; + if ($users[1]['uid'] == $spreadUid) + return '自己不能推荐自己'; + else if ($users[1]['spread_uid']) + return '已有推荐人!'; + try { + $users[1]->setSpread($spreadUid); + } catch (Exception $e) { + return '绑定推荐人失败'; + } + } + } + } + event('wechat.event.subscribe', compact('message')); + break; + case 'unsubscribe': + $wechatUserRepository->unsubscribe($openId); + event('wechat.event.unsubscribe', compact('message')); + break; + case 'scan': + $scanLogin(); + $response = $this->qrKeyByMessage($message->EventKey) ?: $make->reply('subscribe'); + /** @var WechatQrcodeRepository $qr */ + $qr = app()->make(WechatQrcodeRepository::class); + if ($message->EventKey && ($qrInfo = $qr->ticketByQrcode($message->Ticket))) { + $qrInfo->incTicket(); + if (strtolower($qrInfo['third_type']) == 'spread' && $users) { + $spreadUid = $qrInfo['third_id']; + if ($users[1]['uid'] == $spreadUid) + return '自己不能推荐自己'; + else if ($users[1]['spread_uid']) + return '已有推荐人!'; + try { + $users[1]->setSpread($spreadUid); + } catch (Exception $e) { + return '绑定推荐人失败'; + } + } + } + event('wechat.event.scan', compact('message')); + break; + case 'location': + event('wechat.event.location', compact('message')); + break; + case 'click': + $response = $make->reply($message->EventKey); + event('wechat.event.click', compact('message')); + break; + case 'view': + event('wechat.event.view', compact('message')); + break; + case 'funds_order_pay': + if (($count = strpos($message['order_info']['trade_no'], '_')) !== false) { + $trade_no = substr($message['order_info']['trade_no'], $count + 1); + } else { + $trade_no = $message['order_info']['trade_no']; + } + $prefix = substr($trade_no, 0, 3); + //处理一下参数 + switch ($prefix) { + case StoreOrderRepository::TYPE_SN_ORDER: + $attach = 'order'; + break; + case StoreOrderRepository::TYPE_SN_PRESELL: + $attach = 'presell'; + break; + case StoreOrderRepository::TYPE_SN_USER_ORDER: + $attach = 'user_order'; + break; + case StoreOrderRepository::TYPE_SN_USER_RECHARGE: + $attach = 'user_recharge'; + break; + } + event('pay_success_' . $attach, ['order_sn' => $message['order_info']['trade_no'], 'data' => $message, 'is_combine' => 0]); + break; + } + break; + case 'text': + if (preg_match('/^(\/@[1-9]{1}).*\*\//', $message->Content)) { + $command = app()->make(CopyCommand::class)->getMassage($message->Content); + if (empty($command)) { + $response = self::textMessage('无效口令'); + } else { + if ($command['type'] == 30) $command['type'] = 3; + $key = '_scan_url_' . $command['type'] . '_' . $command['id'] . '_' . $command['uid']; + $response = $this->qrKeyByMessage($key); + } + } else { + $response = $make->reply($message->Content); + } + event('wechat.message.text', compact('message')); + break; + case 'image': + event('wechat.message.image', compact('message')); + break; + case 'voice': + event('wechat.message.voice', compact('message')); + break; + case 'video': + event('wechat.message.video', compact('message')); + break; + case 'location': + event('wechat.message.location', compact('message')); + break; + case 'link': + event('wechat.message.link', compact('message')); + break; + // ... 其它消息 + default: + event('wechat.message.other', compact('message')); + break; + } + + return $response ?? false; + }); + } + + /** + * @param $value + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function qrcodeForever($value) + { + return $this->application->qrcode->forever($value); + } + + /** + * @param $value + * @param int $expireSeconds + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function qrcodeTemp($value, $expireSeconds = 2592000) + { + return $this->application->qrcode->temporary($value, $expireSeconds); + } + + /** + * @param string $openid + * @param string $templateId + * @param array $data + * @param null $url + * @param null $defaultColor + * @return mixed + * @author xaboy + * @day 2020-04-20 + */ + public function sendTemplate(string $openid, string $templateId, array $data, $url = null, $defaultColor = null, $miniprogram = []) + { + $notice = $this->application->notice->to($openid)->template($templateId)->andData($data); + if ($url !== null) $notice->url($url); + if ($defaultColor !== null) $notice->defaultColor($defaultColor); + return $notice->send($miniprogram); + } + + /** + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Order + * @author xaboy + * @day 2020-04-20 + */ + protected function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $total_fee = bcmul($total_fee, 100, 0); + $order = array_merge(compact('out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options); + if (!is_null($openid)) $order['openid'] = $openid; + if ($order['detail'] == '') unset($order['detail']); + $order['spbill_create_ip'] = \request()->ip(); + return new Order($order); + } + + /** + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $order = $this->paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options); + if ($this->isV3()) { + if ($trade_type == 'MWEB') $trade_type = 'H5'; + $payFunction = 'pay'.ucfirst($trade_type); + return $this->application->v3Pay->{$payFunction}($order); + } else { + $result = $this->application->payment->prepare($order); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result; + } else { + if ($result->return_code == 'FAIL') { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new WechatException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new WechatException('没有获取微信支付的预支付ID,请重新发起支付!'); + } + } + } + } + + /** + * @param $openid + * @param $out_trade_no + * @param $total_fee + * @param $attach + * @param $body + * @param string $detail + * @param string $trade_type + * @param array $options + * @return array|string + * @author xaboy + * @day 2020-04-20 + */ + public function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = []) + { + $paymentPrepare = $this->paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options); + if ($this->isV3()) { + return $paymentPrepare; + } + return $trade_type === 'APP' + ? $this->application->payment->configForAppPayment($paymentPrepare->prepay_id) + : $this->application->payment->configForJSSDKPayment($paymentPrepare->prepay_id); + } + + /** + * @param $orderNo + * @param $refundNo + * @param $totalFee + * @param null $refundFee + * @param null $opUserId + * @param string $refundReason + * @param string $type + * @param string $refundAccount + * @return Collection + * @author xaboy + * @day 2020-04-20 + */ + public function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '', $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS') + { + if (empty($this->config['payment']['pay_weixin_client_cert']) || empty($this->config['payment']['pay_weixin_client_key'])) { + throw new \Exception('请配置微信支付证书'); + } + $totalFee = floatval($totalFee); + $refundFee = floatval($refundFee); + if ($this->isV3()) { + return $this->application->v3Pay->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason); + } else { + return $this->application->payment->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason); + } + } + + /** + * @param $orderNo + * @param array $opt + * @author xaboy + * @day 2020-04-20 + */ + public function payOrderRefund($orderNo, array $opt) + { + if (!isset($opt['pay_price'])) throw new WechatException('缺少pay_price'); + $totalFee = floatval(bcmul($opt['pay_price'], 100, 0)); + $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'], 100, 0)) : null; + $refundReason = isset($opt['refund_message']) ? $opt['refund_message'] : '无'; + $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo; + $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null; + $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no'; + + //若传递此参数则使用对应的资金账户退款,否则默认使用未结算资金退款(仅对老资金流商户适用) + $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS'; + try { + $res = ($this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount)); + if (isset($res->return_code) && $res->return_code== 'FAIL') + throw new WechatException('退款失败:' . $res->return_msg); + if (isset($res->err_code)) + throw new WechatException('退款失败:' . $res->err_code_des); + } catch (Exception $e) { + throw new WechatException($e->getMessage()); + } + } + + /** + * array ( + * 'appid' => '****', + * 'attach' => 'user_recharge', + * 'bank_type' => 'COMM_CREDIT', + * 'cash_fee' => '1', + * 'fee_type' => 'CNY', + * 'is_subscribe' => 'Y', + * 'mch_id' => ''*****'', + * 'nonce_str' => '5ee9dac1bc302', + * 'openid' => '*****', + * 'out_trade_no' => ''*****'', + * 'result_code' => 'SUCCESS', + * 'return_code' => 'SUCCESS', + * 'sign' => '51'*****'', + * 'time_end' => '20200617165651', + * 'total_fee' => '1', + * 'trade_type' => 'JSAPI', + * 'transaction_id' => ''*****'', + * ) + * + * @throws FaultException + * @author xaboy + * @day 2020-04-20 + */ + public function handleNotify() + { + $this->application->payment = new PaymentService($this->application->merchant); + //TODO 微信支付 + return $this->application->payment->handleNotify(function ($notify, $successful) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $notify['attach'], ['order_sn' => $notify['out_trade_no'], 'data' => $notify, 'is_combine' => 0]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + public function handleNotifyV3() + { + return $this->application->v3Pay->handleNotify(function ($notify, $successful) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $notify['attach'], ['order_sn' => $notify['out_trade_no'], 'data' => $notify, 'is_combine' => 0]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + public function handleCombinePayNotify($type) + { + return $this->application->combinePay->handleNotify(function ($notify, $successful) use ($type) { + Log::info('微信支付成功回调' . var_export($notify, 1)); + if (!$successful) return false; + try { + event('pay_success_' . $type, ['order_sn' => $notify['combine_out_trade_no'], 'data' => $notify, 'is_combine' => 1]); + } catch (\Exception $e) { + Log::info('微信支付回调失败:' . $e->getMessage()); + return false; + } + return true; + }); + } + + /** + * @param string $url + * @return array|string + * @author xaboy + * @day 2020-04-20 + */ + public function jsSdk($url) + { + $apiList = ['editAddress', 'openAddress', 'updateTimelineShareData', 'updateAppMessageShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'onVoicePlayEnd', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'translateVoice', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard']; + $jsService = $this->application->js; + $jsService->setUrl($url); + try { + return $jsService->config($apiList, false, false, false); + } catch (Exception $e) { + Log::info('微信参数获取失败' . $e->getMessage()); + return []; + } + + } + + /** + * 回复文本消息 + * @param string $content 文本内容 + * @return Text + * @author xaboy + * @day 2020-04-20 + */ + public static function textMessage($content) + { + return new Text(compact('content')); + } + + /** + * 回复图片消息 + * @param string $media_id 媒体资源 ID + * @return Image + * @author xaboy + * @day 2020-04-20 + */ + public static function imageMessage($media_id) + { + return new Image(compact('media_id')); + } + + /** + * 回复视频消息 + * @param string $media_id 媒体资源 ID + * @param string $title 标题 + * @param string $description 描述 + * @param null $thumb_media_id 封面资源 ID + * @return Video + * @author xaboy + * @day 2020-04-20 + */ + public static function videoMessage($media_id, $title = '', $description = '...', $thumb_media_id = null) + { + return new Video(compact('media_id', 'title', 'description', 'thumb_media_id')); + } + + /** + * 回复声音消息 + * @param string $media_id 媒体资源 ID + * @return Voice + * @author xaboy + * @day 2020-04-20 + */ + public static function voiceMessage($media_id) + { + return new Voice(compact('media_id')); + } + + /** + * 回复图文消息 + * @param string|array $title 标题 + * @param string $description 描述 + * @param string $url URL + * @param string $image 图片链接 + * @return News|array + * @author xaboy + * @day 2020-04-20 + */ + public static function newsMessage($title, $description = '...', $url = '', $image = '') + { + if (is_array($title)) { + if (isset($title[0]) && is_array($title[0])) { + $newsList = []; + foreach ($title as $news) { + $newsList[] = self::newsMessage($news); + } + return $newsList; + } else { + $data = $title; + } + } else { + $data = compact('title', 'description', 'url', 'image'); + } + return new News($data); + } + + /** + * 回复文章消息 + * @param string|array $title 标题 + * @param string $thumb_media_id 图文消息的封面图片素材id(必须是永久 media_ID) + * @param string $source_url 图文消息的原文地址,即点击“阅读原文”后的URL + * @param string $content 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS + * @param string $author 作者 + * @param string $digest 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空 + * @param int $show_cover_pic 是否显示封面,0为false,即不显示,1为true,即显示 + * @param int $need_open_comment 是否打开评论,0不打开,1打开 + * @param int $only_fans_can_comment 是否粉丝才可评论,0所有人可评论,1粉丝才可评论 + * @return Article + * @author xaboy + * @day 2020-04-20 + */ + public static function articleMessage($title, $thumb_media_id, $source_url, $content = '', $author = '', $digest = '', $show_cover_pic = 0, $need_open_comment = 0, $only_fans_can_comment = 1) + { + $data = is_array($title) ? $title : compact('title', 'thumb_media_id', 'source_url', 'content', 'author', 'digest', 'show_cover_pic', 'need_open_comment', 'only_fans_can_comment'); + return new Article($data); + } + + /** + * 回复素材消息 + * @param string $type [mpnews、 mpvideo、voice、image] + * @param string $media_id 素材 ID + * @return Material + * @author xaboy + * @day 2020-04-20 + */ + public static function materialMessage($type, $media_id) + { + return new Material($type, $media_id); + } + + /** + * @param $to + * @param $message + * @return bool + * @throws InvalidArgumentException + * @throws RuntimeException + * @author xaboy + * @day 2020-04-20 + */ + public function staffTo($to, $message) + { + $staff = $this->application->staff; + $staff = is_callable($message) ? $staff->message($message()) : $staff->message($message); + $res = $staff->to($to)->send(); + return $res; + } + + /** + * @param $openid + * @return array + * @author xaboy + * @day 2020-04-20 + */ + public function getUserInfo($openid) + { + $userService = $this->application->user; + $userInfo = is_array($openid) ? $userService->batchGet($openid) : $userService->get($openid); + return $userInfo->toArray(); + } + + + /** + * 模板消息接口 + * @return \EasyWeChat\Notice\Notice + */ + public function noticeService() + { + return $this->application->notice; + } + + + /** + * 微信二维码生成接口 + * @return \EasyWeChat\QRCode\QRCode + */ + public function qrcodeService() + { + return $this->application->qrcode; + } + + public function storePay() + { + return $this->application->storePay; + } + + /** + * TODO V3的商家到零钱 + * @author Qinii + * @day 2023/3/13 + */ + public function companyPay($data) + { + $transfer_detail_list[] = [ + 'out_detail_no' => $data['sn'], + 'transfer_amount' => $data['price'] * 100, + 'transfer_remark' => $data['mark'] ?? '', + //openid是微信用户在公众号appid下的唯一用户标识 + 'openid' => $data['openid'], + ]; + //商家到零钱 + $ret = [ + //商户系统内部的商家批次单号 + 'out_batch_no' => $data['sn'], + //该笔批量转账的名称 + 'batch_name' => $data['batch_name'], + //转账说明,UTF8编码,最多允许32个字符 + 'batch_remark' => $data['mark'] ?? '', + //转账金额单位为“分” + 'total_amount' => $data['price'] * 100, + //转账总笔数一个转账批次单最多发起三千笔转账 + 'total_num' => 1, + //该批次转账使用的转账场景,可在「商家转账到零钱 - 产品设置」中查看详情,如不填写则使用商家的默认转账场景 + 'transfer_detail_list' => $transfer_detail_list, + ]; + $result = $this->application->batches->send($ret); + return $result; + } + + /** + * TODO V2的企业到零钱 + * @param $data + * @return mixed + * @author Qinii + * @day 2023/3/13 + */ + public function merchantPay($data) + { + $ret = [ + 'partner_trade_no' => $data['sn'], //随机字符串作为订单号,跟红包和支付一个概念。 + 'openid' => $data['openid'], //收款人的openid + 'check_name' => 'NO_CHECK', //文档中有三种校验实名的方法 NO_CHECK OPTION_CHECK FORCE_CHECK + //'re_user_name'=>'张三', //OPTION_CHECK FORCE_CHECK 校验实名的时候必须提交 + 'amount' => $data['price'] * 100, //单位为分 + 'desc' => $data['mark'] ?? '', + 'spbill_create_ip' => request()->ip(), //发起交易的IP地址 + ]; + $result = $this->application->merchant_pay->send($ret); + if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') { + return $result; + } else { + if ($result->return_code == 'FAIL') { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } else if (isset($result->err_code)) { + throw new WechatException('微信支付错误返回:' . $result->err_code_des); + } else { + throw new WechatException('微信支付错误返回:' . $result->return_msg); + } + } + } + + /** + * TODO 分账商户 + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function applyments() + { + return $this->application->sub_merchant; + } + + + /** + * TODO 上传图片 + * @param array $filed + * @return mixed + * @author Qinii + * @day 6/21/21 + */ + public function uploadImages(array $filed) + { + if (empty($filed)) throw new InvalidArgumentException('图片为空'); + foreach ($filed as $file) { + $item = $this->application->sub_merchant->upload($file['path'], $file['name']); + $data[] = [ + 'dir' => $file['dir'], + 'media_id' => $item['media_id'], + ]; + } + return $data; + } + + public function qrKeyByMessage($key) + { + if (strpos($key, '_scan_url_') === 0) { + $key = str_replace('_scan_url_', '', $key); + $data = explode('_', $key); + $siteUrl = rtrim(systemConfig('site_url'), '/'); + $make = app()->make(ProductRepository::class); + if ($data[0] === 'home') { + $share = systemConfig(['share_title', 'share_info', 'share_pic']); + $share['url'] = $siteUrl . '?spid=' . $data[1]; + } else if ($data[0] === 'mer') { + $ret = app()->make(MerchantRepository::class)->get($data[1]); + if (!$ret) return; + $share = [ + 'share_title' => $ret['mer_name'], + 'share_info' => $ret['mer_info'], + 'share_pic' => $ret['mer_avatar'], + 'url' => $siteUrl . '/pages/store/home/index?id=' . $data[1], + ]; + } else if ($data[0] === 'p0') { + $ret = $make->get($data[1]); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $ret['image'], + 'url' => $siteUrl . '/pages/goods_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p1') { + $ret = $make->get($data[1]); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $ret['image'], + 'url' => $siteUrl . '/pages/activity/goods_seckill_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p2') { + $ret = app()->make(ProductPresellRepository::class)->search(['product_presell_id' => $data[1]])->find(); + $res = $make->get($ret['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $res['image'], + 'url' => $siteUrl . '/pages/activity/presell_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p3') { + $ret = app()->make(ProductAssistSetRepository::class)->getSearch(['product_assist_set_id' => $data[1]])->find(); + $res = $make->get($ret['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $res['store_name'], + 'share_info' => $res['store_info'], + 'share_pic' => $res['image'], + 'url' => $siteUrl . '/pages/activity/assist_detail/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p4') { + $ret = app()->make(ProductGroupRepository::class)->get($data[1]); + $res = $make->get($ret['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $res['store_name'], + 'share_info' => $res['store_info'], + 'share_pic' => $res['image'], + 'url' => $siteUrl . '/pages/activity/combination_details/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else if ($data[0] === 'p40') { + $res = app()->make(ProductGroupBuyingRepository::class)->getSearch(['group_buying_id' => $data[1]])->find(); + $ret = $make->get($res->productGroup['product_id']); + if (!$ret) return; + $share = [ + 'share_title' => $ret['store_name'], + 'share_info' => $ret['store_info'], + 'share_pic' => $ret['image'], + 'url' => $siteUrl . '/pages/activity/combination_status/index?id=' . $data[1] . '&spid=' . ($data[2] ?? 0), + ]; + } else { + return; + } + return self::newsMessage($share['share_title'], $share['share_info'], $share['url'], $share['share_pic']); + } + } + + + /** + * @return easywechat\combinePay\Client + */ + public function combinePay() + { + return $this->application->combinePay; + } + + + + /** + * 获取模板列表 + * @return \EasyWeChat\Support\Collection + */ + public function getPrivateTemplates() + { + try { + return $this->application->notice->getPrivateTemplates(); + } catch (\Exception $e) { + throw new ValidateException($this->getMessage($e->getMessage())); + } + } + + /** + * 获得添加模版ID + * @param $template_id_short + */ + public function addTemplateId($template_id_short) + { + try { + return $this->application->notice->addTemplate($template_id_short); + } catch (\Exception $e) { + throw new ValidateException($this->getMessage($e->getMessage())); + } + } + + /* + * 根据模版ID删除模版 + */ + public function deleleTemplate($template_id) + { + try { + return $this->application->notice->deletePrivateTemplate($template_id); + } catch (\Exception $e) { + throw new ValidateException($this->getMessage($e->getMessage())); + } + + } + + /** + * 处理返回错误信息友好提示 + * @param string $message + * @return array|mixed|string + */ + public function getMessage(string $message) + { + if (strstr($message, 'Request AccessToken fail') !== false) { + $message = str_replace('Request AccessToken fail. response:', '', $message); + $message = json_decode($message, true) ?: []; + $errcode = $message['errcode'] ?? false; + if ($errcode) { + $message = ApiErrorCode::ERROR_WECHAT_MESSAGE[$errcode] ?? $message; + } + } + return $message; + } + +} diff --git a/crmeb/services/WechatTemplateMessageService.php b/crmeb/services/WechatTemplateMessageService.php new file mode 100644 index 00000000..80c03412 --- /dev/null +++ b/crmeb/services/WechatTemplateMessageService.php @@ -0,0 +1,759 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreOrderStatusRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\product\ProductGroupBuyingRepository; +use app\common\repositories\store\product\ProductGroupUserRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\ProductTakeRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use app\common\repositories\user\UserBillRepository; +use app\common\repositories\user\UserExtractRepository; +use app\common\repositories\user\UserRechargeRepository; +use app\common\repositories\wechat\WechatUserRepository; +use crmeb\listens\pay\UserRechargeSuccessListen; +use crmeb\services\template\Template; +use app\common\repositories\user\UserRepository; +use think\facade\Log; +use think\facade\Route; + +class WechatTemplateMessageService +{ + /** + * TODO + * @param array $data + * @param string|null $link + * @param string|null $color + * @return bool + * @author Qinii + * @day 2020-06-29 + */ + public function sendTemplate(array $data) + { + event('wechat.template.before',compact('data')); + $res = $this->templateMessage($data); + if(!$res || !is_array($res)) + return true; + foreach($res as $item){ + if(is_array($item['uid'])){ + foreach ($item['uid'] as $value){ + $openid = $this->getUserOpenID($value['uid']); + if (!$openid) continue; + $this->send($openid,$item['tempCode'],$item['data'],'wechat',$item['link'],$item['color']); + } + }else{ + $openid = $this->getUserOpenID($item['uid']); + if (!$openid) continue; + $this->send($openid,$item['tempCode'],$item['data'],'wechat',$item['link'],$item['color']); + } + } + event('wechat.template',compact('res')); + } + + /** + * TODO + * @param $data + * @param string|null $link + * @param string|null $color + * @return bool + * @author Qinii + * @day 2020-07-01 + */ + public function subscribeSendTemplate($data) + { + event('wechat.subscribeTemplate.before',compact('data')); + $res = $this->subscribeTemplateMessage($data); + Log::info('订阅消息发送Data' . var_export($data, 1)); + if(!$res || !is_array($res))return true; + + foreach($res as $item){ + if(is_array($item['uid'])){ + foreach ($item['uid'] as $value){ + $openid = $this->getUserOpenID($value,'min'); + if (!$openid) { + continue; + } + $this->send($openid,$item['tempCode'],$item['data'],'subscribe',$item['link'],$item['color']); + } + }else{ + $openid = $this->getUserOpenID($item['uid'],'min'); + if (!$openid) { + continue; + } + $this->send($openid,$item['tempCode'],$item['data'],'subscribe',$item['link'],$item['color']); + } + } + event('wechat.subscribeTemplate',compact('res')); + } + + /** + * TODO + * @param $uid + * @return mixed + * @author Qinii + * @day 2020-06-29 + */ + public function getUserOpenID($uid,$type = 'wechat') + { + $user = app()->make(UserRepository::class)->get($uid); + if (!$user) return null; + $make = app()->make(WechatUserRepository::class); + if($type == 'wechat') { + return $make->idByOpenId((int)$user['wechat_user_id']); + }else{ + return $make->idByRoutineId((int)$user['wechat_user_id']); + } + } + + + /** + * TODO + * @param $openid + * @param $tempCode + * @param $data + * @param $type + * @param $link + * @param $color + * @return bool|mixed + * @author Qinii + * @day 2020-07-01 + */ + public function send($openid,$tempCode,$data,$type,$link,$color) + { + $template = new Template($type); + $template->to($openid)->color($color); + if ($link) $template->url($link); + return $template->send($tempCode, $data); + } + + /** + * TODO 公众号 + * @param string $tempCode + * @param $id + * @return array|bool + * @author Qinii + * @day 2020-07-01 + */ + public function templateMessage($params) + { + $data = []; + $id = $params['id']; + $tempId = $params['tempId']; + $params = $params['params'] ?? []; + $bill_make = app()->make(UserBillRepository::class); + $order_make = app()->make(StoreOrderRepository::class); + $refund_make = app()->make(StoreRefundOrderRepository::class); + $stie_url = rtrim(systemConfig('site_url'), '/'); + switch ($tempId) + { + //订单生成通知 2.1 + case 'ORDER_CREATE': + /* + {{first.DATA}} + 时间:{{keyword1.DATA}} + 商品名称:{{keyword2.DATA}} + 订单号:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = $order_make->selectWhere(['group_order_id' => $id]); + if(!$res) return false; + foreach ($res as $item){ + $order = $order_make->getWith($item['order_id'],'orderProduct'); + $data[] = [ + 'tempCode' => 'ORDER_CREATE', + 'uid' => app()->make(StoreServiceRepository::class)->getNoticeServiceInfo($item->mer_id), + 'data' => [ + 'first' => '您有新的生成订单请注意查看', + 'keyword1' => $item->create_time, + 'keyword2' => '「' . $order['orderProduct'][0]['cart_info']['product']['store_name'] . '」等', + 'keyword3' => $item->order_sn, + 'remark' => '查看详情' + ], + 'link' => $stie_url. '/pages/admin/orderList/index?types=1&merId=' . $item->mer_id, + 'color' => null + ]; + } + break; + //支付成功 2.1 + case 'ORDER_PAY_SUCCESS': + /* + {{first.DATA}} + 订单商品:{{keyword1.DATA}} + 订单编号:{{keyword2.DATA}} + 支付金额:{{keyword3.DATA}} + 支付时间:{{keyword4.DATA}} + {{remark.DATA}} + */ + $group_order = app()->make(StoreGroupOrderRepository::class)->get($id); + if(!$group_order) return false; + $data[] = [ + 'tempCode' => 'ORDER_PAY_SUCCESS', + 'uid' => $group_order->uid, + 'data' => [ + 'first' => '您的订单已支付', + 'keyword1' => $group_order->orderList[0]->orderProduct[0]['cart_info']['product']['store_name'], + 'keyword2' => $group_order->group_order_sn, + 'keyword3' => $group_order->pay_price, + 'keyword4' => $group_order->pay_time, + 'remark' => '我们会尽快发货,请耐心等待' + ], + 'link' => $stie_url . '/pages/users/order_list/index?status=1', + 'color' => null + ]; + break; + //管理员支付成功提醒 2.1 + case 'ADMIN_PAY_SUCCESS_CODE': + /* + {{first.DATA}} + 订单商品:{{keyword1.DATA}} + 订单编号:{{keyword2.DATA}} + 支付金额:{{keyword3.DATA}} + 支付时间:{{keyword4.DATA}} + {{remark.DATA}} + */ + $res = $order_make->selectWhere(['group_order_id' => $id]); + if (!$res) return false; + foreach ($res as $item) { + $data[] = [ + 'tempCode' => 'ADMIN_PAY_SUCCESS_CODE', + 'uid' => app()->make(StoreServiceRepository::class)->getNoticeServiceInfo($item->mer_id), + 'data' => [ + 'first' => '您有新的支付订单请注意查看。', + 'keyword1' => mb_substr($item->orderProduct[0]->cart_info['product']['store_name'],0,15), + 'keyword2' => $item->order_sn, + 'keyword3' => $item->pay_price, + 'keyword4' => $item->pay_time, + 'remark' => '请尽快发货。' + ], + 'link' => $stie_url . '/pages/admin/orderList/index?types=2&merId=' . $item->mer_id, + 'color' => null + ]; + } + break; + //订单发货提醒 2.1 + case 'DELIVER_GOODS_CODE': + /* + {{first.DATA}} + 订单编号:{{keyword1.DATA}} + 物流公司:{{keyword2.DATA}} + 物流单号:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = $order_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'DELIVER_GOODS_CODE', + 'uid' => $res->uid , + 'data' => [ + 'first' => '亲,宝贝已经启程了,好想快点来到你身边', + 'keyword1' => $res['order_sn'], + 'keyword2' => $res['delivery_name'], + 'keyword3' => $res['delivery_id'], + 'remark' => '请耐心等待收货哦。' + ], + 'link' => $stie_url .'/pages/order_details/index?order_id='.$id, + 'color' => null + ]; + break; + //订单配送提醒 2.1 + case 'ORDER_DELIVER_SUCCESS': + /* + {{first.DATA}} + 订单编号:{{keyword1.DATA}} + 订单金额:{{keyword2.DATA}} + 配送员:{{keyword3.DATA}} + 联系电话:{{keyword4.DATA}} + {{remark.DATA}} + */ + $res = $order_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'ORDER_DELIVER_SUCCESS', + 'uid' => $res->uid , + 'data' => [ + 'first' => '亲,宝贝已经启程了,好想快点来到你身边', + 'keyword1' => $res['order_sn'], + 'keyword2' => $res['pay_prices'], + 'keyword3' => $res['delivery_name'], + 'keyword4' => $res['delivery_id'], + 'remark' => '请耐心等待收货哦。' + ], + 'link' => $stie_url .'/pages/order_details/index?order_id='.$id, + 'color' => null + ]; + break; + //确认收货提醒 2.1 + case 'ORDER_TAKE_SUCCESS': + /* + {{first.DATA}} + 订单编号:{{keyword1.DATA}} + 订单金额:{{keyword2.DATA}} + 收货时间:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = $order_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'ORDER_TAKE_SUCCESS', + 'uid' => $res->uid, + 'data' => [ + 'first' => '亲,宝贝已经签收', + 'keyword1' => $res['order_sn'], + 'keyword2' => $res['pay_price'], + 'keyword3' => $res['orderStatus'][0]['change_time'], + 'remark' => '请确认。' + ], + 'link' => $stie_url .'/pages/order_details/index?order_id='.$id, + 'color' => null + ]; + break; + case 'ADMIN_TAKE_DELIVERY_CODE': + /* + {{first.DATA}} + 订单编号:{{keyword1.DATA}} + 订单金额:{{keyword2.DATA}} + 收货时间:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = $order_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'ORDER_TAKE_SUCCESS', + 'uid' => app()->make(StoreServiceRepository::class)->getNoticeServiceInfo($res->mer_id), + 'data' => [ + 'first' => '亲,宝贝已经签收', + 'keyword1' => $res['order_sn'], + 'keyword2' => $res['pay_price'], + 'keyword3' => $res['orderStatus'][0]['change_time'], + 'remark' => '商品:【'.mb_substr($res['orderProduct'][0]['product']['store_name'],0,15). '】等' + ], + 'link' => $stie_url .'/pages/order_details/index?order_id='.$id, + 'color' => null + ]; + break; + //退款申请通知 2.1 + case 'ADMIN_RETURN_GOODS_CODE': + /* + {{first.DATA}} + 退款单号:{{keyword1.DATA}} + 退款原因:{{keyword2.DATA}} + 退款金额:{{keyword3.DATA}} + 申请时间:{{keyword4.DATA}} + {{remark.DATA}} + */ + $res = $refund_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'ADMIN_RETURN_GOODS_CODE', + 'uid' => app()->make(StoreServiceRepository::class)->getNoticeServiceInfo($res->mer_id), + 'data' => [ + 'first' => '您有新的退款申请', + 'keyword1' => $res['refund_order_sn'], + 'keyword2' => $res['refund_message'], + 'keyword3' => $res['refund_price'], + 'keyword4' => $res['create_time'], + 'remark' => '请及时处理' + ], + 'link' => null, + 'color' => null + ]; + break; + //商户同意退款 2.1 + case 'REFUND_SUCCESS_CODE': + /* + {{first.DATA}} + 退款申请单号:{{keyword1.DATA}} + 退款进度:{{keyword2.DATA}} + 时间:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = $refund_make->get($id); + if(!$res || $res['status'] != 1) return false; + $data[] = [ + 'tempCode' => 'REFUND_SUCCESS_CODE', + 'uid' => $res->uid, + 'data' => [ + 'first' => '退款进度提醒', + 'keyword1' => $res['refund_order_sn'], + 'keyword2' => '商家已同意退货,请尽快将商品退回,并填写快递单号', + 'keyword3' => $res->status_time, + 'remark' => '' + ], + 'link' => $stie_url .'/pages/users/refund/detail?id='.$id, + 'color' => null + ]; + break; + //商户拒绝退款 2.1 + case 'REFUND_FAIL_CODE': + /* + {{first.DATA}} + 退款申请单号:{{keyword1.DATA}} + 退款进度:{{keyword2.DATA}} + 时间:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = $refund_make->get($id); + if(!$res || $res['status'] != -1) return false; + $data[] = [ + 'tempCode' => 'REFUND_FAIL_CODE', + 'uid' => $res->uid, + 'data' => [ + 'first' => '退款进度提醒', + 'keyword1' => $res['refund_order_sn'], + 'keyword2' => '商家已拒绝退款,如有疑问请联系商户', + 'keyword3' => $res->status_time, + 'remark' => '' + ], + 'link' => $stie_url.'/pages/users/refund/detail?id='.$id, + 'color' => null + ]; + break; + //退款成功通知 2.1 + case 'REFUND_CONFORM_CODE': + /* + {{first.DATA}} + 订单号:{{keyword1.DATA}} + 下单日期:{{keyword2.DATA}} + 商品名称:{{keyword3.DATA}} + 退款金额:{{keyword4.DATA}} + 退货原因:{{keyword5.DATA}} + {{remark.DATA}} + */ + $res = $refund_make->get($id); + if(!$res || $res['status'] != 3) return false; + $data[] = [ + 'tempCode' => 'REFUND_CONFORM_CODE', + 'uid' => $res->uid, + 'data' => [ + 'first' => '亲,您有一个订单已退款', + 'keyword1' => $res['refund_order_sn'], + 'keyword2' => $res['order']['create_time'], + 'keyword3' => '「'.mb_substr($res['refundProduct'][0]['product']['cart_info']['product']['store_name'],0,15).'」等', + 'keyword4' => $res['refund_price'], + 'keyword5' => $res['refund_message'], + 'remark' => '请查看详情' + ], + 'link' => $stie_url.'/pages/users/refund/detail?id='.$id, + 'color' => null + ]; + break; + //到货通知 2.1 + case 'PRODUCT_INCREASE': + /* + {{first.DATA}} + 商品名称:{{keyword1.DATA}} + 到货地点:{{keyword2.DATA}} + 到货时间:{{keyword3.DATA}} + {{remark.DATA} + */ + $make = app()->make(ProductTakeRepository::class); + $product = app()->make(ProductRepository::class)->getWhere(['product_id' => $id],'*',['attrValue']); + if(!$product) return false; + $unique[] = 1; + foreach ($product['attrValue'] as $item) { + if($item['stock'] > 0){ + $unique[] = $item['unique']; + } + } + $res = $make->getSearch(['product_id' => $id,'status' =>0,'type' => 2])->where('unique','in',$unique)->column('uid,product_id,product_take_id'); + $uids = array_unique(array_column($res,'uid')); + if (!$uids) return false; + $takeId = array_column($res,'product_take_id'); + foreach ($uids as $uid) { + $data[] = [ + 'tempCode' => 'PRODUCT_INCREASE', + 'uid' => $uid, + 'data' => [ + 'first' => '亲,你想要的商品已到货,可以购买啦~', + 'keyword1' => '「'.$product->store_name.'」', + 'keyword2' => $product->merchant->mer_name, + 'keyword3' => date('Y-m-d H:i:s',time()), + 'remark' => '到货商品:【'.mb_substr($product['store_name'],0,15).'】等,点击查看' + ], + 'link' => $stie_url.'/pages/goods_details/index?id='.$id, + 'color' => null + ]; + } + $make->updates($takeId,['status' => 1]); + break; + //余额变动 2.1 + case 'USER_BALANCE_CHANGE': + /* + {{first.DATA}} + 用户名:{{keyword1.DATA}} + 变动时间:{{keyword2.DATA}} + 变动金额:{{keyword3.DATA}} + 可用余额:{{keyword4.DATA}} + 变动原因:{{keyword5.DATA}} + {{remark.DATA}} + */ + $res = $bill_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'USER_BALANCE_CHANGE', + 'uid' => $res->uid, + 'data' => [ + 'first' => '资金变动提醒', + 'keyword1' => $res->user->nickname, + 'keyword2' => $res['create_time'], + 'keyword3' => $res['number'], + 'keyword4' => $res['balance'], + 'keyword5' => $res['title'], + 'remark' => '请确认' + ], + 'link' => $stie_url.'/pages/users/user_money/index', + 'color' => null + ]; + break; + //拼团成功 2.1 + case 'GROUP_BUYING_SUCCESS': + /* + {{first.DATA}} + 订单编号:{{keyword1.DATA}} + 订单信息:{{keyword2.DATA}} + 注意信息:{{keyword3.DATA}} + {{remark.DATA}} + */ + $res = app()->make(ProductGroupBuyingRepository::class)->get($id); + if(!$res) return false; + $ret = app()->make(ProductGroupUserRepository::class)->getSearch(['group_buying_id' => $id])->where('uid','>',0)->select(); + foreach ($ret as $item){ + $data[] = [ + 'tempCode' => 'GROUP_BUYING_SUCCESS', + 'uid' => $item->uid, + 'data' => [ + 'first' => '恭喜您拼团成功!', + 'keyword1' => $item->orderInfo['order_sn'], + 'keyword2' => '「'.mb_substr($res->productGroup->product['store_name'],0,15).'」', + 'keyword3' => '无', + 'remark' => '' + ], + 'link' => $stie_url.'/pages/order_details/index?order_id='.$item['order_id'], + 'color' => null + ]; + } + break; + //客服消息 2.1 + case'SERVER_NOTICE': + /* + {{first.DATA}} + 回复时间:{{keyword1.DATA}} + 回复内容:{{keyword2.DATA}} + {{remark.DATA}} + */ + $first = '【平台】'; + if ($params['mer_id']) { + $mer = app()->make(MerchantRepository::class)->get($params['mer_id']); + $first = '【' . $mer['mer_name'] . '】'; + } + $data[] = [ + 'tempCode' => 'SERVER_NOTICE', + 'uid' => $id, + 'data' => [ + 'first' => $first .'亲,您有新的消息请注意查看~', + 'keyword1' => $params['keyword1'], + 'keyword2' => $params['keyword2'], + 'remark' => '' + ], + 'link' => $stie_url.$params['url'], + 'color' => null + ]; + break; + default: + break; + } + return $data; + } + + /** + * TODO 小程序模板 + * @param string $tempCode + * @param $id + * @return array|bool + * @author Qinii + * @day 2020-07-01 + */ + public function subscribeTemplateMessage($params) + { + $data = []; + $id = $params['id']; + $tempId = $params['tempId']; + $user_make = app()->make(UserRechargeRepository::class); + $order_make = app()->make(StoreOrderRepository::class); + $refund_make = app()->make(StoreRefundOrderRepository::class); + $order_group_make = app()->make(StoreGroupOrderRepository::class); + $extract_make = app()->make(UserExtractRepository::class); + switch($tempId) + { + //订单支付成功 + case 'ORDER_PAY_SUCCESS': + $res = $order_group_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'ORDER_PAY_SUCCESS', + 'uid' => $res->uid, + 'data' => [ + 'character_string1' => $res->group_order_sn, + 'amount2' => $res->pay_price, + 'date3' => $res->pay_time, + 'amount5' => $res->total_price, + ], + 'link' => 'pages/users/order_list/index?status=1', + 'color' => null + ]; + break; + //订单发货提醒(快递) + case 'DELIVER_GOODS_CODE': + $res = $order_make->getWith($id,'orderProduct'); + if(!$res) return false; + $name = mb_substr($res['orderProduct'][0]['cart_info']['product']['store_name'],0,10); + $data[] = [ + 'tempCode' => 'ORDER_POSTAGE_SUCCESS', + 'uid' => $res->uid, + /** + 快递单号{{character_string2.DATA}} + 快递公司{{thing1.DATA}} + 发货时间{{time3.DATA}} + 订单商品{{thing5.DATA}} + */ + 'data' => [ + 'character_string2' => $res->delivery_id, + 'thing1' => $res->delivery_name, + 'time3' => date('Y-m-d H:i:s',time()), + 'thing5' => '「'.$name.'」等', + ], + + 'link' => 'pages/order_details/index?order_id='.$id, + 'color' => null + ]; + break; + //订单发货提醒(送货) + case 'ORDER_DELIVER_SUCCESS': + $res = $order_make->getWith($id,'orderProduct'); + if(!$res) return false; + $name = mb_substr($res['orderProduct'][0]['cart_info']['product']['store_name'],0,10); + $data[] = [ + 'tempCode' => 'ORDER_DELIVER_SUCCESS', + 'uid' => $res->uid, + 'data' => [ + 'thing8' => '「'.$name.'」等', + 'character_string1' => $res->order_sn, + 'name4' => $res->delivery_name, + 'phone_number10' => $res->delivery_id, + ], + 'link' => 'pages/order_details/index?order_id='.$id, + 'color' => null + ]; + break; + //退款通知 + case 'REFUND_CONFORM_CODE': + $res = $refund_make->get($id); + if(!$res) return false; + $name = mb_substr($res['refundProduct'][0]['product']['cart_info']['product']['store_name'],0,10); + $data[] = [ + 'tempCode' => 'ORDER_REFUND_NOTICE', + 'uid' => $res->uid, + 'data' => [ + 'thing1' => '退款成功', + 'thing2' => '「'.$name.'」等', + 'character_string6' => $res->refund_order_sn, + 'amount3' => $res->refund_price, + 'thing13' => $res->fail_message ?? '', + ], + 'link' => 'pages/users/refund/detail?id='.$id, + 'color' => null + ]; + break; + //资金变动 + case 'USER_BALANCE_CHANGE': + $res = $user_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'USER_BALANCE_CHANGE', + 'uid' => $res->uid, + 'data' => [ + 'character_string1' => $res->order_id, + 'amount3' => $res->price, + 'amount6' => $res->give_price, + 'date5' => $res->pay_time, + ], + 'link' => 'pages/users/user_money/index', + 'color' => null + ]; + break; + //提现结果通知 + case 'EXTRACT_NOTICE': + $res = $extract_make->get($id); + if(!$res) return false; + $data[] = [ + 'tempCode' => 'USER_EXTRACT', + 'uid' => $res->uid, + 'data' => [ + 'thing1' => $res->status == -1 ? '未通过' : '已通过', + 'amount2' => empty($res->bank_code)?(empty($res->alipay_code)?$res->wechat:$res->alipay_code):$res->bank_code, + 'thing3' => $res->give_price, + 'date4' => $res->create_time, + ], + 'link' => 'pages/users/user_spread_user/index', + 'color' => null + ]; + break; + //到货通知 + case'PRODUCT_INCREASE': + /* + 商品名称 {{thing1.DATA}} + 商品价格:{{amount5.DATA}} + 温馨提示:{{thing2.DATA}} + */ + $make = app()->make(ProductTakeRepository::class); + $product = app()->make(ProductRepository::class)->getWhere(['product_id' => $id],'*',['attrValue']); + if(!$product) return false; + $unique[] = 1; + foreach ($product['attrValue'] as $item) { + if($item['stock'] > 0){ + $unique[] = $item['unique']; + } + } + $res = $make->getSearch(['product_id' => $id,'status' =>0,'type' => 3])->where('unique','in',$unique)->column('uid,product_id,product_take_id'); + $uids = array_unique(array_column($res,'uid')); + if (!$uids) return false; + $takeId = array_column($res,'product_take_id'); + foreach ($uids as $uid) { + $data[] = [ + 'tempCode' => 'PRODUCT_INCREASE', + 'uid' => $uid, + 'data' => [ + 'thing1' => '「'.mb_substr($product->store_name,0,10) .'」', + 'amount5' => $product->price, + 'thing2' => '亲!你想要的商品已到货,可以购买啦~', + ], + 'link' => 'pages/goods_details/index?id='.$id, + 'color' => null + ]; + } + if ($takeId) $make->updates($takeId,['status' => 1]); + break; + default: + return false; + break; + } + return $data; + } +} diff --git a/crmeb/services/WechatUserGroupService.php b/crmeb/services/WechatUserGroupService.php new file mode 100644 index 00000000..7d1f389e --- /dev/null +++ b/crmeb/services/WechatUserGroupService.php @@ -0,0 +1,114 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use EasyWeChat\Support\Collection; +use EasyWeChat\User\Group; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\facade\Route; + +/** + * Class WechatUserGroupService + * @package crmeb\services + * @author xaboy + * @day 2020-04-27 + */ +class WechatUserGroupService +{ + /** + * @var Group + */ + protected $userGroup; + + /** + * WechatTemplateService constructor. + */ + public function __construct() + { + $this->userGroup = WechatService::create()->getApplication()->user_group; + } + + /** + * @return Group + * @author xaboy + * @day 2020-04-29 + */ + public function userGroup() + { + return $this->userGroup; + } + + /** + * @return array + * @author xaboy + * @day 2020-04-27 + */ + public function lst() + { + return $this->userGroup->lists()->toArray(); + } + + /** + * @param $groupName + * @return Collection + * @author xaboy + * @day 2020-04-27 + */ + public function create($groupName) + { + return $this->userGroup->create($groupName); + } + + /** + * @param $id + * @param $groupName + * @return Collection + * @author xaboy + * @day 2020-04-27 + */ + public function update($id, $groupName) + { + return $this->userGroup->update($id, $groupName); + } + + /** + * @param $id + * @return Collection + * @author xaboy + * @day 2020-04-27 + */ + public function delete($id) + { + return $this->userGroup->delete($id); + } + + + /** + * @param null $id + * @param string $name + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-27 + */ + public function form($id = null, $name = '') + { + return Elm::createForm($id ? Route::buildUrl('updateWechatUserGroup', compact('id'))->build() : Route::buildUrl('createWechatUserGroup')->build(), [ + Elm::input('tag_name', '分组名称', $name)->required() + ])->setTitle($id ? '编辑用户分组' : '添加用户分组'); + } +} diff --git a/crmeb/services/WechatUserTagService.php b/crmeb/services/WechatUserTagService.php new file mode 100644 index 00000000..dad212ff --- /dev/null +++ b/crmeb/services/WechatUserTagService.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use EasyWeChat\Support\Collection; +use EasyWeChat\User\Tag; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\facade\Route; + +/** + * Class WechatUserTagService + * @package crmeb\services + * @author xaboy + * @day 2020-04-27 + */ +class WechatUserTagService +{ + /** + * @var Tag + */ + protected $userTag; + + /** + * WechatTemplateService constructor. + */ + public function __construct() + { + $this->userTag = WechatService::create()->getApplication()->user_tag; + } + + public function userTag() + { + return $this->userTag; + } + + /** + * @return array + * @author xaboy + * @day 2020-04-27 + */ + public function lst() + { + return $this->userTag->lists()->toArray(); + } + + /** + * @param $tagName + * @return Collection + * @author xaboy + * @day 2020-04-27 + */ + public function create($tagName) + { + return $this->userTag->create($tagName); + } + + /** + * @param $id + * @param $tagName + * @return Collection + * @author xaboy + * @day 2020-04-27 + */ + public function update($id, $tagName) + { + return $this->userTag->update($id, $tagName); + } + + /** + * @param $id + * @return Collection + * @author xaboy + * @day 2020-04-27 + */ + public function delete($id) + { + return $this->userTag->delete($id); + } + + /** + * @param string $openId + * @return array + * @author xaboy + * @day 2020-04-29 + */ + public function userTags(string $openId) + { + return $this->userTag->userTags($openId)->toArray(); + } + + /** + * @param null $id + * @param string $name + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-04-27 + */ + public function form($id = null, $name = '') + { + return Elm::createForm($id ? Route::buildUrl('updateWechatUserTag', compact('id'))->build() : Route::buildUrl('createWechatUserTag')->build(), [ + Elm::input('tag_name', '标签名称', $name)->required() + ])->setTitle($id ? '编辑用户标签' : '添加用户标签'); + } +} diff --git a/crmeb/services/YunxinSmsService.php b/crmeb/services/YunxinSmsService.php new file mode 100644 index 00000000..7ef14251 --- /dev/null +++ b/crmeb/services/YunxinSmsService.php @@ -0,0 +1,439 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services; + + +use app\common\dao\system\sms\SmsRecordDao; +use app\common\repositories\store\broadcast\BroadcastRoomRepository; +use app\common\repositories\store\order\StoreGroupOrderRepository; +use app\common\repositories\store\order\StoreOrderRepository; +use app\common\repositories\store\order\StoreRefundOrderRepository; +use app\common\repositories\store\product\ProductRepository; +use app\common\repositories\store\product\ProductTakeRepository; +use app\common\repositories\store\service\StoreServiceRepository; +use app\common\repositories\system\config\ConfigValueRepository; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use crmeb\exceptions\SmsException; +use FormBuilder\Exception\FormBuilderException; +use FormBuilder\Factory\Elm; +use FormBuilder\Form; +use think\exception\ValidateException; +use think\facade\Cache; +use think\facade\Config; +use think\facade\Route; + +/** + * Class YunxinSmsService + * @package crmeb\services + * @author xaboy + * @day 2020-05-18 + */ +class YunxinSmsService +{ + /** + * api + */ + const API = 'https://sms.crmeb.net/api/'; + // const API = 'http://plat.crmeb.net/api/'; + + /** + * @var array + */ + protected $config; + + /** + * YunxinSmsService constructor. + * @param array $config + */ + public function __construct(array $config = []) + { + $this->config = $config; + if (isset($this->config['sms_token'])) { + $this->config['sms_token'] = $this->getToken(); + } + } + + /** + * @return string + * @author xaboy + * @day 2020-05-18 + */ + protected function getToken() + { + return md5($this->config['sms_account'] . $this->config['sms_token']); + } + + /** + * @author xaboy + * @day 2020-05-18 + */ + public function checkConfig() + { + if (!isset($this->config['sms_account']) || !$this->config['sms_account']) { + throw new ValidateException('请登录短信账户'); + } + if (!isset($this->config['sms_token']) || !$this->config['sms_token']) { + throw new ValidateException('请登录短信账户'); + } + } + + /** + * 发送注册验证码 + * @param $phone + * @return mixed + */ + public function captcha($phone) + { + return json_decode(HttpService::getRequest(self::API . 'sms/captcha', compact('phone')), true); + } + + /** + * 短信注册 + * @param $account + * @param $password + * @param $url + * @param $phone + * @param $code + * @param $sign + * @return mixed + */ + public function register($account, $password, $url, $phone, $code, $sign) + { + return $this->registerData(compact('account', 'password', 'url', 'phone', 'code', 'sign')); + } + + /** + * @param array $data + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function registerData(array $data) + { + return json_decode(HttpService::postRequest(self::API . 'sms/register', $data), true); + } + + /** + * 公共短信模板列表 + * @param array $data + * @return mixed + */ + public function publictemp(array $data = []) + { + $this->checkConfig(); + $data['account'] = $this->config['sms_account']; + $data['token'] = $this->config['sms_token']; + $data['source'] = 'crmeb_merchant'; + return json_decode(HttpService::postRequest(self::API . 'sms/publictemp', $data), true); + } + + /** + * 公共短信模板添加 + * @param $id + * @param $tempId + * @return mixed + */ + public function use($id, $tempId) + { + $this->checkConfig(); + $data = [ + 'account' => $this->config['sms_account'], + 'token' => $this->config['sms_token'], + 'id' => $id, + 'tempId' => $tempId, + ]; + + return json_decode(HttpService::postRequest(self::API . 'sms/use', $data), true); + } + + /** + * @param string $templateId + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function getTemplateCode(string $templateId) + { + return Config::get('sms.template_id.' . $templateId); + } + + /** + * 原 send 方法 (弃用) + * 发送短信 + * @param string $phone + * @param string $templateId + * @param array $data + * @return bool|string + * @throws SmsException + */ + public function sendDe(string $phone, string $templateId, array $data = []) + { + if (!$phone) { + throw new SmsException('Mobile number cannot be empty'); + } + + $this->checkConfig(); + + $formData['uid'] = $this->config['sms_account']; + $formData['token'] = $this->config['sms_token']; + $formData['mobile'] = $phone; + $formData['template'] = $this->getTemplateCode($templateId); + if (is_null($formData['template'])) + throw new SmsException('Missing template number'); + + $formData['param'] = json_encode($data); + $resource = json_decode(HttpService::postRequest(self::API . 'sms/send', $formData), true); + if ($resource['status'] === 400) { + throw new SmsException($resource['msg']); + } else { + app()->make(SmsRecordDao::class)->create([ + 'uid' => $formData['uid'], + 'phone' => $phone, + 'content' => $resource['data']['content'], + 'template' => $resource['data']['template'], + 'record_id' => $resource['data']['id'] + ]); + } + return $resource; + } + + /** + * 账号信息 + * @return mixed + */ + public function count() + { + $this->checkConfig(); + return json_decode(HttpService::postRequest(self::API . 'sms/userinfo', [ + 'account' => $this->config['sms_account'], + 'token' => $this->config['sms_token'] + ]), true); + } + + /** + * 支付套餐 + * @param $page + * @param $limit + * @return mixed + */ + public function meal($page, $limit) + { + return json_decode(HttpService::getRequest(self::API . 'sms/meal', [ + 'page' => $page, + 'limit' => $limit + ]), true); + } + + /** + * 支付码 + * @param $payType + * @param $mealId + * @param $price + * @param $attach + * @param $notify + * @return mixed + */ + public function pay($payType, $mealId, $price, $attach, $notify = null) + { + $this->checkConfig(); + $data['uid'] = $this->config['sms_account']; + $data['token'] = $this->config['sms_token']; + $data['payType'] = $payType; + $data['mealId'] = $mealId; + $data['notify'] = $notify ?? Route::buildUrl('SmsNotify')->build(); + $data['price'] = $price; + $data['attach'] = $attach; + return json_decode(HttpService::postRequest(self::API . 'sms/mealpay', $data), true); + } + + /** + * 申请模板消息 + * @param $title + * @param $content + * @param $type + * @return mixed + */ + public function apply($title, $content, $type) + { + $this->checkConfig(); + $data['account'] = $this->config['sms_account']; + $data['token'] = $this->config['sms_token']; + $data['title'] = $title; + $data['content'] = $content; + $data['type'] = $type; + return json_decode(HttpService::postRequest(self::API . 'sms/apply', $data), true); + } + + /** + * 短信模板列表 + * @param $data + * @return mixed + */ + public function template(array $data) + { + $this->checkConfig(); + return json_decode(HttpService::postRequest(self::API . 'sms/template', $data + [ + 'account' => $this->config['sms_account'], 'token' => $this->config['sms_token'] + ]), true); + } + + /** + * 获取短息记录状态 + * @param $record_id + * @return mixed + */ + public function getStatus(array $record_id) + { + return json_decode(HttpService::postRequest(self::API . 'sms/status', [ + 'record_id' => json_encode($record_id) + ]), true); + } + + /** + * @return YunxinSmsService + * @author xaboy + * @day 2020-05-18 + */ + public static function create() + { + /** @var ConfigValueRepository $make */ + $make = app()->make(ConfigValueRepository::class); + $config = $make->more(['sms_account', 'sms_token'], 0); + + return new static($config); + } + + /** + * @param string $sms_account + * @param string $sms_token + * @return $this + * @author xaboy + * @day 2020-05-18 + */ + public function setConfig(string $sms_account, string $sms_token) + { + $this->config = compact('sms_token', 'sms_account'); + $this->config['sms_token'] = $this->getToken(); + return $this; + } + + /** + * @return Form + * @throws FormBuilderException + * @author xaboy + * @day 2020-05-18 + */ + public function form() + { + return Elm::createForm(Route::buildUrl('smsCreate')->build(), [ + Elm::input('title', '模板名称'), + Elm::input('content', '模板内容')->type('textarea'), + Elm::radio('type', '模板类型', 1)->options([['label' => '验证码', 'value' => 1], ['label' => '通知', 'value' => 2], ['label' => '推广', 'value' => 3]]) + ])->setTitle('申请短信模板'); + } + + /** + * @return mixed + * @author xaboy + * @day 2020-05-18 + */ + public function account() + { + $this->checkConfig(); + return $this->config['sms_account']; + } + + /** + * @Author:Qinii + * @Date: 2020/9/19 + * @param $data + * @return mixed + */ + public function smsChange($data) + { + $this->checkConfig(); + $data['account'] = $this->config['sms_account']; + $data['token'] = $this->config['sms_token']; + return json_decode(HttpService::postRequest(self::API . 'sms/modify', $data), true); + } + + /** + * @Author:Qinii + * @Date: 2020/9/19 + * @param $phone + * @param $code + * @param $type + * @return bool + */ + public function checkSmsCode($phone, $code, $type) + { + if (!env('DEVELOPMENT',false)) { + $sms_key = $this->sendSmsKey($phone, $type); + if (!$cache_code = Cache::get($sms_key)) return false; + if ($code != $cache_code) return false; + Cache::delete($sms_key); + } + return true; + } + + /** + * @Author:Qinii + * @Date: 2020/9/19 + * @param $phone + * @param string $type + * @return string + */ + public function sendSmsKey($phone, $type = 'login') + { + switch ($type) { + case 'login': //登录 + return 'api_login_' . $phone; + break; + case 'binding': //绑定手机号 + return 'api_binding_' . $phone; + break; + case 'intention': //申请入住 + return 'merchant_intention_' . $phone; + break; + case 'change_pwd': //修改密码 + return 'change_pwd_' . $phone; + break; + case 'change_phone': //修改手机号 + return 'change_phone_' . $phone; + break; + default: + return 'crmeb_' . $phone; + break; + } + } + + public function send(string $phone, string $templateId, array $data = []) + { + try { + $make = app()->make(CrmebServeServices::class)->sms(); + $resource = $make->send($phone, $this->getTemplateCode($templateId), $data); + if ($resource) { + app()->make(SmsRecordDao::class)->create([ + 'uid' => $this->config['sms_account'], + 'phone' => $phone, + 'content' => $resource['content'], + 'template' => $resource['template'], + 'record_id' => $resource['id'], + ]); + } + } catch (\Exception $exception) { + throw new SmsException($exception->getMessage()); + } + } +} diff --git a/crmeb/services/alipay/AlipayNotify.php b/crmeb/services/alipay/AlipayNotify.php new file mode 100644 index 00000000..480cef06 --- /dev/null +++ b/crmeb/services/alipay/AlipayNotify.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\alipay; + + +use Payment\Contracts\IPayNotify; +use think\exception\ValidateException; +use think\facade\Log; + +class AlipayNotify implements IPayNotify +{ + private $type; + + public function __construct($type) + { + $this->type = $type; + } + + public function handle(string $channel, string $notifyType, string $notifyWay, array $notifyData) + { + Log::info('支付宝支付回调' . var_export($notifyData, 1)); + if (!in_array($notifyData['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) + throw new ValidateException('未支付'); + try { + event('pay_success_' . $this->type, ['order_sn' => $notifyData['out_trade_no'], 'data' => $notifyData]); + return true; + } catch (\Exception$e) { + Log::info('支付宝支付回调失败:' . $e->getMessage()); + } + return false; + } +} diff --git a/crmeb/services/delivery/Delivery.php b/crmeb/services/delivery/Delivery.php new file mode 100644 index 00000000..6748bc5b --- /dev/null +++ b/crmeb/services/delivery/Delivery.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\delivery; + +use crmeb\basic\BaseManager; +use think\facade\Config; + +class Delivery extends BaseManager +{ + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\delivery\\storage\\'; + + /** + * 设置默认 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('delivery.default', 'dada'); + } +} diff --git a/crmeb/services/delivery/storage/Dada.php b/crmeb/services/delivery/storage/Dada.php new file mode 100644 index 00000000..ce2575a6 --- /dev/null +++ b/crmeb/services/delivery/storage/Dada.php @@ -0,0 +1,319 @@ + +// +----------------------------------------------------------------------\ +namespace crmeb\services\delivery\storage; + +use crmeb\basic\BaseStorage; +use crmeb\interfaces\DeliveryInterface; +use think\exception\ValidateException; + +class Dada extends BaseStorage implements DeliveryInterface +{ + const BASE_URL = 'https://newopen.imdada.cn'; + + const ADD_MERCHANT = '/merchantApi/merchant/add'; + + const ADD_SHOP = '/api/shop/add'; + + const UPDATE_SHOP = '/api/shop/update'; + + const GET_CITY_CODE = '/api/cityCode/list'; + + const GET_SHOP_DETAIL = '/api/shop/detail'; + + const GET_ORDER_PRICE = '/api/order/queryDeliverFee'; + + const ADD_ORDER_AFTER_QUERY = '/api/order/addAfterQuery'; + + const ADD_ORDER_STSATUS_QUERY = '/api/order/status/query'; + + const GET_REASONS = '/api/order/cancel/reasons'; + + const CANCEL_ORDER = '/api/order/formalCancel'; + + const GET_BALANCE = '/api/balance/query'; + + const GET_RECHARGE = '/api/recharge'; + + public $config; + + public function initialize(array $config) + { + $this->config = $config; + } + + //创建商户 + public function addMerchant($data) + { + return $this->sendRequest(self::ADD_MERCHANT, $data); + } + + //创建门店 + public function addShop($data) + { + $parmas = []; + foreach ($data as $key => $item) { + if (!($item['lng']) || !($item['lat'])) + throw new ValidateException('经纬度不能为空'); + if (!($item['phone']) || !($item['contact_name'])) + throw new ValidateException('联系人信息不能为空'); + if (!($item['business'])) + throw new ValidateException('配送物品分类不能为空'); + if (!($item['station_name']) || !$item['station_address']) + throw new ValidateException('门店信息不能为空'); + $value = [ + 'lng' => (float)$item['lng'], + 'lat' => (float)$item['lat'], + 'phone' => $item['phone'], + 'business' => (int)$item['business'], + 'contact_name' => $item['contact_name'], + 'station_name' => $item['station_name'], + 'station_address' => $item['station_address'], + 'status' => 1, + 'origin_shop_id' => $item['origin_shop_id'], + ]; + if (isset($item['username']) && $item['username']) $value['username'] = $item['username']; + if (isset($item['password']) && $item['password']) $value['password'] = $item['password']; + $parmas[] = $value; + } + return $this->sendRequest(self::ADD_SHOP, $parmas); + } + + //更新门店 + public function updateShop($data) + { + $params['origin_shop_id'] = $data['origin_shop_id']; + if (isset($data['new_shop_id'])) $params['new_shop_id'] = $data['new_shop_id']; + if (isset($data['station_name'])) $params['station_name'] = $data['station_name']; + if (isset($data['business'])) $params['business'] = $data['business']; + if (isset($data['station_address'])) $params['station_address'] = $data['station_address']; + if (isset($data['lng'])) $params['lng'] = $data['lng']; + if (isset($data['lat'])) $params['lat'] = $data['lat']; + if (isset($data['contact_name'])) $params['contact_name'] = $data['contact_name']; + if (isset($data['phone'])) $params['phone'] = $data['phone']; + if (isset($data['status'])) $params['status'] = $data['status']; + return $this->sendRequest(self::UPDATE_SHOP, $params); + } + + //预发布订单 + public function addOrder($data) + { + $params = [ + 'deliveryNo' => $data['deliveryNo'], + ]; + return $this->sendRequest(self::ADD_ORDER_AFTER_QUERY, $params); + } + + //计算订单价格 + public function getOrderPrice($data) + { + $params = [ + 'shop_no' => $data['shop_no'], + 'origin_id' => $data['origin_id'], + 'city_code' => $data['city_code'], + 'cargo_price' => $data['cargo_price'], + 'is_prepay' => $data['is_prepay'], + 'receiver_name' => $data['receiver_name'], + 'receiver_address'=> $data['receiver_address'], + 'callback' => $data['callback_url'], + 'cargo_weight' => $data['cargo_weight'], + 'receiver_phone' => $data['receiver_phone'], + 'is_finish_code_needed'=> $data['is_finish_code_needed'], + ]; + return $this->sendRequest(self::GET_ORDER_PRICE, $params); + } + + //获取订单详情 + public function getOrderDetail($data) + { + $params['order_id'] = $data['origin_id']; + return $this->sendRequest(self::ADD_ORDER_STSATUS_QUERY, $params); + } + //取消订单 + public function cancelOrder($data) + { + $params['order_id'] = $data['origin_id']; + $params['cancel_reason'] = $data['cancel_reason'] ?? '无'; + $params['cancel_reason_id'] = $data['reason']; + return $this->sendRequest(self::CANCEL_ORDER, $params); + } + //获取充值地址 + public function getRecharge($data =[]) + { + $params = [ + 'amount' => $data['amount'] ?? 100, + 'category'=> $data['category'] ?? 'PC', + ]; + return $this->sendRequest(self::GET_RECHARGE, $params); + } + //获取余额 + public function getBalance($data) + { + $params['category'] = $data['category'] ?? 3; + $res = $this->sendRequest(self::GET_BALANCE, $params); + return [ + 'deliverBalance' => $res['deliverBalance'] + ]; + } + //支付小费 + public function addTip($data) + { + } + //取消原因 + public function reasons($data = '') + { + $options = $this->sendRequest(self::GET_REASONS, $data); + foreach ($options as $option) { + $value = $option['id']; + $label = $option['reason']; + $res[] = compact('value','label'); + } + return $res; + } + //获取城市信息 + public function getCity($data = '') + { + $res = $this->sendRequest(self::GET_CITY_CODE, $data); + foreach ($res as $item) { + $data[] = [ + 'key' => $item['cityName'], + 'label' => $item['cityName'], + ]; + } + return $data; + } + + public function getShopDetail($id) + { + $data = ['origin_shop_id' => $id]; + return $this->sendRequest(self::GET_SHOP_DETAIL, $data); + } + + public function getBusiness() + { + return [ + ['key' => 1 , 'label' => '食品小吃'], + ['key' => 2 , 'label' => '饮料'], + ['key' => 3 , 'label' => '鲜花绿植'], + ['key' => 5 , 'label' => '其他'], + ['key' => 8 , 'label' => '文印票务'], + ['key' => 9 , 'label' => '便利店'], + ['key' => 13 , 'label' => '水果生鲜'], + ['key' => 19 , 'label' => '同城电商'], + ['key' => 20 , 'label' => '医药'], + ['key' => 21 , 'label' => '蛋糕'], + ['key' => 24 , 'label' => '酒品'], + ['key' => 25 , 'label' => '小商品市场'], + ['key' => 26 , 'label' => '服装'], + ['key' => 27 , 'label' => '汽修零配'], + ['key' => 28 , 'label' => '数码家电'], + ['key' => 29 , 'label' => '小龙虾/烧烤'], + ['key' => 31 , 'label' => '超市'], + ['key' => 51 , 'label' => '火锅'], + ['key' => 53 , 'label' => '个护美妆'], + ['key' => 55 , 'label' => '母婴'], + ['key' => 57 , 'label' => '家居家纺'], + ['key' => 59 , 'label' => '手机'], + ['key' => 61 , 'label' => '家装'], + ['key' => 63 , 'label' => '成人用品'], + ]; + } + + public function sendRequest($api, $params) + { + $url = self::BASE_URL . $api; + $params = $this->bulidRequestParams($params); + $response = $this->httpRequestWithPost($url, $params); + $data = $this->getMessage($response); + return $data; + } + + /** + * 构造请求数据 + * data:业务参数,json字符串 + */ + public function bulidRequestParams($params) + { + $requestParams = array(); + $requestParams['app_key'] = $this->config['app_key']; + $requestParams['body'] = json_encode($params); + $requestParams['format'] = 'json'; + $requestParams['v'] = '1.0'; + $requestParams['source_id'] = $this->config['source_id']; + $requestParams['timestamp'] = time(); + $requestParams['signature'] = $this->_sign($requestParams); + return json_encode($requestParams); + } + + /** + * 签名生成signature + */ + public function _sign($data) + { + //1.升序排序 + ksort($data); + //2.字符串拼接 + $args = ""; + foreach ($data as $key => $value) { + $args .= $key . $value; + } + $args = $this->config['app_secret'] . $args . $this->config['app_secret']; + //3.MD5签名,转为大写 + $sign = strtoupper(md5($args)); + return $sign; + } + + /** + * 发送请求,POST + * @param $url 指定URL完整路径地址 + * @param $data 请求的数据 + */ + public function httpRequestWithPost($url, $data, $headers = []) + { + $headers = array( + 'Content-Type: application/json', + ); + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + curl_setopt($curl, CURLOPT_TIMEOUT, 3); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + $resp = curl_exec($curl); + $info = curl_getinfo($curl); + curl_close($curl); + if (isset($info['http_code']) && $info['http_code'] == 200) { + return $resp; + } + return ; + } + + protected function getMessage($json, $message = '未知错误!') + { + $data = json_decode($json, true); + if ($data['code'] !== 0) { + isset($data['msg']) && $message = $data['msg']; + if ($data['errorCode'] == 7718) { + foreach ($data['result']['failedList'] as $datum) { + $message .= ':'.$datum['shopName'].'/'. $datum['msg'].';'; + } + } + throw new ValidateException('【达达错误提示】:'.$message); + } else { + if ($data['status'] == 'success') return $data['result'] ?? $data; + return $data; + + } + } + + +} diff --git a/crmeb/services/delivery/storage/Uupt.php b/crmeb/services/delivery/storage/Uupt.php new file mode 100644 index 00000000..dd7b6bcb --- /dev/null +++ b/crmeb/services/delivery/storage/Uupt.php @@ -0,0 +1,309 @@ + +// +---------------------------------------------------------------------- +namespace crmeb\services\delivery\storage; + +use crmeb\basic\BaseStorage; +use crmeb\interfaces\DeliveryInterface; +use think\exception\ValidateException; + +class Uupt extends BaseStorage implements DeliveryInterface +{ + //uu跑腿 + public $config; + + //域名 + // const BASE_URL = 'http://openapi.test.uupt.com/'; + const BASE_URL = 'https://openapi.uupt.com'; + + //发布订单 + const ADD_ORDER = '/v2_0/addorder.ashx'; + + //计算价格 + const GET_ORDER_PRICE = '/v2_0/getorderprice.ashx'; + + //详情 + const GET_ORDER_DETAIL = '/v2_0/getorderdetail.ashx'; + + //充值 + const GET_RECHARGE = '/v2_0/getrecharge.ashx'; + + //取消 + const CANCEL_ORDER = '/v2_0/cancelorder.ashx'; + + //查询门店 + const GET_SHOP = '/v2_0/getshoplist.ashx'; + + //余额 + const GET_BALANCEDE = '/v2_0/getbalancedetail.ashx'; + + //获取城市 + const GET_CITY = '/v2_0/getcitylist.ashx'; + + public function initialize(array $config) + { + $this->config = $config; + } + + //发布订单 + public function addOrder($data) + { + $params = [ + 'price_token' => $data['price_token'], + 'order_price' => $data['total_money'], + 'balance_paymoney' => $data['need_paymoney'], + 'receiver' => $data['receiver'], + 'receiver_phone' => $data['receiver_phone'], + 'callback_url' => $data['callback_url'], + 'push_type' => '0', //推送方式(0 开放订单,2测试订单)默认传0即可 + 'special_type' => '0', + 'callme_withtake' => $data['callme_withtake'] ?? '0', + 'pay_type' => 0, + ]; + if ($data['note']) $params['note'] = $data['note']; + return $this->sendRequest(self::ADD_ORDER, $params); + } + + //计算订单价格 + public function getOrderPrice($data) + { + $params = [ + 'from_address' => $data['from_address'], + 'to_address' => $data['to_address'], + 'city_name' => $data['city_name'], + 'goods_type' => $data['goods_type'], + 'send_type' =>'0', + 'to_lat' => (string)$data['to_lat'], + 'to_lng' => (string)$data['to_lng'], + 'from_lat' => (string)$data['from_lat'], + 'from_lng' => (string)$data['from_lng'], + ]; + return $this->sendRequest(self::GET_ORDER_PRICE, $params); + } + + //获取订单详情 + public function getOrderDetail($data) + { + if($data['order_sn']) $params['origin_id'] = $data['order_sn']; + if($data['order_code']) $params['order_code'] = $data['order_code']; + return $this->sendRequest(self::GET_ORDER_DETAIL, $params); + } + + //取消订单 + public function cancelOrder($data) + { + $params = [ + 'origin_id' => $data['origin_id'], + 'order_code'=> $data['order_code'], + 'reason' => $data['reason'], + ]; + return $this->sendRequest(self::CANCEL_ORDER, $params); + } + + //获取充值地址 + public function getRecharge($data) + { + return $this->sendRequest(self::GET_RECHARGE, $data); + } + + //获取余额 + public function getBalance($data) + { + $res = $this->sendRequest(self::GET_BALANCEDE, $data); + return [ + 'deliverBalance' => $res['AccountMoney'] + ]; + } + //支付小费 + public function addTip($data) + { + } + //获取城市信息 + public function getCity($data = []) + { + $res = $this->sendRequest(self::GET_CITY, $data); + foreach ($res['CityList'] as $item) { + $data[] = [ + 'key' => $item['CityName'], + 'label' => $item['CityName'], + ]; + } + return $data; + } + + + public function sendRequest($api, $params = []) + { + $url = self::BASE_URL . $api; + $params = $this->bulidRequestParams($params); + $response = $this->httpRequestWithPost($url, $params); + $data = $this->getMessage($response); + return $data; + } + + /** + * 构造请求数据 + * data:业务参数 + */ + public function bulidRequestParams(array $params = []) + { + $params['openid'] = $this->config['open_id']; + $params['appid'] = $this->config['app_id']; + $params['nonce_str'] = str_replace('-', '', $this->guid()); + $params['timestamp'] = time(); + $params['sign'] = $this->_sign($params); + $arr = []; + foreach ($params as $key => $value) { + $arr[] = $key . '=' . $value; + } + $curlPost = implode('&', $arr); + return $curlPost; + } + + // 生成guid + public function guid() + { + mt_srand((float)microtime() * 10000); //optional for php 4.2.0 and up. + $charid = strtoupper(md5(uniqid(rand(), true))); + $hyphen = chr(45); // "-" + $uuid = substr($charid, 0, 8) . $hyphen + . substr($charid, 8, 4) . $hyphen + . substr($charid, 12, 4) . $hyphen + . substr($charid, 16, 4) . $hyphen + . substr($charid, 20, 12); + return strtolower(str_replace('-', '', $uuid)); + } + + /** + * 签名生成sign + */ + public function _sign($data) + { + ksort($data); + $str = ''; + foreach ($data as $key => $value) { + if (!is_null($value)) { + $str .= $key . '=' . $value . '&'; + } + } + $str .= 'key=' . $this->config['app_key']; + $str = mb_strtoupper($str, 'UTF-8'); + return strtoupper(md5($str)); + } + + /** + * 发送请求,POST + * @param $url 指定URL完整路径地址 + * @param $data 请求的数据 + */ + public function httpRequestWithPost($url, $data) + { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + curl_setopt($curl, CURLOPT_TIMEOUT, 3); + $resp = curl_exec($curl); + $info = curl_getinfo($curl); + curl_close($curl); + return $resp; + } + + protected function getMessage($json, $message = '未知错误!') + { + $data = json_decode($json, true); + if (!in_array($data['return_code'], ['ok', 'fail'])) { + isset($data['return_msg']) && $message = $data['return_msg']; + $mes = $message == '未知错误!' ? $this->getCodeMap($data['return_code']) : $message; + throw new ValidateException('【UU错误提示】:'.$mes); + } else { + return $data; + } + } + + + /** + * 获取错误代码 + * @param string $key 代码 + * @return String 错误代码与信息 + */ + protected function getCodeMap($key) + { + $codeMap = [ + '-101' => '参数格式校验错误', + '-102' => 'timestamp错误', + '-103' => 'appid无效', + '-104' => '签名校验失败', + '-105' => 'openid无效', + '-199' => '参数格式校验错误', + '-1001' => '无法解析起始地', + '-1002' => '无法解析目的地', + '-1003' => '无法获取订单城市相关信息', + '-1004' => '订单小类出现错误', + '-1005' => '没有用户信息', + '-1006' => '优惠券ID错误', + '-2001' => 'price_token无效', + '-2002' => 'price_token无效', + '-2003' => '收货人电话格式错误', + '-2004' => 'special_type错误', + '-2005' => 'callme_withtake错误', + '-2006' => 'order_price错误', + '-2007' => 'balance_paymoney错误', + '-2008' => '订单总金额错误', + '-2009' => '支付金额错误', + '-2010' => '用户不一致', + '-2011' => '手机号错误', + '-2012' => '不存在绑定关系', + '-4001' => '取消原因不能为空', + '-4002' => '订单编号无效', + '-5001' => '订单编号无效', + '-5002' => '订单编号无效', + '-5003' => '订单编号无效', + '-10001' => '发送频率过快,请稍候重试', + '-11001' => '请输入正确的验证码', + ]; + $info = isset($codeMap[$key]) ? $codeMap[$key] : false; + + return $info; + } + + //创建商户 + public function addMerchant($data) + { + return true; + } + + //创建门店 + public function addShop($data) + { + return true; + } + + //更新门店 + public function updateShop($data) + { + return true; + } + + public function getBusiness() + { + return [ + ['key' => 1, 'label' => '美食'], + ['key' => 2, 'label' => '鲜花'], + ['key' => 3, 'label' => '蛋糕'], + ['key' => 4, 'label' => '手机'], + ['key' => 5, 'label' => '钥匙'], + ['key' => 6, 'label' => '文件'], + ['key' => 0, 'label' => '其他'], + ]; + } +} diff --git a/crmeb/services/easywechat/BaseClient.php b/crmeb/services/easywechat/BaseClient.php new file mode 100644 index 00000000..141e27e3 --- /dev/null +++ b/crmeb/services/easywechat/BaseClient.php @@ -0,0 +1,309 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat; + + +use EasyWeChat\Core\AbstractAPI; +use EasyWeChat\Core\AccessToken; +use EasyWeChat\Core\Exceptions\HttpException; +use EasyWeChat\Core\Exceptions\InvalidConfigException; +use EasyWeChat\Core\Http; +use EasyWeChat\Encryption\EncryptionException; +use think\exception\InvalidArgumentException; + +class BaseClient extends AbstractAPI +{ + protected $app; + + const KEY_LENGTH_BYTE = 32; + const AUTH_TAG_LENGTH_BYTE = 16; + + protected $isService = true; + + public function __construct(AccessToken $accessToken, $app) + { + parent::__construct($accessToken); + $this->app = $app; + } + + public function setServiceStatus($val) + { + $this->isService = $val; + return $this; + } + + + /** + * @param $api + * @param $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + protected function httpPostJson($api, $params) + { + try { + return $this->parseJSON('json', [$api, $params]); + } catch (HttpException $e) { + $code = $e->getCode(); + throw new HttpException("接口异常[$code]" . ($e->getMessage()), $code); + } + } + + /** + * @param $api + * @param $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + protected function httpPost($api, $params) + { + try { + return $this->parseJSON('post', [$api, $params]); + } catch (HttpException $e) { + $code = $e->getCode(); + throw new HttpException("接口异常[$code]" . ($e->getMessage()), $code); + } + } + + + /** + * @param $api + * @param $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + protected function httpGet($api, $params) + { + try { + return $this->parseJSON('get', [$api, $params]); + } catch (HttpException $e) { + $code = $e->getCode(); + throw new HttpException("接口异常[$code]" . ($e->getMessage()), $code); + } + } + + /** + * request. + * + * @param string $endpoint + * @param string $method + * @param array $options + * @param bool $returnResponse + */ + public function request(string $endpoint, string $method = 'POST', array $options = [], $serial = true) + { + $sign_body = $options['sign_body'] ?? ''; + $headers = [ + 'Content-Type' => 'application/json', + 'User-Agent' => 'curl', + 'Accept' => 'application/json', + 'Authorization' => $this->getAuthorization($endpoint, $method, $sign_body), +// 'Wechatpay-Serial' => $this->app['config']['payment']['serial_no'] + ]; + $options['headers'] = array_merge($headers, ($options['headers'] ?? [])); + + if ($serial) $options['headers']['Wechatpay-Serial'] = $this->app->certficates->setServiceStatus($this->isService)->get()['serial_no']; + + Http::setDefaultOptions($options); + return $this->_doRequestCurl($method, 'https://api.mch.weixin.qq.com' . $endpoint, $options); + } + + + private function _doRequestCurl($method, $location, $options = []) + { + $curl = curl_init(); + // POST数据设置 + if (strtolower($method) === 'post') { + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $options['data'] ?? $options['sign_body'] ?? ''); + } + // CURL头信息设置 + if (!empty($options['headers'])) { + $headers = []; + foreach ($options['headers'] as $k => $v) { + $headers[] = "$k: $v"; + } + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + } + curl_setopt($curl, CURLOPT_URL, $location); + curl_setopt($curl, CURLOPT_HEADER, true); + curl_setopt($curl, CURLOPT_TIMEOUT, 60); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + $content = curl_exec($curl); + $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE); + curl_close($curl); + return json_decode(substr($content, $headerSize), true); + } + + + /** + * get sensitive fields name. + * + * @return array + */ + protected function getSensitiveFieldsName() + { + return [ + 'contact_name', + 'contact_id_number', + 'mobile_phone', + 'contact_email', + 'id_card_name', + 'id_card_number', + 'id_card_address', + 'id_doc_name', + 'id_doc_number', + 'id_doc_address', + 'name', + 'id_number', + 'account_name', + 'account_number', + 'contact_id_card_number', + 'contact_email', + 'openid', + 'ubo_id_doc_name', + 'ubo_id_doc_number', + 'ubo_id_doc_address', + 'bank_address_code', + ]; + } + + /** + * To id card, mobile phone number and other fields sensitive information encryption. + * + * @param string $string + * + * @return string + */ + protected function encryptSensitiveInformation(string $string) + { + $certificates = $this->app->certficates->setServiceStatus($this->isService)->get()['certificates']; + if (null === $certificates) { + throw new InvalidConfigException('config certificate connot be empty.'); + } + $encrypted = ''; + if (openssl_public_encrypt($string, $encrypted, $certificates, OPENSSL_PKCS1_OAEP_PADDING)) { + //base64编码 + $sign = base64_encode($encrypted); + } else { + throw new EncryptionException('Encryption of sensitive information failed'); + } + return $sign; + } + + /** + * processing parameters contain fields that require sensitive information encryption. + * + * @param array $params + * + * @return array + */ + protected function processParams(array $params) + { + + $sensitive_fields = $this->getSensitiveFieldsName(); + foreach ($params as $k => $v) { + if (is_array($v)) { + $params[$k] = $this->processParams($v); + } else { + if (in_array($k, $sensitive_fields, true)) { + $params[$k] = $this->encryptSensitiveInformation($v); + } + } + } + + return $params; + } + + /** + * @param string $url + * @param string $method + * @param string $body + * @return string + */ + protected function getAuthorization(string $url, string $method, string $body) + { + $nonce_str = uniqid(); + $timestamp = time(); + $message = $method . "\n" . + $url . "\n" . + $timestamp . "\n" . + $nonce_str . "\n" . + $body . "\n"; + openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption'); + $sign = base64_encode($raw_sign); + $schema = 'WECHATPAY2-SHA256-RSA2048 '; + $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', + ($this->isService ? $this->app['config']['service_payment']['merchant_id'] : $this->app['config']['payment']['merchant_id']), + $nonce_str, + $timestamp, + ($this->isService ? $this->app['config']['service_payment']['serial_no'] : $this->app['config']['payment']['serial_no']), + $sign); + + return $schema . $token; + } + + /** + * 获取商户私钥 + * @return bool|resource + */ + protected function getPrivateKey() + { + $key_path = $this->isService ? $this->app['config']['service_payment']['key_path'] : $this->app['config']['payment']['key_path']; + if (!file_exists($key_path)) { + throw new \InvalidArgumentException( + "SSL certificate not found: {$key_path}" + ); + } + return openssl_pkey_get_private(file_get_contents($key_path)); + } + + /** + * decrypt ciphertext. + * + * @param array $encryptCertificate + * + * @return string + */ + public function decrypt(array $encryptCertificate) + { + $ciphertext = base64_decode($encryptCertificate['ciphertext'], true); + $associatedData = $encryptCertificate['associated_data']; + $nonceStr = $encryptCertificate['nonce']; + $aesKey = ($this->isService ? $this->app['config']['service_payment']['apiv3_key'] : $this->app['config']['payment']['apiv3_key']); + + try { + // ext-sodium (default installed on >= PHP 7.2) + if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) { + return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey); + } + // ext-libsodium (need install libsodium-php 1.x via pecl) + if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) { + return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey); + } + // openssl (PHP >= 7.1 support AEAD) + if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) { + $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE); + $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE); + return \openssl_decrypt($ctext, 'aes-256-gcm', $aesKey, \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData); + } + } catch (\Exception $exception) { + throw new InvalidArgumentException($exception->getMessage(), $exception->getCode()); + } catch (\SodiumException $exception) { + throw new InvalidArgumentException($exception->getMessage(), $exception->getCode()); + } + throw new InvalidArgumentException('AEAD_AES_256_GCM 需要 PHP 7.1 以上或者安装 libsodium-php'); + } +} diff --git a/crmeb/services/easywechat/batches/Client.php b/crmeb/services/easywechat/batches/Client.php new file mode 100644 index 00000000..0a820f0a --- /dev/null +++ b/crmeb/services/easywechat/batches/Client.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\batches; + + +use crmeb\services\easywechat\BaseClient; +use think\exception\ValidateException; + +class Client extends BaseClient +{ + protected $isService = false; + + /** + * 商家转账到零钱 + * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml + * @param $type + * @param array $order + * @return mixed + */ + public function send(array $order) + { + $params = [ + 'appid' => $this->app['config']['app_id'], + 'out_batch_no' => $order['out_batch_no'], + 'batch_name' => $order['batch_name'], + 'batch_remark' => $order['batch_remark'], + 'total_amount' => $order['total_amount'], + 'total_num' => $order['total_num'], + 'transfer_detail_list' => $order['transfer_detail_list'], + ]; + $content = json_encode($params, JSON_UNESCAPED_UNICODE); + + $res = $this->request('/v3/transfer/batches', 'POST', ['sign_body' => $content]); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + +} diff --git a/crmeb/services/easywechat/batches/ServiceProvider.php b/crmeb/services/easywechat/batches/ServiceProvider.php new file mode 100644 index 00000000..8b027417 --- /dev/null +++ b/crmeb/services/easywechat/batches/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\batches; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['batches'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/broadcast/Client.php b/crmeb/services/easywechat/broadcast/Client.php new file mode 100644 index 00000000..ca35139c --- /dev/null +++ b/crmeb/services/easywechat/broadcast/Client.php @@ -0,0 +1,462 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\broadcast; + + +use EasyWeChat\Core\Exceptions\HttpException; +use EasyWeChat\MiniProgram\Core\AbstractMiniProgram; + +/** + * Class Client. + * + * @author Abbotton + */ +class Client extends AbstractMiniProgram +{ + const MSG_CODE = [ + '1' => '未创建直播间', + '1003' => '商品id不存在', + '47001' => '入参格式不符合规范', + '200002' => '入参错误', + '300001' => '禁止创建/更新商品 或 禁止编辑&更新房间', + '300002' => '名称长度不符合规则', + '300006' => '图片上传失败', + '300022' => '此房间号不存在', + '300023' => '房间状态 拦截', + '300024' => '商品不存在', + '300025' => '商品审核未通过', + '300026' => '房间商品数量已经满额', + '300027' => '导入商品失败', + '300028' => '房间名称违规', + '300029' => '主播昵称违规', + '300030' => '主播微信号不合法', + '300031' => '直播间封面图不合规', + '300032' => '直播间分享图违规', + '300033' => '添加商品超过直播间上限', + '300034' => '主播微信昵称长度不符合要求', + '300035' => '主播微信号不存在', + '300003' => '价格输入不合规', + '300004' => '商品名称存在违规违法内容', + '300005' => '商品图片存在违规违法内容', + '300007' => '线上小程序版本不存在该链接', + '300008' => '添加商品失败', + '300009' => '商品审核撤回失败', + '300010' => '商品审核状态不对', + '300011' => '操作非法', + '300012' => '没有提审额度', + '300013' => '提审失败', + '300014' => '审核中,无法删除', + '300017' => '商品未提审', + '300018' => '图片尺寸不符合要求', + '300021' => '商品添加成功,审核失败', + '300036' => '请先在微信直播小程序中实名认证', + '300038' => '请先在小程序后台配置直播客服', + '-1' => '系统错误', + ]; + + const API = 'https://api.weixin.qq.com/'; + + /** + * @param $api + * @param $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + protected function httpPostJson($api, $params) + { + try { + return $this->parseJSON('json', [self::API . $api, $params]); + } catch (HttpException $e) { + $code = $e->getCode(); + throw new HttpException("接口异常[$code]" . (self::MSG_CODE[$code] ?? $e->getMessage()), $code); + } + } + + /** + * @param $api + * @param $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + protected function httpPost($api, $params) + { + try { + return $this->parseJSON('post', [self::API . $api, $params]); + } catch (HttpException $e) { + $code = $e->getCode(); + throw new HttpException("接口异常[$code]" . (self::MSG_CODE[$code] ?? $e->getMessage()), $code); + } + } + + + /** + * @param $api + * @param $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + protected function httpGet($api, $params) + { + try { + return $this->parseJSON('get', [self::API . $api, $params]); + } catch (HttpException $e) { + $code = $e->getCode(); + throw new HttpException("接口异常[$code]" . (self::MSG_CODE[$code] ?? $e->getMessage()), $code); + } + } + + /** + * Add broadcast goods. + * + * @param array $goodsInfo + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function create(array $goodsInfo) + { + $params = [ + 'goodsInfo' => $goodsInfo, + ]; + + return $this->httpPostJson('wxaapi/broadcast/goods/add', $params); + } + + /** + * Reset audit. + * + * @param int $auditId + * @param int $goodsId + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function resetAudit(int $auditId, int $goodsId) + { + $params = [ + 'auditId' => $auditId, + 'goodsId' => $goodsId, + ]; + + return $this->httpPostJson('wxaapi/broadcast/goods/resetaudit', $params); + } + + /** + * Resubmit audit goods. + * + * @param int $goodsId + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function resubmitAudit(int $goodsId) + { + $params = [ + 'goodsId' => $goodsId, + ]; + + return $this->httpPostJson('wxaapi/broadcast/goods/audit', $params); + } + + /** + * Delete broadcast goods. + * + * @param int $goodsId + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function delete(int $goodsId) + { + $params = [ + 'goodsId' => $goodsId, + ]; + try{ + return $this->httpPostJson('wxaapi/broadcast/goods/delete', $params); + } catch (HttpException $exception) { + if ($exception->getCode() == 300015) return ; + } + } + + /** + * Update goods info. + * + * @param array $goodsInfo + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function update(array $goodsInfo) + { + $params = [ + 'goodsInfo' => $goodsInfo, + ]; + + return $this->httpPostJson('wxaapi/broadcast/goods/update', $params); + } + + /** + * Get goods information and review status. + * + * @param array $goodsIdArray + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getGoodsWarehouse(array $goodsIdArray) + { + $params = [ + 'goods_ids' => $goodsIdArray, + ]; + + return $this->httpPostJson('wxa/business/getgoodswarehouse', $params); + } + + /** + * Get goods list based on status + * + * @param array $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getApproved(array $params) + { + return $this->httpGet('wxaapi/broadcast/goods/getapproved', $params); + } + + /** + * Add goods to the designated live room. + * + * @param array $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function addGoods(array $params) + { + return $this->httpPost('wxaapi/broadcast/room/addgoods', $params); + } + + /** + * Get Room List. + * + * @param int $start + * @param int $limit + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getRooms(int $start = 0, int $limit = 10) + { + $params = [ + 'start' => $start, + 'limit' => $limit, + ]; + + return $this->httpPostJson('wxa/business/getliveinfo', $params); + } + + /** + * Get Playback List. + * + * @param int $roomId + * @param int $start + * @param int $limit + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getPlaybacks(int $roomId, int $start = 0, int $limit = 10) + { + $params = [ + 'action' => 'get_replay', + 'room_id' => $roomId, + 'start' => $start, + 'limit' => $limit, + ]; + + return $this->httpPostJson('wxa/business/getliveinfo', $params); + } + + /** + * Create a live room. + * + * @param array $params + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function createLiveRoom(array $params) + { + return $this->httpPostJson('wxaapi/broadcast/room/create', $params); + } + + /** + * TODO + * @param int $roomId + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/22/21 + */ + public function getPushUrl(int $roomId) + { + $params = [ + 'roomId' => $roomId, + ]; + return $this->httpGet('wxaapi/broadcast/room/getpushurl', $params); + } + + /** + * TODO 是否关闭客服 【0:开启,1:关闭】 + * @param int $roomId + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/22/21 + */ + public function closeKf(int $roomId,int $status) + { + $params = [ + 'roomId' => $roomId, + 'closeKf' => $status ? 1 : 0, + ]; + return $this->httpPostJson('wxaapi/broadcast/room/updatekf', $params); + } + + /** + * TODO 1-禁言,0-取消禁言 + * @param int $roomId + * @param int $type + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/22/21 + */ + public function banComment(int $roomId, int $status) + { + $params = [ + 'roomId' => $roomId, + 'banComment' => $status ? 1 : 0, + ]; + return $this->httpPostJson('wxaapi/broadcast/room/updatecomment', $params); + } + + /** + * TODO 添加助手 + * @param array $params + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/25/21 + */ + public function addAssistant(array $params) + { + return $this->httpPostJson('wxaapi/broadcast/room/addassistant', $params); + } + + /** + * TODO 删除助手 + * @param array $params + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/25/21 + */ + public function removeAssistant(int $roomId, string $username) + { + $params = [ + 'roomId' => $roomId, + 'username' => $username, + ]; + return $this->httpPostJson('wxaapi/broadcast/room/removeassistant', $params); + } + + /** + * TODO 修改小助手 + * @param array $params + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/25/21 + */ + public function modifyAssistant(array $params) + { + return $this->httpPostJson('wxaapi/broadcast/room/modifyassistant', $params); + } + + /** + * TODO 助手列表 + * @param int $roomId + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/25/21 + * wxa/business/get_wxa_followers?access_token= + + + */ + public function getAssistantList(int $roomId) + { + $params = [ + 'roomId' => $roomId, + ]; + return $this->httpGet('wxaapi/broadcast/room/getassistantlist', $params); + } + + /** + * TODO 获取长期订阅用户 + * @param int $roomId + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/25/21 + */ + public function getFollowers(string $page, int $limit = 2000) + { + $params['limit'] = $limit; + if ($page) $params['page_break'] = $page; + return $this->httpPostJson('wxa/business/get_wxa_followers', $params); + } + + /** + * TODO 群发发送订阅 + * @param int $roomId + * @param array $data + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/25/21 + */ + public function pushMessage(int $roomId, array $data) + { + $params = [ + 'room_id' => $roomId, + 'user_openid' => $data, + ]; + + return $this->httpPostJson('wxa/business/push_message', $params); + } + + + /** + * TODO 更新官方收录 + * @param int $roomId + * @param int $status + * @return \EasyWeChat\Support\Collection|null + * @author Qinii + * @day 10/30/21 + */ + public function updateFeedPublic(int $roomId, int $status) + { + $params = [ + 'roomId' => $roomId, + 'isFeedsPublic' => $status ? 1 : 0, + ]; + + return $this->httpPostJson('wxaapi/broadcast/room/updatefeedpublic', $params); + } + + public function goodsOnsale(int $roomId, int $goodsId, int $status) + { + $params = [ + 'roomId' => $roomId, + 'goodsId' => $goodsId, + 'onSale' => $status ? 1 : 0, + ]; + + return $this->httpPostJson('wxaapi/broadcast/goods/onsale', $params); + } +} diff --git a/crmeb/services/easywechat/broadcast/ServiceProvider.php b/crmeb/services/easywechat/broadcast/ServiceProvider.php new file mode 100644 index 00000000..8a8a36d8 --- /dev/null +++ b/crmeb/services/easywechat/broadcast/ServiceProvider.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\broadcast; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +class ServiceProvider implements ServiceProviderInterface +{ + + public function register(Container $pimple) + { + $pimple['miniBroadcast'] = function ($pimple) { + return new Client($pimple['mini_program.access_token'], $pimple['config']['mini_program']); + }; + \EasyWeChat\Core\Http::setDefaultOptions(['timeout' => 0]); + } +} diff --git a/crmeb/services/easywechat/certficates/Client.php b/crmeb/services/easywechat/certficates/Client.php new file mode 100644 index 00000000..494aca32 --- /dev/null +++ b/crmeb/services/easywechat/certficates/Client.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\certficates; + + +use crmeb\exceptions\WechatException; +use crmeb\services\easywechat\BaseClient; +use EasyWeChat\Core\AbstractAPI; +use think\exception\InvalidArgumentException; +use think\facade\Cache; + +class Client extends BaseClient +{ + public function get() + { + $driver = Cache::store('file'); + $cacheKey = '_wx_v3' . ($this->isService ? $this->app['config']['service_payment']['serial_no'] : $this->app['config']['payment']['serial_no']); + if ($driver->has($cacheKey)) { + return $driver->get($cacheKey); + } + $certficates = $this->getCertficates(); + $driver->set($cacheKey, $certficates, 3600 * 24 * 30); + return $certficates; + } + + /** + * get certficates. + * + * @return array + */ + public function getCertficates() + { + $response = $this->request('/v3/certificates', 'GET', [], false); + if (isset($response['code'])) throw new WechatException($response['message']); + $certificates = $response['data'][0]; + $certificates['certificates'] = $this->decrypt($certificates['encrypt_certificate']); + unset($certificates['encrypt_certificate']); + return $certificates; + } +} diff --git a/crmeb/services/easywechat/certficates/ServiceProvider.php b/crmeb/services/easywechat/certficates/ServiceProvider.php new file mode 100644 index 00000000..9d8bf589 --- /dev/null +++ b/crmeb/services/easywechat/certficates/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\certficates; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['certficates'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/combinePay/Client.php b/crmeb/services/easywechat/combinePay/Client.php new file mode 100644 index 00000000..d42ac3f5 --- /dev/null +++ b/crmeb/services/easywechat/combinePay/Client.php @@ -0,0 +1,265 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\combinePay; + + +use app\common\model\store\order\StoreRefundOrder; +use crmeb\services\easywechat\BaseClient; +use think\exception\ValidateException; +use think\facade\Route; +use function EasyWeChat\Payment\generate_sign; + +class Client extends BaseClient +{ + + public function handleNotify($callback) + { + $request = request(); + $success = $request->post('event_type') === 'TRANSACTION.SUCCESS'; + $data = $this->decrypt($request->post('resource', [])); + + $handleResult = call_user_func_array($callback, [json_decode($data, true), $success]); + if (is_bool($handleResult) && $handleResult) { + $response = [ + 'code' => 'SUCCESS', + 'message' => 'OK', + ]; + } else { + $response = [ + 'code' => 'FAIL', + 'message' => $handleResult, + ]; + } + + return response($response, 200, [], 'json'); + } + + public function pay($type, array $order) + { + $params = [ + 'combine_out_trade_no' => $order['order_sn'], + 'combine_mchid' => $this->app['config']['service_payment']['merchant_id'], + 'combine_appid' => $this->app['config']['app_id'], + 'scene_info' => [ + 'device_id' => 'shop system', + 'payer_client_ip' => request()->ip(), + ], + 'sub_orders' => [], + 'notify_url' => rtrim(systemConfig('site_url'), '/') . Route::buildUrl($this->app['config']['service_payment']['type'] . 'CombinePayNotify', ['type' => $order['attach']])->build(), + ]; + + if ($type === 'h5') { + $params['scene_info']['h5_info'] = [ + 'type' => $order['h5_type'] ?? 'Wap' + ]; + } + + foreach ($order['sub_orders'] as $sub_order) { + $subOrder = [ + 'mchid' => $this->app['config']['service_payment']['merchant_id'], + 'amount' => [ + 'total_amount' => intval($sub_order['pay_price'] * 100), + 'currency' => 'CNY', + ], + 'settle_info' => [ + 'profit_sharing' => true + ], + 'out_trade_no' => $sub_order['order_sn'], + 'sub_mchid' => $sub_order['sub_mchid'] + ]; + $subOrder['attach'] = $sub_order['attach'] ?? $order['attach'] ?? ''; + $subOrder['description'] = $sub_order['body'] ?? $order['body'] ?? ''; + $params['sub_orders'][] = $subOrder; + } + + if (isset($order['openid'])) { + $params['combine_payer_info'] = [ + 'openid' => $order['openid'], + ]; + } + $content = json_encode($params, JSON_UNESCAPED_UNICODE); + + $res = $this->request('/v3/combine-transactions/' . $type, 'POST', ['sign_body' => $content]); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function payApp(array $options) + { + $res = $this->pay('app', $options); + return $this->configForAppPayment($res['prepay_id']); + } + + /** + * @param string $type 场景类型,枚举值: iOS:IOS移动应用; Android:安卓移动应用; Wap:WAP网站应用 + */ + public function payH5(array $options, $type = 'Wap') + { + $options['h5_type'] = $type; + return $this->pay('h5', $options); + } + + public function payJs($openId, array $options) + { + $options['openid'] = $openId; + $res = $this->pay('jsapi', $options); + return $this->configForJSSDKPayment($res['prepay_id']); + } + + public function payNative(array $options) + { + return $this->pay('native', $options); + } + + public function profitsharingOrder(array $options, bool $finish = false) + { + $params = [ + 'appid' => $this->app['config']['app_id'], + 'sub_mchid' => $options['sub_mchid'], + 'transaction_id' => $options['transaction_id'], + 'out_order_no' => $options['out_order_no'], + 'receivers' => [], + 'finish' => $finish + ]; + + foreach ($options['receivers'] as $receiver) { + $data = [ + 'amount' => intval($receiver['amount'] * 100), + 'description' => $receiver['body'] ?? $options['body'] ?? '', + ]; + $data['receiver_account'] = $receiver['receiver_account']; + if (isset($receiver['receiver_name'])) { + $data['receiver_name'] = $receiver['receiver_name']; + $data['type'] = 'PERSONAL_OPENID'; + } else { + $data['type'] = 'MERCHANT_ID'; + } + $params['receivers'][] = $data; + } + $content = json_encode($params); + $res = $this->request('/v3/ecommerce/profitsharing/orders', 'POST', ['sign_body' => $content]); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function profitsharingFinishOrder(array $params) + { + $content = json_encode($params); + $res = $this->request('/v3/ecommerce/profitsharing/finish-order', 'POST', ['sign_body' => $content]); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function payOrderRefund(string $order_sn, array $options) + { + $params = [ + 'sub_mchid' => $options['sub_mchid'], + 'sp_appid' => $this->app['config']['app_id'], + 'out_trade_no' => $options['order_sn'], + 'out_refund_no' => $options['refund_order_sn'], + 'amount' => [ + 'refund' => intval($options['refund_price'] * 100), + 'total' => intval($options['pay_price'] * 100), + 'currency' => 'CNY' + ] + ]; + if (isset($options['reason'])) { + $params['reason'] = $options['reason']; + } + if (isset($options['refund_account'])) { + $params['refund_account'] = $options['refund_account']; + } + $content = json_encode($params); + $res = $this->request('/v3/ecommerce/refunds/apply', 'POST', ['sign_body' => $content], true); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function returnAdvance($refund_id, $sub_mchid) + { + $res = $this->request('/v3/ecommerce/refunds/' . $refund_id . '/return-advance', 'POST', ['sign_body' => json_encode(compact('sub_mchid'))], true); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function configForPayment($prepayId, $json = true) + { + $params = [ + 'appId' => $this->app['config']['app_id'], + 'timeStamp' => strval(time()), + 'nonceStr' => uniqid(), + 'package' => "prepay_id=$prepayId", + 'signType' => 'RSA', + ]; + $message = $params['appId'] . "\n" . + $params['timeStamp'] . "\n" . + $params['nonceStr'] . "\n" . + $params['package'] . "\n"; + openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption'); + $sign = base64_encode($raw_sign); + + $params['paySign'] = $sign; + + return $json ? json_encode($params) : $params; + } + + /** + * Generate app payment parameters. + * + * @param string $prepayId + * + * @return array + */ + public function configForAppPayment($prepayId) + { + $params = [ + 'appid' => $this->app['config']['app_id'], + 'partnerid' => $this->app['config']['service_payment']['merchant_id'], + 'prepayid' => $prepayId, + 'noncestr' => uniqid(), + 'timestamp' => time(), + 'package' => 'Sign=WXPay', + ]; + $message = $params['appid'] . "\n" . + $params['timestamp'] . "\n" . + $params['noncestr'] . "\n" . + $params['prepayid'] . "\n"; + openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption'); + $sign = base64_encode($raw_sign); + + $params['sign'] = $sign; + + return $params; + } + + public function configForJSSDKPayment($prepayId) + { + $config = $this->configForPayment($prepayId, false); + + $config['timestamp'] = $config['timeStamp']; + unset($config['timeStamp']); + + return $config; + } + +} diff --git a/crmeb/services/easywechat/combinePay/ServiceProvider.php b/crmeb/services/easywechat/combinePay/ServiceProvider.php new file mode 100644 index 00000000..5fd34e1d --- /dev/null +++ b/crmeb/services/easywechat/combinePay/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\combinePay; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['combinePay'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/merchant/Client.php b/crmeb/services/easywechat/merchant/Client.php new file mode 100644 index 00000000..050813c4 --- /dev/null +++ b/crmeb/services/easywechat/merchant/Client.php @@ -0,0 +1,206 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\merchant; + +use crmeb\services\easywechat\BaseClient; +use think\exception\ValidateException; + +/** + * Class Client. + * + * @author ClouderSky + */ +class Client extends BaseClient +{ + + /** + * TODO 二级商户进件成为微信支付商户 + * @param $params + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function submitApplication($params) + { + $params = $this->processParams($params); + $res = $this->request('/v3/ecommerce/applyments/', 'POST', ['sign_body' => json_encode($params, JSON_UNESCAPED_UNICODE)], true); + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 申请单ID查询申请状态 + * @param $id + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function getApplicationById($id) + { + $url = '/v3/ecommerce/applyments/'.$id; + $res = $this->request($url, 'GET'); + + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 业务申请编号查询申请状 + * @param $no + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function getApplicationByNo($no) + { + $url = '/v3/ecommerce/applyments/out-request-no/'.$no; + $res = $this->request($url, 'GET'); + + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 修改结算账号 + * @param $mchid + * @param $params + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function updateSubMerchat($mchid,$params) + { + $url = "/v3/apply4sub/sub_merchants/{$mchid}/modify-settlement"; + $res = $this->request($url, 'POST',['sign_body' => json_encode($params, JSON_UNESCAPED_UNICODE)], true); + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 查询结算账户 + * @param $mchid + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function getSubMerchant($mchid) + { + $url = "/v3/apply4sub/sub_merchants/{$mchid}/settlement"; + $res = $this->request($url, 'GET'); + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 添加分账接收方 + * @param array $params + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function profitsharingAdd(array $params) + { + $url = '/v3/ecommerce/profitsharing/receivers/add'; + + $app_id = !empty($this->app->config->app_id) ? $this->app->config->app_id : $this->app->config->routine_appId; + + $params['appid'] = $app_id; + + $options['sign_body'] = json_encode($params,JSON_UNESCAPED_UNICODE); + + $res = $this->request($url, 'POST',$options,true); + + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 删除分账接收方 + * @param array $params + * @return mixed + * @author Qinii + * @day 6/24/21 + */ + public function profitsharingDel(array $params) + { + $url = '/v3/ecommerce/profitsharing/receivers/delete'; + + $app_id = !empty($this->app->config->app_id) ? $this->app->config->app_id : $this->app->config->routine_appId; + + $params['appid'] = $app_id; + + $options['sign_body'] = json_encode($params,JSON_UNESCAPED_UNICODE); + + $res = $this->request($url, 'POST',$options,true); + + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + } + + /** + * TODO 上传图片 + * @param $filepath + * @param $filename + * @author Qinii + * @day 6/21/21 + */ + public function upload($filepath,$filename) + { + + $boundary = uniqid(); + try{ + // $file = file_get_contents($filepath); + $file = fread(fopen($filepath,'r'),filesize($filepath)); + }catch (\Exception $exception){ + throw new ValidateException($exception->getMessage()); + } + + + $options['headers'] = ['Content-Type' => 'multipart/form-data;boundary='.$boundary]; + + $options['sign_body'] = json_encode(['filename' => $filename,'sha256' => hash_file("sha256",$filepath)]); + + $boundaryStr = "--{$boundary}\r\n"; + + $body = $boundaryStr; + $body .= 'Content-Disposition: form-data; name="meta"'."\r\n"; + $body .= 'Content-Type: application/json'."\r\n"; + $body .= "\r\n"; + $body .= $options['sign_body']."\r\n"; + $body .= $boundaryStr; + $body .= 'Content-Disposition: form-data; name="file"; filename="'.$filename.'"'."\r\n"; + $body .= 'Content-Type: image/jpeg'.';'."\r\n"; + $body .= "\r\n"; + $body .= $file."\r\n"; + $body .= "--{$boundary}--"; + + $options['data'] = (($body)); + + try { + $res = $this->request('/v3/merchant/media/upload', 'POST', $options, true); + }catch(\Exception $exception){ + throw new ValidateException($exception->getMessage()); + } + + if(isset($res['code'])) throw new ValidateException('[微信接口返回]:' . $res['message']); + + return $res; + + } +} diff --git a/crmeb/services/easywechat/merchant/ServiceProvider.php b/crmeb/services/easywechat/merchant/ServiceProvider.php new file mode 100644 index 00000000..fd32fcd0 --- /dev/null +++ b/crmeb/services/easywechat/merchant/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\merchant; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['sub_merchant'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/miniPayment/Client.php b/crmeb/services/easywechat/miniPayment/Client.php new file mode 100644 index 00000000..3a6bed48 --- /dev/null +++ b/crmeb/services/easywechat/miniPayment/Client.php @@ -0,0 +1,101 @@ +merchant = $merchant; + } + + /** + * 支付 + * @param array $params [ + * 'openid'=>'支付者的openid', + * 'out_trade_no'=>'商家合单支付总交易单号', + * 'total_fee'=>'支付金额', + * 'wx_out_trade_no'=>'商家交易单号', + * 'body'=>'商品描述', + * 'attach'=>'支付类型', //product 产品 member 会员 + * ] + * @param $isContract + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function createorder($order) + { + $params = [ + 'openid' => $order['openid'], // 支付者的openid + 'combine_trade_no' => $order['out_trade_no'], // 商家合单支付总交易单号 + 'expire_time' => time() + $this->expire_time, + 'sub_orders' => [ + [ + 'mchid' => $this->merchant->merchant_id, + 'amount' => (int)$order['total_fee'], + 'trade_no' => $order['out_trade_no'], + 'description' => $order['body'] + ] + ] + ]; + return $this->parseJSON('post', [self::API_SET_CREATE_ORDER, json_encode($params)]); + } + + /** + * 退款 + * @param array $params [ + * 'openid'=>'退款者的openid', + * 'trade_no'=>'商家交易单号', + * 'transaction_id'=>'支付单号', + * 'refund_no'=>'商家退款单号', + * 'total_amount'=>'订单总金额', + * 'refund_amount'=>'退款金额', //product 产品 member 会员 + * ] + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function refund($orderNo, $refundNo, $totalFee, $refundFee,$openId,$transactionId) + { + $params = [ + 'openid' => $openId, + 'mchid' => $this->merchant->merchant_id, + 'trade_no' => $orderNo, + 'transaction_id' => $transactionId, + 'refund_no' => $refundNo, + 'total_amount' => $totalFee, + 'refund_amount' => $refundFee, + ]; + return $this->parseJSON('post', [self::API_SET_REFUND_ORDER, json_encode($params)]); + } + + +} diff --git a/crmeb/services/easywechat/miniPayment/ServiceProvider.php b/crmeb/services/easywechat/miniPayment/ServiceProvider.php new file mode 100644 index 00000000..6b32eaa2 --- /dev/null +++ b/crmeb/services/easywechat/miniPayment/ServiceProvider.php @@ -0,0 +1,52 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\miniPayment; + +use EasyWeChat\Payment\Merchant; +use Pimple\Container; +use Pimple\ServiceProviderInterface; +use EasyWeChat\MiniProgram\AccessToken; + +/** + * Class ServiceProvider. + * + * @author mingyoung + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['merchant'] = function ($pimple) { + $config = array_merge( + ['app_id' => $pimple['config']['app_id']], + $pimple['config']->get('payment', []) + ); + + return new Merchant($config); + }; + + $pimple['mini_program.access_token'] = function ($pimple) { + return new AccessToken( + $pimple['config']['mini_program']['app_id'], + $pimple['config']['mini_program']['secret'], + $pimple['cache'] + ); + }; + + $pimple['minipay'] = function ($pimple) { + return new Client($pimple['mini_program.access_token'],$pimple['merchant']); + }; + } +} diff --git a/crmeb/services/easywechat/msgseccheck/Client.php b/crmeb/services/easywechat/msgseccheck/Client.php new file mode 100644 index 00000000..fe8ec3bf --- /dev/null +++ b/crmeb/services/easywechat/msgseccheck/Client.php @@ -0,0 +1,113 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\msgseccheck; + +use crmeb\services\easywechat\BaseClient; +use EasyWeChat\Core\AbstractAPI; +use EasyWeChat\Core\AccessToken; +use EasyWeChat\Core\Exceptions\HttpException; +use EasyWeChat\Core\Http; +use EasyWeChat\Payment\API; +use EasyWeChat\Payment\Merchant; +use GuzzleHttp\HandlerStack; +use think\Exception; +use EasyWeChat\Support\XML; +use EasyWeChat\Support\Collection; +use Psr\Http\Message\ResponseInterface; +use think\exception\ValidateException; + +/** + * Class Client. + * + * @author ClouderSky + */ +class Client extends BaseClient +{ + protected $isService = false; + + const MSG_API = 'https://api.weixin.qq.com/wxa/msg_sec_check?access_token='; + const MEDIA_API = 'https://api.weixin.qq.com/wxa/media_check_async?access_token='; + const LABEL = [ + 100 => '正常', + 10001 => '广告', + 20001 => '时政', + 20002 => '色情', + 20003 => '辱骂', + 20006 => '违法犯罪', + 20008 => '欺诈', + 20012 => '低俗', + 20013 => '版权', + 21000 => '其他' + ]; + + public function msgSecCheck($content, $scene, $openId) + { + $access_token = $this->accessToken->getToken(); + //scene 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志) + $_url = self::MSG_API.$access_token; + $params = [ + 'content' => $content, + 'version' => (int)2, + 'scene' => (int)$scene, + 'openid' => $openId, + ]; + + try{ + $res = $this->parseJSON('json',[$_url, $params]); + if (isset($res->errcode) && $res->errcode == 0) { + if($res->result['label'] == 100) { + return true; + } else { + throw new ValidateException('内容包含:【'.self::LABEL[$res->result['label']].'】无法发布'); + } + } + }catch (Exception $exception) { + throw new ValidateException($exception->getMessage()); + } + } + + + /** + * TODO 图片或音频是异步回调,暂未使用 + * @param $media_url + * @param $scene + * @param $openId + * @param $media_type + * @return bool + * @author Qinii + * @day 2023/2/1 + */ + public function mediaSecCheck($media_url,$scene,$openId,$media_type) + { + $access_token = $this->accessToken->getToken(); + //$media_type 1:音频;2:图片 + //scene 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志) + $params = [ + 'media_url' => $media_url, + 'media_type' => $media_type, + 'version' => (int)2, + 'scene' => (int)$scene, + 'openid' => $openId, + ]; + $_url = self::MEDIA_API.$access_token; + try{ + $res = $this->parseJSON('json',[$_url, $params]); + if (isset($res->errcode) && $res->errcode == 0) { + return true; + } else { + throw new ValidateException($res->errmsg); + } + }catch (Exception $exception) { + throw new ValidateException($exception->getMessage()); + } + } +} diff --git a/crmeb/services/easywechat/msgseccheck/ServiceProvider.php b/crmeb/services/easywechat/msgseccheck/ServiceProvider.php new file mode 100644 index 00000000..4655b810 --- /dev/null +++ b/crmeb/services/easywechat/msgseccheck/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\msgseccheck; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['msgSec'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/pay/Client.php b/crmeb/services/easywechat/pay/Client.php new file mode 100644 index 00000000..881b4f36 --- /dev/null +++ b/crmeb/services/easywechat/pay/Client.php @@ -0,0 +1,201 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\pay; + + +use crmeb\services\easywechat\BaseClient; +use think\exception\ValidateException; +use think\facade\Log; + +class Client extends BaseClient +{ + + protected $isService = false; + + public function handleNotify($callback) + { + $request = request(); + $success = $request->post('event_type') === 'TRANSACTION.SUCCESS'; + $data = $this->decrypt($request->post('resource', [])); + + $handleResult = call_user_func_array($callback, [json_decode($data, true), $success]); + if (is_bool($handleResult) && $handleResult) { + $response = [ + 'code' => 'SUCCESS', + 'message' => 'OK', + ]; + } else { + $response = [ + 'code' => 'FAIL', + 'message' => $handleResult, + ]; + } + + return response($response, 200, [], 'json'); + } + + public function pay($type, $order) + { + + $params = [ + 'appid' => $this->app['config']['app_id'], + 'mchid' => $this->app['config']['payment']['merchant_id'], + 'description' => $order['body'], + 'out_trade_no' => $order['out_trade_no'], + 'attach' => $order['attach'], + 'notify_url' => $this->app['config']['payment']['notify_url'], + 'amount' => [ + 'total' => intval($order['total_fee']), + 'currency' => 'CNY' + ], + 'scene_info' => [ + 'device_id' => 'shop system', + 'payer_client_ip' => request()->ip(), + ], + ]; + + if ($type === 'h5') { + $params['scene_info']['h5_info'] = [ + 'type' => $order['h5_type'] ?? 'Wap' + ]; + } + + if (isset($order['openid'])) { + $params['payer'] = [ + 'openid' => $order['openid'] + ]; + } + Log::info('微信v3支付:'.var_export($params,true)); + $content = json_encode($params, JSON_UNESCAPED_UNICODE); + + $res = $this->request('/v3/pay/transactions/' . $type, 'POST', ['sign_body' => $content]); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function payApp($options) + { + $res = $this->pay('app', $options); + return $this->configForAppPayment($res['prepay_id']); + } + + /** + * @param string $type 场景类型,枚举值: iOS:IOS移动应用; Android:安卓移动应用; Wap:WAP网站应用 + */ + public function payH5($options, $type = 'Wap') + { + $options['h5_type'] = $type; + return $this->pay('h5', $options); + } + + public function payJsapi($options) + { + $res = $this->pay('jsapi', $options); + return $this->configForJSSDKPayment($res['prepay_id']); + } + + public function payNative($options) + { + unset($options['openid']); + return $this->pay('native', $options); + } + + public function refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId = null, $type, $refundAccount, $refundReason) + { + $params = [ + $type => $orderNo, + 'out_refund_no' => $refundNo, + 'amount' => [ + 'refund' => intval($refundFee), + 'total' => intval($totalFee), + 'currency' => 'CNY' + ] + ]; + + if (isset($refundReason)) { + $params['reason'] = $refundReason; + } +// if (isset($refundAccount)) { +// $params['refund_account'] = $refundAccount; +// } + $content = json_encode($params); + $res = $this->request('/v3/refund/domestic/refunds', 'POST', ['sign_body' => $content], true); + if (isset($res['code'])) { + throw new ValidateException('微信接口报错:' . $res['message']); + } + return $res; + } + + public function configForPayment($prepayId, $json = true) + { + $params = [ + 'appId' => $this->app['config']['app_id'], + 'timeStamp' => strval(time()), + 'nonceStr' => uniqid(), + 'package' => "prepay_id=$prepayId", + 'signType' => 'RSA', + ]; + $message = $params['appId'] . "\n" . + $params['timeStamp'] . "\n" . + $params['nonceStr'] . "\n" . + $params['package'] . "\n"; + openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption'); + $sign = base64_encode($raw_sign); + + $params['paySign'] = $sign; + + return $json ? json_encode($params) : $params; + } + + /** + * Generate app payment parameters. + * + * @param string $prepayId + * + * @return array + */ + public function configForAppPayment($prepayId) + { + $params = [ + 'appid' => $this->app['config']['app_id'], + 'partnerid' => $this->app['config']['payment']['merchant_id'], + 'prepayid' => $prepayId, + 'noncestr' => uniqid(), + 'timestamp' => time(), + 'package' => 'Sign=WXPay', + ]; + $message = $params['appid'] . "\n" . + $params['timestamp'] . "\n" . + $params['noncestr'] . "\n" . + $params['prepayid'] . "\n"; + openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption'); + $sign = base64_encode($raw_sign); + + $params['sign'] = $sign; + + return $params; + } + + public function configForJSSDKPayment($prepayId) + { + $config = $this->configForPayment($prepayId, false); + + $config['timestamp'] = $config['timeStamp']; + unset($config['timeStamp']); + + return $config; + } + +} diff --git a/crmeb/services/easywechat/pay/ServiceProvider.php b/crmeb/services/easywechat/pay/ServiceProvider.php new file mode 100644 index 00000000..5beeffed --- /dev/null +++ b/crmeb/services/easywechat/pay/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\pay; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['v3Pay'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/storePay/Client.php b/crmeb/services/easywechat/storePay/Client.php new file mode 100644 index 00000000..be99b028 --- /dev/null +++ b/crmeb/services/easywechat/storePay/Client.php @@ -0,0 +1,59 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\storePay; + +use crmeb\services\easywechat\BaseClient; +use EasyWeChat\Core\AbstractAPI; +use EasyWeChat\Core\AccessToken; +use EasyWeChat\Core\Exceptions\HttpException; +use EasyWeChat\Core\Http; +use EasyWeChat\Payment\API; +use EasyWeChat\Payment\Merchant; +use GuzzleHttp\HandlerStack; +use think\Exception; +use EasyWeChat\Support\XML; +use EasyWeChat\Support\Collection; +use Psr\Http\Message\ResponseInterface; +use think\exception\ValidateException; + +/** + * Class Client. + * + * @author ClouderSky + */ +class Client extends BaseClient +{ + const API = 'https://api.mch.weixin.qq.com'; + + public function transferBatches(array $data) + { + $api = '/v3/transfer/batches'; + $params = [ + "appid" => $this->app['config']['app_id'], + "out_batch_no" => "plfk2020042013", + "batch_name" => "分销明细", + "batch_remark" => "分销明细", + "total_amount" => 100, + "total_num" => 1, + "transfer_detail_list" => [ + [ + "openid" => "oOdvCvjvCG0FnCwcMdDD_xIODRO0", + "out_detail_no" => "x23zy545Bd5436", + "transfer_amount" => 100, + "transfer_remark" => "分销明细", + ] + ], + ]; + $res = $this->request($api, 'POST', ['sign_body' => json_encode($params, JSON_UNESCAPED_UNICODE)], true); + } + +} diff --git a/crmeb/services/easywechat/storePay/ServiceProvider.php b/crmeb/services/easywechat/storePay/ServiceProvider.php new file mode 100644 index 00000000..938d8fd2 --- /dev/null +++ b/crmeb/services/easywechat/storePay/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace crmeb\services\easywechat\storePay; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author ClouderSky + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $pimple) + { + $pimple['storePay'] = function ($pimple) { + return new Client($pimple['access_token'], $pimple); + }; + } +} diff --git a/crmeb/services/easywechat/subscribe/ProgramProvider.php b/crmeb/services/easywechat/subscribe/ProgramProvider.php new file mode 100644 index 00000000..57d0273b --- /dev/null +++ b/crmeb/services/easywechat/subscribe/ProgramProvider.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\subscribe; + +use EasyWeChat\MiniProgram\AccessToken; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * 注册订阅消息 + * Class ProgramProvider + * @package crmeb\utils + */ +class ProgramProvider implements ServiceProviderInterface +{ + public function register(Container $pimple) + { + $pimple['mini_program.access_token'] = function ($pimple) { + return new AccessToken( + $pimple['config']['mini_program']['app_id'], + $pimple['config']['mini_program']['secret'], + $pimple['cache'] + ); + }; + + $pimple['mini_program.now_notice'] = function ($pimple) { + return new ProgramSubscribe($pimple['mini_program.access_token']); + }; + } +} diff --git a/crmeb/services/easywechat/subscribe/ProgramSubscribe.php b/crmeb/services/easywechat/subscribe/ProgramSubscribe.php new file mode 100644 index 00000000..993c66a1 --- /dev/null +++ b/crmeb/services/easywechat/subscribe/ProgramSubscribe.php @@ -0,0 +1,285 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\easywechat\subscribe; + +use EasyWeChat\Core\AbstractAPI; +use EasyWeChat\Core\AccessToken; +use EasyWeChat\Core\Exceptions\InvalidArgumentException; + +/** + * 小程序订阅消息 + * Class ProgramSubscribe + * @package crmeb\utils + * @method $this + * @method $this template(string $template_id) 设置模板id + * @method $this withTemplateId(string $template_id) 设置模板id + * @method $this andTemplateId(string $template_id) 设置模板id + * @method $this andTemplate(string $template_id) 设置模板id + * @method $this andUses(string $template_id) 设置模板id + * @method $this to(string $touser) 设置opendid + * @method $this andReceiver(string $touser) 设置opendid + * @method $this withReceiver(string $touser) 设置opendid + * @method $this with(array $data) 设置发送内容 + * @method $this andData(array $data) 设置发送内容 + * @method $this withData(array $data) 设置发送内容 + * @method $this data(array $data) 设置发送内容 + * @method $this withUrl(string $page) 设置跳转路径 + */ +class ProgramSubscribe extends AbstractAPI +{ + + /** + * 添加模板接口 + */ + const API_SET_TEMPLATE_ADD = 'https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate'; + + /** + * 删除模板消息接口 + */ + const API_SET_TEMPLATE_DEL = 'https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate'; + + /** + * 获取模板消息列表 + */ + const API_GET_TEMPLATE_LIST = 'https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate'; + + /** + * 获取模板消息分类 + */ + const API_GET_TEMPLATE_CATE = 'https://api.weixin.qq.com/wxaapi/newtmpl/getcategory'; + + /** + * 获取模板消息关键字 + */ + const API_GET_TEMPLATE_KEYWORKS = 'https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords'; + + /** + * 获取公共模板 + */ + const API_GET_PUBLIC_TEMPLATE = 'https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatetitles'; + + /** + * 发送模板消息 + */ + const API_SUBSCRIBE_SEND = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send'; + + /** + * Attributes + * @var array + */ + protected $message = [ + 'touser' => '', + 'template_id' => '', + 'page' => '', + 'data' => [], + ]; + + /** + * Message backup. + * + * @var array + */ + protected $messageBackup; + + protected $required = ['template_id', 'touser']; + + /** + * ProgramSubscribeService constructor. + * @param AccessToken $accessToken + */ + public function __construct(AccessToken $accessToken) + { + parent::__construct($accessToken); + + $this->messageBackup = $this->message; + + } + + /** + * 获取当前拥有的模板列表 + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getTemplateList() + { + return $this->parseJSON('get', [self::API_GET_TEMPLATE_LIST]); + } + + /** + * 获取公众模板列表 + * @param string $ids + * @param int $start + * @param int $limit + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getPublicTemplateList(string $ids, int $start = 0, int $limit = 10) + { + $params = [ + 'ids' => $ids, + 'start' => $start, + 'limit' => $limit + ]; + return $this->parseJSON('get', [self::API_GET_PUBLIC_TEMPLATE, $params]); + } + + /** + * 获取模板分类 + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getTemplateCate() + { + return $this->parseJSON('get', [self::API_GET_TEMPLATE_CATE]); + } + + /** + * 获取模板标题下的关键词列表 + * @param string $tid 模板标题 id,可通过接口获取 + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function getPublicTemplateKeywords(string $tid) + { + $params = [ + 'tid' => $tid + ]; + return $this->parseJSON('get', [self::API_GET_TEMPLATE_KEYWORKS, $params]); + } + + /** + * 添加订阅模板消息 + * @param string $tid 模板标题 id,可通过接口获取,也可登录小程序后台查看获取 + * @param array $kidList 模板序列号 关键词顺序可以自由搭配(例如 [3,5,4] 或 [4,5,3]),最多支持5个,最少2个关键词组合 + * @param string $sceneDesc 服务场景描述,15个字以内 + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function addTemplate(string $tid, array $kidList, string $sceneDesc = '') + { + $params = [ + 'tid' => $tid, + 'kidList' => $kidList, + 'sceneDesc' => $sceneDesc, + ]; + return $this->parseJSON('json', [self::API_SET_TEMPLATE_ADD, $params]); + } + + /** + * 删除模板消息 + * @param string $priTmplId + * @return \EasyWeChat\Support\Collection|null + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function delTemplate(string $priTmplId) + { + $params = [ + 'priTmplId' => $priTmplId + ]; + return $this->parseJSON('json', [self::API_SET_TEMPLATE_DEL, $params]); + } + + /** + * 发送订阅消息 + * @param array $data + * @return \EasyWeChat\Support\Collection|null + * @throws InvalidArgumentException + * @throws \EasyWeChat\Core\Exceptions\HttpException + */ + public function send(array $data = []) + { + $params = array_merge($this->message, $data); + + foreach ($params as $key => $value) { + if (in_array($key, $this->required, true) && empty($value) && empty($this->message[$key])) { + throw new InvalidArgumentException("Attribute '$key' can not be empty!"); + } + + $params[$key] = empty($value) ? $this->message[$key] : $value; + } + + $params['data'] = $this->formatData($params['data']); + + $this->message = $this->messageBackup; + + return $this->parseJSON('json', [self::API_SUBSCRIBE_SEND, $params]); + } + + /** + * 设置订阅消息发送data + * @param array $data + * @return array + */ + protected function formatData(array $data) + { + $return = []; + + foreach ($data as $key => $item) { + if (is_scalar($item)) { + $value = $item; + } elseif (is_array($item) && !empty($item)) { + if (isset($item['value'])) { + $value = strval($item['value']); + } elseif (count($item) < 2) { + $value = array_shift($item); + } else { + [$value] = $item; + } + } else { + $value = 'error data item.'; + } + + $return[$key] = ['value' => $value]; + } + + return $return; + } + + + /** + * Magic access.. + * + * @param $method + * @param $args + * @return $this + */ + public function __call($method, $args) + { + $map = [ + 'template' => 'template_id', + 'templateId' => 'template_id', + 'uses' => 'template_id', + 'to' => 'touser', + 'receiver' => 'touser', + 'url' => 'page', + 'link' => 'page', + 'data' => 'data', + 'with' => 'data', + ]; + + if (0 === stripos($method, 'with') && strlen($method) > 4) { + $method = lcfirst(substr($method, 4)); + } + + if (0 === stripos($method, 'and')) { + $method = lcfirst(substr($method, 3)); + } + + if (isset($map[$method])) { + $this->message[$map[$method]] = array_shift($args); + } + + return $this; + } + +} diff --git a/crmeb/services/express/Express.php b/crmeb/services/express/Express.php new file mode 100644 index 00000000..de85316a --- /dev/null +++ b/crmeb/services/express/Express.php @@ -0,0 +1,62 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\express; + + +use crmeb\basic\BaseManager; +use crmeb\services\AccessTokenServeService; +use think\Container; +use think\facade\Config; + +/** + * Class Express + * @package crmeb\services\express + * @mixin \crmeb\services\express\storage\Express + */ +class Express extends BaseManager +{ + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\express\\storage\\'; + + /** + * 默认驱动 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('express.default', 'express'); + } + + /** + * 获取类的实例 + * @param $class + * @return mixed|void + */ + protected function invokeClass($class) + { + if (!class_exists($class)) { + throw new \RuntimeException('class not exists: ' . $class); + } + $this->getConfigFile(); + + if (!$this->config) { + $this->config = Config::get($this->configFile . '.stores.' . $this->name, []); + } + $handleAccessToken = new AccessTokenServeService($this->config['account'] ?? '', $this->config['secret'] ?? '', app()->cache); + $handle = Container::getInstance()->invokeClass($class, [$this->name, $handleAccessToken, $this->configFile]); + $this->config = []; + return $handle; + } +} diff --git a/crmeb/services/express/storage/Express.php b/crmeb/services/express/storage/Express.php new file mode 100644 index 00000000..8dd39ff4 --- /dev/null +++ b/crmeb/services/express/storage/Express.php @@ -0,0 +1,175 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\express\storage; + +use app\common\repositories\store\shipping\ExpressPartnerRepository; +use app\common\repositories\store\shipping\ExpressRepository; +use app\common\repositories\system\merchant\MerchantRepository; +use crmeb\services\AccessTokenServeService; +use crmeb\services\BaseExpress; +use think\exception\ValidateException; + +/** + * Class Express + * @package crmeb\services\express\storage + */ +class Express extends BaseExpress +{ + /** + * 注册服务 + */ + const EXPRESS_OPEN = 'expr/open'; + + /** + * 电子面单模版 + */ + const EXPRESS_TEMP = 'expr/temp'; + + /** + * 快递公司 + */ + const EXPRESS_LIST = 'expr/express'; + + /** + * 快递查询 + */ + const EXPRESS_QUERY = 'expr/query'; + + /** + * 面单打印 + */ + const EXPRESS_DUMP = 'expr/dump'; + + /** 初始化 + * @param array $config + * @return mixed|void + */ + + protected function initialize(array $config = []) + { + parent::initialize($config); // TODO: Change the autogenerated stub + } + + /** + * 开通物流服务 + * @return bool|mixed + */ + public function open() + { + return $this->accessToken->httpRequest(self::EXPRESS_OPEN, []); + } + + /** + * 获取电子面单模版 + * @param $com 快递公司编号 + * @param int $page + * @param int $limit + * @return bool|mixed + */ + public function temp(string $com) + { + $param = [ + 'com' => $com + ]; + + return $this->accessToken->httpRequest(self::EXPRESS_TEMP, $param); + } + + /** + * 获取物流公司列表 + * @param int $type 快递类型:1,国内运输商;2,国际运输商;3,国际邮政 + * @return bool|mixed + */ + public function express(int $type = 0, int $page = 0, int $limit = 20) + { + $param = []; + if ($type) $param['type'] = $type; + return $this->accessToken->httpRequest(self::EXPRESS_LIST, $param); + } + + /** + * 查询物流信息 + * @param $com + * @param $num + * @return bool|mixed + * @return 是否签收 ischeck + * @return 物流状态:status 0在途,1揽收,2疑难,3签收,4退签,5派件,6退回,7转单,10待清关,11清关中,12已清关,13清关异常,14收件人拒签 + * @return 物流详情 content + */ + public function query(string $num, string $com = '') + { + $param = [ + 'com' => $com, + 'num' => $num + ]; + if ($com === null) { + unset($param['com']); + } + return $this->accessToken->httpRequest(self::EXPRESS_QUERY, $param); + } + + /** + * 电子面单打印 + * @param array $data 必需参数: com(快递公司编码)、to_name(寄件人)、to_tel(寄件人电话)、to_addr(寄件人详细地址)、from_name(收件人)、from_tel(收件人电话)、from_addr(收件人地址)、temp_id(电子面单模板ID)、siid(云打印机编号)、count(商品数量) + * @return bool|mixed + */ + public function dump($merId,$data) + { + $param = $data; + $param['com'] = $data['com'] ?? ''; + if (!$param['com']) throw new ValidateException('快递公司编码缺失'); + $param['to_name'] = $data['to_name'] ?? ''; + $param['to_tel'] = $data['to_tel'] ?? ''; + $param['order_id'] = $data['order_id'] ?? ''; + $param['to_addr'] = $data['to_addr'] ?? ''; + if (!$param['to_addr'] || !$param['to_tel'] || !$param['to_name']) throw new ValidateException('寄件人信息缺失'); + $param['from_name'] = $data['from_name'] ?? ''; + $param['from_tel'] = $data['from_tel'] ?? ''; + $param['from_addr'] = $data['from_addr'] ?? ''; + if (!$param['from_name'] || !$param['from_tel'] || !$param['from_addr']) throw new ValidateException('收件人信息缺失'); + $param['temp_id'] = $data['temp_id'] ?? ''; + if (!$param['temp_id']) { + throw new ValidateException('电子面单模板ID缺失'); + } + + $param['siid'] = merchantConfig($merId,'mer_config_siid'); + if (!$param['siid']) { + throw new ValidateException('云打印机编号缺失'); + } + $param['count'] = $data['count'] ?? ''; + $param['cargo'] = $data['cargo'] ?? ''; + + if (!$param['count']) { + throw new ValidateException('商品数量缺失'); + } + + $exp = app()->make(ExpressRepository::class)->getWhere(['code' => $data['com']]); + + $expressData = app()->make(ExpressPartnerRepository::class)->getSearch([ + 'express_id' => $exp['id'], + 'mer_id' => $merId, + ])->find(); + + if ($exp['partner_id'] == 1) { + if (!$expressData) throw new ValidateException('未查询到快递公司的月结账号'); + $param['partner_id'] = $expressData['account']; + } + if ($exp['partner_key'] == 1) $param['partner_key'] = $expressData['key']; + if ($exp['net'] == 1) $param['net'] = $expressData['net_name']; + if ($exp['check_man'] == 1) $param['checkMan'] = $expressData['check_man']; + if ($exp['partner_name'] == 1) $param['partner_name'] = $expressData['partner_name']; + if ($exp['is_code'] == 1) $param['code'] = $expressData['code']; + + return $this->accessToken->httpRequest(self::EXPRESS_DUMP, $param, 'POST'); + } + +} diff --git a/crmeb/services/printer/AccessToken.php b/crmeb/services/printer/AccessToken.php new file mode 100644 index 00000000..fa16bc45 --- /dev/null +++ b/crmeb/services/printer/AccessToken.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\printer; + +use crmeb\services\HttpService; +use think\facade\Config; +use think\helper\Str; +use think\facade\Cache; + +/** + * + * Class AccessToken + * @package crmeb\services\printer + */ +class AccessToken extends HttpService +{ + + /** + * token + * @var array + */ + protected $accessToken; + + /** + * 请求接口 + * @var string + */ + protected $apiUrl; + + /** + * @var string + */ + protected $clientId; + + /** + * 终端号码 + * @var string + */ + protected $machineCode; + + /** + * 开发者id + * @var string + */ + protected $partner; + + /** + * 驱动类型 + * @var string + */ + protected $name; + + /** + * 配置文件名 + * @var string + */ + protected $configFile; + + /** + * api key + * @var string + */ + protected $apiKey; + + public function __construct(array $config = [], string $name, string $configFile) + { + $this->clientId = $config['clientId'] ?? null; + $this->apiKey = $config['apiKey'] ?? null; + $this->partner = $config['partner'] ?? null; + $this->machineCode = $config['terminal'] ?? null; + $this->name = $name; + $this->configFile = $configFile; + $this->apiUrl = Config::get($this->configFile . '.stores.' . $this->name . '.apiUrl', 'https://open-api.10ss.net/'); + } + + /** + * 获取token + * @return mixed|null|string + * @throws \Exception + */ + public function getAccessToken() + { + if (isset($this->accessToken[$this->name])) { + return $this->accessToken[$this->name]; + } + + $action = 'get' . Str::studly($this->name) . 'AccessToken'; + if (method_exists($this, $action)) { + return $this->{$action}(); + } else { + throw new \RuntimeException(__CLASS__ . '->' . $action . '(),Method not worn in'); + } + } + + /** + * 获取易联云token + * @return mixed|null|string + * @throws \Exception + */ + protected function getYiLianYunAccessToken() + { + /** @var CacheServices $cacheServices */ + if(!$this->accessToken[$this->name] = Cache::get('YLY_access_token_'.$this->clientId)){ + $token = $this->getToken(); + Cache::set('YLY_access_token_'.$this->clientId,$token, 18 * 86400); + $this->accessToken[$this->name] = $token; + } + if (!$this->accessToken[$this->name]) + throw new \Exception('获取access_token获取失败'); + + return $this->accessToken[$this->name]; + } + + protected function getToken () { + $data = [ + 'client_id' => $this->clientId, + 'grant_type' => 'client_credentials', + 'sign' => strtolower(md5($this->clientId . time() . $this->apiKey)), + 'scope' => 'all', + 'timestamp' => time(), + 'id' => $this->createUuid(), + ]; + $request = self::postRequest($this->apiUrl . 'oauth/oauth',$data ); + $request = json_decode($request, true); + $request['error'] = $request['error'] ?? 0; + $request['error_description'] = $request['error_description'] ?? ''; + if ($request['error'] == 0 && $request['error_description'] == 'success') { + return $request['body']['access_token'] ?? ''; + } + + return ''; + } + + /** + * 获取请求链接 + * @return string + */ + public function getApiUrl(string $url = '') + { + return $url ? $this->apiUrl . $url : $this->apiUrl; + } + + /** + * 生成UUID4 + * @return string + */ + public function createUuid() + { + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), + mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)); + } + + /** + * 获取属性 + * @param $name + * @return mixed + */ + public function __get($name) + { + if (in_array($name, ['clientId', 'apiKey', 'accessToken', 'partner', 'terminal', 'machineCode'])) { + return $this->{$name}; + } + } +} diff --git a/crmeb/services/printer/Printer.php b/crmeb/services/printer/Printer.php new file mode 100644 index 00000000..626bfc46 --- /dev/null +++ b/crmeb/services/printer/Printer.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\printer; + +use crmeb\basic\BaseManager; +use think\facade\Config; +use think\Container; + +/** + * Class Printer + * @package crmeb\services\auth + * @mixin \crmeb\services\printer\storage\YiLianYun + */ +class Printer extends BaseManager +{ + + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\printer\\storage\\'; + + /** + * @var object + */ + protected $handleAccessToken; + + /** + * 默认驱动 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('printer.default', 'yi_lian_yun'); + } + + /** + * 获取类的实例 + * @param $class + * @return mixed|void + */ + protected function invokeClass($class) + { + if (!class_exists($class)) { + throw new \RuntimeException('class not exists: ' . $class); + } + $this->getConfigFile(); + + if (!$this->config) { + $this->config = Config::get($this->configFile . '.stores.' . $this->name, []); + } + + if (!$this->handleAccessToken) { + $this->handleAccessToken = new AccessToken($this->config, $this->name, $this->configFile); + } + + $handle = Container::getInstance()->invokeClass($class, [$this->name, $this->handleAccessToken, $this->configFile]); + $this->config = []; + return $handle; + } + +} diff --git a/crmeb/services/printer/storage/YiLianYun.php b/crmeb/services/printer/storage/YiLianYun.php new file mode 100644 index 00000000..da9eaa30 --- /dev/null +++ b/crmeb/services/printer/storage/YiLianYun.php @@ -0,0 +1,118 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\printer\storage; + +use crmeb\services\PrinterService; +use crmeb\services\printer\AccessToken; +use Exception; +use think\facade\Cache; + +/** + * Class YiLianYun + * @package crmeb\services\printer\storage + */ +class YiLianYun extends PrinterService +{ + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config) + { + + } + + /** + * 开始打印 + * @return bool|mixed|string + * @throws Exception + */ + public function startPrinter() + { + if (!$this->printerContent) { + return $this->setError('Missing print'); + } + $arr = [ + 'client_id' => $this->accessToken->clientId, + 'access_token' => $this->accessToken->getAccessToken(), + 'machine_code' => $this->accessToken->machineCode, + 'content' => $this->printerContent, + 'origin_id' => 'crmeb' . time(), + 'sign' => strtolower(md5($this->accessToken->clientId . time() . $this->accessToken->apiKey)), + 'id' => $this->accessToken->createUuid(), + 'timestamp' => time() + ]; + $request = $this->accessToken->postRequest($this->accessToken->getApiUrl('print/index'), $arr); + $info = \Qiniu\json_decode($request); + if($info->error == 18){ + Cache::delete('YLY_access_token_'.$this->accessToken->clientId); + $arr['access_token'] = $this->accessToken->getAccessToken(); + $request = $this->accessToken->postRequest($this->accessToken->getApiUrl('print/index'), $arr); + } + if ($request === false) { + return $this->setError('request was aborted'); + } + $request = is_string($request) ? json_decode($request, true) : $request; + if (isset($request['error']) && in_array($request['error'], [18, 14])) { + return $this->setError('Accesstoken has expired'); + } + return $request; + } + + /** + * 设置打印内容 + * @param array $config + * @return YiLianYun + */ + public function setPrinterContent(array $config): self + { + $timeYmd = date('Y-m-d H:i:s', time()); + $goodsStr = ''; + $product = $config['product']; + foreach ($product as $item) { + $goodsStr .= ''; + $goodsStr .= ""; + $goodsStr .= ''; + } + $goodsStr .= '
    商品名称数量单价金额
    {$item['store_name']}{$item['product_num']}{$item['price']}{$item['product_price']}
    '; + $orderInfo = $config['orderInfo']; + $name = $config['name']; + $orderType = $orderInfo['order_type'] ? "核销订单" : '普通订单'; + $this->printerContent = <<

    ** {$name} **
    +---------------- +订单类型:{$orderType}\r +订单编号:{$orderInfo['order_sn']}\r +打印时间: {$timeYmd} \r +付款时间: {$orderInfo['pay_time']}\r +姓 名: {$orderInfo['real_name']}\r +电 话: {$orderInfo['user_phone']}\r +地 址: {$orderInfo['user_address']}\r +订单备注:{$orderInfo['mark']}\r +*************商品***************\r +{$goodsStr} +********************************\r + +合计:¥{$orderInfo['total_price']},优惠: ¥{$orderInfo['coupon_price']} +邮费:¥{$orderInfo['pay_postage']} +实际支付:¥{$orderInfo['pay_price']} + +
    ** 完 **
    +CONTENT; + return $this; + } + + +} diff --git a/crmeb/services/product/Product.php b/crmeb/services/product/Product.php new file mode 100644 index 00000000..7b8263ac --- /dev/null +++ b/crmeb/services/product/Product.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\product; + +use crmeb\basic\BaseManager; +use crmeb\services\AccessTokenServeService; +use think\facade\Config; +use think\Container; + + +/** + * Class Product + * @package crmeb\services\product + * @mixin \crmeb\services\product\storage\Copy + */ +class Product extends BaseManager +{ + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\product\\storage\\'; + + /** + * 默认驱动 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('product.default', 'copy'); + } + + /** + * 获取类的实例 + * @param $class + * @return mixed|void + */ + protected function invokeClass($class) + { + if (!class_exists($class)) { + throw new \RuntimeException('class not exists: ' . $class); + } + $this->getConfigFile(); + + if (!$this->config) { + $this->config = Config::get($this->configFile . '.stores.' . $this->name, []); + } + $handleAccessToken = new AccessTokenServeService($this->config['account'] ?? '', $this->config['secret'] ?? ''); + $handle = Container::getInstance()->invokeClass($class, [$this->name, $handleAccessToken, $this->configFile]); + $this->config = []; + return $handle; + } + +} diff --git a/crmeb/services/product/storage/Copy.php b/crmeb/services/product/storage/Copy.php new file mode 100644 index 00000000..047a513d --- /dev/null +++ b/crmeb/services/product/storage/Copy.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\product\storage; + +use crmeb\services\BaseProduct; + +/** + * Class Copy + * @package crmeb\services\product\storage + */ +class Copy extends BaseProduct +{ + + /** + * 是否开通 + */ + const PRODUCT_OPEN = 'copy/open'; + /** + * 获取详情 + */ + const PRODUCT_GOODS = 'copy/goods'; + + /** 初始化 + * @param array $config + */ + protected function initialize(array $config = []) + { + parent::initialize($config); + } + + /** 是否开通复制 + * @return mixed + */ + public function open() + { + return $this->accessToken->httpRequest(self::PRODUCT_OPEN, []); + } + + /** 复制商品 + * @return mixed + */ + public function goods(string $url) + { + $param['url'] = $url; + return $this->accessToken->httpRequest(self::PRODUCT_GOODS, $param); + } + + +} diff --git a/crmeb/services/serve/Serve.php b/crmeb/services/serve/Serve.php new file mode 100644 index 00000000..431e988d --- /dev/null +++ b/crmeb/services/serve/Serve.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\serve; + + +use crmeb\basic\BaseManager; +use crmeb\services\AccessTokenServeService; +use crmeb\services\serve\storage\Crmeb; +use think\facade\Config; +use think\Container; + +/** + * Class Serve + * @package crmeb\services\serve + * @mixin Crmeb + */ +class Serve extends BaseManager +{ + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\serve\\storage\\'; + + /** + * 默认驱动 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('serve.default', 'crmeb'); + } + + /** + * 获取类的实例 + * @param $class + * @return mixed|void + */ + protected function invokeClass($class) + { + if (!class_exists($class)) { + throw new \RuntimeException('class not exists: ' . $class); + } + $this->getConfigFile(); + + if (!$this->config) { + $this->config = Config::get($this->configFile . '.stores.' . $this->name, []); + } + + $handleAccessToken = new AccessTokenServeService($this->config['account'] ?? '', $this->config['secret'] ?? ''); + $handle = Container::getInstance()->invokeClass($class, [$this->name, $handleAccessToken, $this->configFile]); + $this->config = []; + return $handle; + } +} diff --git a/crmeb/services/serve/storage/Crmeb.php b/crmeb/services/serve/storage/Crmeb.php new file mode 100644 index 00000000..417b5837 --- /dev/null +++ b/crmeb/services/serve/storage/Crmeb.php @@ -0,0 +1,174 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\serve\storage; + + +use crmeb\basic\BaseStorage; +use crmeb\services\AccessTokenServeService; +use think\exception\ValidateException; + +/** + * Class Crmeb + * @package crmeb\services\serve\storage + */ +class Crmeb extends BaseStorage +{ + + protected $accessToken; + + /** + * Crmeb constructor. + * @param string $name + * @param AccessTokenServeService $service + * @param string|null $configFile + */ + public function __construct(string $name, AccessTokenServeService $service, string $configFile = null) + { + $this->accessToken = $service; + } + + protected function initialize(array $config) + { + // TODO: Implement initialize() method. + } + + /** + * 获取用户信息 + * @param string $account + * @param string $secret + * @return array|mixed + */ + public function getUser() + { + return $this->accessToken->httpRequest('user/info'); + } + + /** + * 用户登录 + * @param string $account + * @param string $secret + * @return array|mixed + */ + public function login(string $account, string $secret) + { + return $this->accessToken->httpRequest('user/login', ['account' => $account, 'secret' => $secret], 'POST', false); + } + + /** + * 注册平台 + * @param array $data + * @return array|mixed + */ + public function register(array $data) + { + return $this->accessToken->httpRequest('user/register', $data, 'POST', false); + } + + /** + * 平台用户消息记录 + * @param int $page + * @param int $limit + * @return array|mixed + */ + public function userBill(int $page, int $limit) + { + return $this->accessToken->httpRequest('user/bill', ['page' => $page, 'limit' => $limit]); + } + + /** + * 找回账号 + * @param array $data + * @return array|mixed + */ + public function forget(array $data) + { + return $this->accessToken->httpRequest('user/forget', $data, 'POST', false); + } + + /** + * 修改密码 + * @param array $data + * @return array|mixed + */ + public function modify(array $data) + { + return $this->accessToken->httpRequest('user/modify', $data, 'POST', false); + } + + /** + * 获取验证码 + * @param string $phone + * @return array|mixed + */ + public function code(string $phone, $type = 0) + { + return $this->accessToken->httpRequest('user/code', ['phone' => $phone, 'types' => $type], 'POST', false); + } + + /** + * 验证验证码 + * @param string $phone + * @return array|mixed + */ + public function checkCode(string $phone, string $verify_code) + { + return $this->accessToken->httpRequest('user/code/verify', ['phone' => $phone, 'verify_code' => $verify_code], 'POST', false); + } + + /** + * 套餐列表 + * @param string $type 套餐类型:sms,短信;query,物流查询;dump,电子面单;copy,产品复制 + * @return array|mixed + */ + public function mealList(string $type) + { + return $this->accessToken->httpRequest('meal/list', ['type' => $type]); + } + + /** + * 套餐支付 + * @param array $data + * @return array|mixed + */ + public function payMeal(array $data) + { + return $this->accessToken->httpRequest('meal/code', $data); + } + + /** + * 用量记录 + * @param int $page + * @param int $limit + * @param int $type + * @return array|mixed + */ + public function record(int $page, int $limit, int $type, $status = '') + { + $typeContent = [1 => 'sms', 2 => 'expr_dump', 3 => 'expr_query', 4 => 'copy']; + if (!isset($typeContent[$type])) { + throw new ValidateException('参数类型不正确'); + } + $data = ['page' => $page, 'limit' => $limit, 'type' => $typeContent[$type]]; + + return $this->accessToken->httpRequest('user/record', $data); + } + + /** + * 修改手机号 + * @param array $data + * @return array|mixed + */ + public function modifyPhone(array $data) + { + return $this->accessToken->httpRequest('user/modify/phone', $data); + } +} diff --git a/crmeb/services/sms/Sms.php b/crmeb/services/sms/Sms.php new file mode 100644 index 00000000..3e2ebbc6 --- /dev/null +++ b/crmeb/services/sms/Sms.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\sms; + +use crmeb\basic\BaseManager; +use crmeb\services\AccessTokenServeService; +use think\Container; +use think\facade\Config; + + +/** + * Class Sms1 + * @package crmeb\services\sms + * @mixin Yunxin + */ +class Sms extends BaseManager +{ + + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\sms\\storage\\'; + + /** + * 默认驱动 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('sms.default', 'yunxin'); + } + + + /** + * 获取类的实例 + * @param $class + * @return mixed|void + */ + protected function invokeClass($class) + { + if (!class_exists($class)) { + throw new \RuntimeException('class not exists: ' . $class); + } + $this->getConfigFile(); + + if (!$this->config) { + $this->config = Config::get($this->configFile . '.stores.' . $this->name, []); + } + + $handleAccessToken = new AccessTokenServeService($this->config['account'] ?? '', $this->config['secret'] ?? ''); + $handle = Container::getInstance()->invokeClass($class, [$this->name, $handleAccessToken, $this->configFile]); + + $this->config = []; + return $handle; + } +} diff --git a/crmeb/services/sms/storage/Aliyun.php b/crmeb/services/sms/storage/Aliyun.php new file mode 100644 index 00000000..cc9a3477 --- /dev/null +++ b/crmeb/services/sms/storage/Aliyun.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\sms\storage; + +use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use crmeb\services\BaseSmss; +use \Exception; +use AlibabaCloud\Tea\Exception\TeaError; +use AlibabaCloud\Tea\Utils\Utils; +use Darabonba\OpenApi\Models\Config as AliConfig; +use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest; +use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions; +use think\exception\ValidateException; +use think\facade\Config; + + + +/** + * Class Aliyun + * @package crmeb\services\sms\storage + */ +class Aliyun extends BaseSmss +{ + protected $AccessKeySecret = ''; + /** + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config = []) + { + + parent::initialize($config); + } + + public static function createClient($accessKeyId, $accessKeySecret){ + $config = new AliConfig([ + // 您的 AccessKey ID + "accessKeyId" => systemConfig('aliyun_AccessKeyId'), + // 您的 AccessKey Secret + "accessKeySecret" => systemConfig('aliyun_AccessKeySecret') + ]); + // 访问的域名 + $config->endpoint = "dysmsapi.aliyuncs.com"; + return new Dysmsapi($config); + } + + + /** + * @param string $phone + * @param string $templateId + * @param array $data + * @return array[]|bool|mixed + */ + public function send(string $phone, string $templateId, array $data = []) + { + if (empty($phone)) { + return $this->setError('电话号码不能为空'); + } + //验证码只支持一个参数 + if ($templateId == 'VERIFICATION_CODE') { + unset($data['time']); + } + if (isset($data['site'])) { + unset($data['site']); + } + $client = self::createClient("accessKeyId", "accessKeySecret"); + $temp = app()->make(SystemNoticeConfigRepository::class)->getSmsTemplate($templateId); + if (!$temp) throw new ValidateException('模板不存在:'. $templateId); + $sendSmsRequest = new SendSmsRequest([ + "phoneNumbers" => $phone, + "signName" => systemConfig('aliyun_SignName'), + "templateCode" => $temp, + "templateParam" => json_encode($data), + ]); + $runtime = new RuntimeOptions([]); + try { + // 复制代码运行请自行打印 API 的返回值 + $resp = $client->sendSmsWithOptions($sendSmsRequest, $runtime); + } + catch (Exception $error) { + if (!($error instanceof TeaError)) { + $error = new TeaError([], $error->getMessage(), $error->getCode(), $error); + } + // 如有需要,请打印 error + throw new ValidateException('【阿里云平台错误提示】:'.$error->message); + //$resp = Utils::assertAsString($error->message); + } + if (isset($resp) && $resp->body->code !== 'OK') { + throw new ValidateException('【阿里云平台错误提示】:'.$resp->body->message); + } + return 'ok'; + } + + public function open(){} + + public function modify(string $sign = null , string $phone, string $code){} + + public function info(){} + + public function temps(int $page = 0, int $limit = 10, int $type = 1){} + + public function apply(string $title, string $content, int $type){} + + public function applys(int $tempType, int $page, int $limit){} + + public function record($record_id){} +} diff --git a/crmeb/services/sms/storage/Yunxin.php b/crmeb/services/sms/storage/Yunxin.php new file mode 100644 index 00000000..5b08e7c5 --- /dev/null +++ b/crmeb/services/sms/storage/Yunxin.php @@ -0,0 +1,282 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\services\sms\storage; + +use app\common\dao\system\sms\SmsRecordDao; +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use crmeb\exceptions\SmsException; +use crmeb\services\BaseSmss; +use think\exception\ValidateException; +use think\facade\Config; + + +/** + * Class Yunxin + * @package crmeb\services\sms\storage + */ +class Yunxin extends BaseSmss +{ + + /** + * 开通 + */ + const SMS_OPEN = 'sms_v2/open'; + + /** + * 修改签名 + */ + const SMS_MODIFY = 'sms_v2/modify'; + + /** + * 用户信息 + */ + const SMS_INFO = 'sms_v2/info'; + + /** + * 发送短信 + */ + const SMS_SEND = 'sms_v2/send'; + + /** + * 短信模板 + */ + const SMS_TEMPS = 'sms_v2/temps'; + + /** + * 申请模板 + */ + const SMS_APPLY = 'sms_v2/apply'; + + /** + * 模板记录 + */ + const SMS_APPLYS = 'sms_v2/applys'; + + /** + * 发送记录 + */ + const SMS_RECORD = 'sms_v2/record'; + + /** + * 获取短信发送状态 + */ + const SMS_STSTUS = 'sms/status'; + + /** + * 短信签名 + * @var string + */ + protected $sign = ''; + + /** + * 模板id + * @var array + */ + protected $templateIds = []; + + /** 初始化 + * @param array $config + */ + protected function initialize(array $config = []) + { + parent::initialize($config); + $this->templateIds = Config::get($this->configFile . '.stores.' . $this->name . '.template_id', []); + + } + + /** + * 提取模板code + * @param string $templateId + * @return null + */ + protected function getTemplateCode(string $templateId) + { + $temp = app()->make(SystemNoticeConfigRepository::class)->getSmsTemplate($templateId); + if (!$temp) throw new ValidateException('模板不存在:'. $templateId); + return $temp; + } + + /** + * 设置签名 + * @param $sign + * @return $this + */ + public function setSign($sign) + { + $this->sign = $sign; + return $this; + } + + /** + * 获取验证码 + * @param string $phone + * @return array|mixed + */ + public function captcha(string $phone) + { + $params = [ + 'phone' => $phone + ]; + return $this->accessToken->httpRequest('sms/captcha', $params, 'GET', false); + } + + /** + * 开通服务 + * @return array|bool|mixed + */ + public function open() + { + $param = [ + 'sign' => $this->sign + ]; + return $this->accessToken->httpRequest(self::SMS_OPEN, $param); + } + + /** + * 修改签名 + * @param string $sign + * @return array|bool|mixed + */ + public function modify(string $sign = null, string $phone, string $code) + { + $param = [ + 'sign' => $sign ?: $this->sign, + 'verify_code' => $code, + 'phone' => $phone + ]; + return $this->accessToken->httpRequest(self::SMS_MODIFY, $param); + } + + /** + * 获取用户信息 + * @return array|bool|mixed + */ + public function info() + { + return $this->accessToken->httpRequest(self::SMS_INFO, []); + } + + /** + * 获取短信模板 + * @param int $page + * @param int $limit + * @param int $type + * @return array|mixed + */ + public function temps(int $page = 0, int $limit = 10, int $type = 1) + { + $param = [ + 'page' => $page, + 'limit' => $limit, + 'temp_type' => $type + ]; + return $this->accessToken->httpRequest(self::SMS_TEMPS, $param); + } + + /** + * 申请模版 + * @param $title + * @param $content + * @param $type + * @return array|bool|mixed + */ + public function apply(string $title, string $content, int $type) + { + $param = [ + 'title' => $title, + 'content' => $content, + 'type' => $type + ]; + return $this->accessToken->httpRequest(self::SMS_APPLY, $param); + } + + /** + * 申请记录 + * @param $temp_type + * @param int $page + * @param int $limit + * @return array|bool|mixed + */ + public function applys(int $tempType, int $page, int $limit) + { + $param = [ + 'temp_type' => $tempType, + 'page' => $page, + 'limit' => $limit + ]; + return $this->accessToken->httpRequest(self::SMS_APPLYS, $param); + } + + /** + * 发送短信 + * @param $phone + * @param $template + * @param $param + * @return bool|string + */ + public function send(string $phone, string $templateId, array $data = []) + { + if (!$phone) { + throw new ValidateException('手机号不能为空'); + } + $param = [ + 'phone' => $phone, + 'host' => request()->host(), + ]; + $param['temp_id'] = $this->getTemplateCode($templateId); + if (is_null($param['temp_id'])) { + throw new ValidateException('模版ID不存在'); + } + $param['param'] = json_encode($data); + $resp = $this->accessToken->httpRequest(self::SMS_SEND, $param); + + try{ + if ($resp) { + app()->make(SmsRecordDao::class)->create([ + 'uid' => systemConfig('serve_account'), + 'phone' => $phone, + 'content' => $resp['content'], + 'template' => $resp['template'], + 'record_id' => $resp['id'], + ]); + } + } catch (\Exception $exception) { + throw new SmsException($exception->getMessage()); + } + + return $resp; + } + + /** + * 发送记录 + * @param $record_id + * @return array|bool|mixed + */ + public function record($record_id) + { + $param = [ + 'record_id' => $record_id + ]; + return $this->accessToken->httpRequest(self::SMS_RECORD, $param); + } + + /** + * 获取发送状态 + * @param array $recordIds + * @return array|mixed + */ + public function getStatus(array $recordIds) + { + $data['record_id'] = json_encode($recordIds); + return $this->accessToken->httpRequest(self::SMS_STSTUS, $data, 'POST', false); + } +} diff --git a/crmeb/services/template/Template.php b/crmeb/services/template/Template.php new file mode 100644 index 00000000..f178acdd --- /dev/null +++ b/crmeb/services/template/Template.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\template; + +use crmeb\basic\BaseManager; +use think\facade\Config; + +/** + * Class Template + * @package crmeb\services\template + * @mixin \crmeb\services\template\storage\Wechat + * @mixin \crmeb\services\template\storage\Subscribe + */ +class Template extends BaseManager +{ + + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\template\\storage\\'; + + /** + * 设置默认 + * @return mixed + */ + protected function getDefaultDriver() + { + return 'wechat'; + } +} diff --git a/crmeb/services/template/storage/Subscribe.php b/crmeb/services/template/storage/Subscribe.php new file mode 100644 index 00000000..44762a18 --- /dev/null +++ b/crmeb/services/template/storage/Subscribe.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\template\storage; + +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use app\common\repositories\wechat\TemplateMessageRepository; +use crmeb\basic\BaseMessage; +use crmeb\services\MiniProgramService; +use think\facade\Log; + +/** + * 订阅消息 + * Class Subscribe + * @package crmeb\services\template\storage + */ +class Subscribe extends BaseMessage +{ + + protected function initialize(array $config) + { + parent::initialize($config); // TODO: Change the autogenerated stub + } + + /** + * @param string $templateId + * @return mixed + */ + public function getTempId(string $templateId) + { + $tempkey = app()->make(SystemNoticeConfigRepository::class)->getSearch(['const_key' => $templateId])->with(['routineTemplate'])->find(); + return $tempkey['routineTemplate']['tempid']; + } + + /** + * 发送订阅消息 + * @param string $templateId + * @param array $data + * @return bool|\EasyWeChat\Support\Collection|mixed|null + */ + public function send(string $templateId, array $data = []) + { +// $templateId = $this->getTemplateCode($templateId); +// if (!$templateId) { +// return ; //$this->setError('Template number does not exist'); +// } + $tempid = $this->getTempId($templateId); + if (!$tempid || !$this->openId) { + return ; //$this->setError('Template ID does not exist'); + } + + try { + $res = MiniProgramService::create()->sendSubscribeTemlate($this->openId, $tempid, $data, $this->toUrl); + $this->clear(); + return $res; + } catch (\Throwable $e) { + Log::error('发送给openid为:' . $this->openId . '小程序订阅消息失败,模板id为:' . $tempid . ';错误原因为:' . $e->getMessage()); + return $this->setError($e->getMessage()); + } + } + + public function delete(string $templateId) + { + // TODO: Implement delete() method. + } + + public function add(string $shortId) + { + // TODO: Implement add() method. + } + + public function list() + { + // TODO: Implement list() method. + } +} diff --git a/crmeb/services/template/storage/Wechat.php b/crmeb/services/template/storage/Wechat.php new file mode 100644 index 00000000..877675b6 --- /dev/null +++ b/crmeb/services/template/storage/Wechat.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\template\storage; + +use app\common\repositories\system\notice\SystemNoticeConfigRepository; +use app\common\repositories\wechat\TemplateMessageRepository; +use crmeb\basic\BaseMessage; +use crmeb\services\WechatService; +use think\facade\Log; + +class Wechat extends BaseMessage +{ + /** + * @var WechatService + */ + protected $service; + protected $miniprogram; + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config) + { + parent::initialize($config); // TODO: Change the autogenerated stub + $this->service = WechatService::create(); + $this->miniprogram = [ + 'appid' => systemConfig('routine_appId'), + ]; + } + + /** + * @param string $templateId + * @return mixed + */ + public function getTempId(string $templateId) + { + $tempkey = app()->make(SystemNoticeConfigRepository::class)->getSearch(['const_key' => $templateId])->with(['wechatTemplate'])->find(); + return $tempkey['wechatTemplate']['tempid']; + } + + /** + * 发送消息 + * @param string $templateId + * @param array $data + * @return bool|mixed + */ + public function send(string $templateId, array $data = []) + { +// $templateId = $this->getTemplateCode($templateId); +// if (!$templateId) { +// return ; +// //return $this->setError('Template number does not exist'); +// } + $tempid = $this->getTempId($templateId); + if (!$tempid || !$this->openId) { + return ; + //return $this->setError('Template ID does not exist'); + } + + $miniprogram = []; + if ($this->miniprogram['appid']) $miniprogram = $this->miniprogram; + try { + $res = $this->service->sendTemplate($this->openId, $tempid, $data, $this->toUrl, $this->color,$miniprogram); + $this->clear(); + return $res; + } catch (\Exception $e) { + Log::error('发送给openid为:' . $this->openId . '微信模板消息失败,模板id为:' . $tempid . ';错误原因为:' . $e->getMessage()); + return $this->setError($e->getMessage()); + } + } + + /** + * 获取所有模板 + * @return \EasyWeChat\Support\Collection|mixed + */ + public function list() + { + return $this->service->noticeService()->getPrivateTemplates(); + } + + /** + * 添加模板消息 + * @param string $shortId + * @return \EasyWeChat\Support\Collection|mixed + */ + public function add(string $shortId) + { + return $this->service->noticeService()->addTemplate($shortId); + } + + /** + * 删除模板消息 + * @param string $templateId + * @return \EasyWeChat\Support\Collection|mixed + */ + public function delete(string $templateId) + { + return $this->service->noticeService()->deletePrivateTemplate($templateId); + } + + /** + * 返回所有支持的行业列表 + * @return \EasyWeChat\Support\Collection + */ + public function getIndustry() + { + return $this->service->noticeService()->getIndustry(); + } +} diff --git a/crmeb/services/upload/Upload.php b/crmeb/services/upload/Upload.php new file mode 100644 index 00000000..f9d89032 --- /dev/null +++ b/crmeb/services/upload/Upload.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\upload; + +use crmeb\basic\BaseManager; +use think\facade\Config; + +/** + * Class Upload + * @package crmeb\services\upload + * @mixin \crmeb\services\upload\storage\Local + * @mixin \crmeb\services\upload\storage\OSS + * @mixin \crmeb\services\upload\storage\COS + * @mixin \crmeb\services\upload\storage\Qiniu + */ +class Upload extends BaseManager +{ + /** + * 空间名 + * @var string + */ + protected $namespace = '\\crmeb\\services\\upload\\storage\\'; + + /** + * 设置默认上传类型 + * @return mixed + */ + protected function getDefaultDriver() + { + return Config::get('upload.default', 'local'); + } + + +} diff --git a/crmeb/services/upload/client/UploadManager.php b/crmeb/services/upload/client/UploadManager.php new file mode 100644 index 00000000..cda4a579 --- /dev/null +++ b/crmeb/services/upload/client/UploadManager.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- +namespace crmeb\services\upload\client; + +use UCloud\ActionType; +use UCloud\Auth; +use UCloud\Config; +use UCloud\Http\Client; +use UCloud\Http\Error; +use UCloud\Http\Request; +use UCloud\Storage\UploadManager as UcloudUploadManager; + +class UploadManager extends UcloudUploadManager +{ + + public $auth; + public function __construct(Auth $auth = null) { + parent::__construct($auth); + $this->auth = $auth; + } + + + public function MultipartForm($bucket, $key, $file) { + $action_type = ActionType::POSTFILE; + $err = \UCloud\CheckConfig($this->auth, ActionType::POSTFILE); + if ($err != null) { + return array(null, $err); + } + + $f = @fopen($file, "r"); + if (!$f) return array(null, new Error(-1, -1, "open $file error")); + + $host = $bucket . $this->auth->ProxySuffix; + $path = ""; + $fsize = filesize($file); + $content = ""; + if ($fsize != 0) { + $content = @fread($f, filesize($file)); + if ($content == FALSE) { + fclose($f); + return array(null, new Error(0, -1, "read file error")); + } + } + list($mimetype, $err) = \UCloud\GetFileMimeType($file); + if ($err) { + fclose($f); + return array("", $err); + } + + $req = new Request('POST', array('host'=>$host, 'path'=>$path), $content, $bucket, $key, $action_type); + $req->Header['Expect'] = ''; + $token = $this->auth->SignRequest($req, $mimetype); + + $fields = array('Authorization'=>$token, 'FileName' => $key); + $files = array('files'=>array('file', $file, $content, $mimetype)); + + $client = new Client($this->auth, Config::NO_AUTH_CHECK); + list($data, $err) = $client->CallWithMultipartForm($req, $fields, $files); + fclose($f); + return array($data, $err); + } + +} diff --git a/crmeb/services/upload/storage/Cos.php b/crmeb/services/upload/storage/Cos.php new file mode 100644 index 00000000..98426ac1 --- /dev/null +++ b/crmeb/services/upload/storage/Cos.php @@ -0,0 +1,390 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\upload\storage; + +use crmeb\basic\BaseUpload; +use crmeb\exceptions\UploadException; +use Guzzle\Http\EntityBody; +use Qcloud\Cos\Client; +use think\Exception; +use think\exception\ValidateException; +use think\Image; + +/** + * 腾讯云COS文件上传 + * Class COS + * @package crmeb\services\upload\storage + */ +class Cos extends BaseUpload +{ + /** + * accessKey + * @var mixed + */ + protected $accessKey; + + /** + * secretKey + * @var mixed + */ + protected $secretKey; + + /** + * 句柄 + * @var Client + */ + protected $handle; + + /** + * 空间域名 Domain + * @var mixed + */ + protected $uploadUrl; + + /** + * 存储空间名称 公开空间 + * @var mixed + */ + protected $storageName; + + /** + * COS使用 所属地域 + * @var mixed|null + */ + protected $storageRegion; + + /** + * cdn 域名 + * @var + */ + protected $cdn; + + /** + * 缩略图配置 + * @var + */ + protected $thumbConfig; + + /** + * 缩略图开关 + * @var mixed|null + */ + protected $thumb_status; + + /** + * 缩略图比例 + * @var mixed|null + */ + protected $thumb_rate; + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + public function initialize(array $config) + { + parent::initialize($config); + $this->accessKey = $config['accessKey'] ?? null; + $this->secretKey = $config['secretKey'] ?? null; + $this->uploadUrl = tidy_url($this->checkUploadUrl($config['uploadUrl'] ?? '')); + $this->storageName = $config['storageName'] ?? null; + $this->storageRegion = $config['storageRegion'] ?? null; + $this->cdn = $config['cdn'] ?? null; + $this->thumb_status = $config['thumb_status']; + $this->thumb_rate = $config['thumb_rate']; + } + + /** + * 实例化cos + * @return Client + */ + protected function app() + { + if (!$this->accessKey || !$this->secretKey) { + throw new UploadException('Please configure accessKey and secretKey'); + } + $this->handle = new Client(['region' => $this->storageRegion, 'credentials' => [ + 'secretId' => $this->accessKey, 'secretKey' => $this->secretKey + ]]); + return $this->handle; + } + + /** + * 上传文件 + * @param string|null $file + * @param bool $isStream 是否为流上传 + * @param string|null $fileContent 流内容 + * @return array|bool|\StdClass + */ + protected function upload(string $file = null, bool $isStream = false, string $fileContent = null,$thumb = true) + { + if (!$isStream) { + $fileHandle = app()->request->file($file); + if (!$fileHandle) { + return $this->setError('Upload file does not exist'); + } + if ($this->validate) { + try { + validate([$file => $this->validate])->check([$file => $fileHandle]); + } catch (ValidateException $e) { + return $this->setError($e->getMessage()); + } + } + $key = $this->saveFileName($fileHandle->getRealPath(), $fileHandle->getOriginalExtension()); + $body = fopen($fileHandle->getRealPath(), 'rb'); + } else { + $key = $file; + $body = $fileContent; + } + $path = ($this->path ? trim($this->path , '/') . '/' : ''); + try { + $this->fileInfo->uploadInfo = $this->app()->putObject([ + 'Bucket' => $this->storageName, + 'Key' => $path . $key, + 'Body' => $body + ]); + $src = rtrim(($this->cdn ?: $this->uploadUrl), '/') . '/' . $path . $key; + if ($thumb) $src = $this->thumb($src); + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 缩略图 + * @param string $filePath + * @param string $type + * @return mixed|string[] + */ + public function thumb(string $key = '') + { + if ($this->thumb_status && $key) { + $key = $key.'?imageMogr2/thumbnail/!' . $this->thumb_rate .'p'; + } + return $key; + } + + /** + * 文件流上传 + * @param string $fileContent + * @param string|null $key + * @return array|bool|mixed|\StdClass + */ + public function stream(string $fileContent, string $key = null) + { + if (!$key) { + $key = $this->saveFileName(); + } + return $this->upload($key, true, $fileContent,false); + } + + /** + * 文件上传 + * @param string $file + * @return array|bool|mixed|\StdClass + */ + public function move(string $file = 'file' ,$thumb = true) + { + return $this->upload($file,false,null,$thumb); + } + + /** + * TODO 删除资源 + * @param $key + * @return mixed + */ + public function delete(string $filePath) + { + try { + return $this->app()->deleteObject(['Bucket' => $this->storageName, 'Key' => $filePath]); + } catch (\Exception $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 获取腾讯云存储临时密钥 + * @return array|bool|mixed|null|string + */ + public function getTempKeys() + { + // TODO: Implement getTempKeys() method. + $config = array( + 'url' => 'https://sts.tencentcloudapi.com/', + 'domain' => 'sts.tencentcloudapi.com', + 'proxy' => '', + 'secretId' => $this->accessKey, // 固定密钥 + 'secretKey' => $this->secretKey, // 固定密钥 + 'bucket' => $this->storageName, // 换成你的 bucket + 'region' => $this->storageRegion, // 换成 bucket 所在园区 + 'durationSeconds' => 1800, // 密钥有效期 + 'allowPrefix' => '*', // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用) + // 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923 + 'allowActions' => array ( + // 简单上传 + 'name/cos:PutObject', + 'name/cos:PostObject', + // 分片上传 + 'name/cos:InitiateMultipartUpload', + 'name/cos:ListMultipartUploads', + 'name/cos:ListParts', + 'name/cos:UploadPart', + 'name/cos:CompleteMultipartUpload' + ) + ); + $result = null; + try{ + if(array_key_exists('policy', $config)){ + $policy = $config['policy']; + }else{ + if(array_key_exists('bucket', $config)){ + $ShortBucketName = substr($config['bucket'],0, strripos($config['bucket'], '-')); + $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-')); + }else{ + throw new Exception("bucket== null"); + } + if(array_key_exists('allowPrefix', $config)){ + if(!(strpos($config['allowPrefix'], '/') === 0)){ + $config['allowPrefix'] = '/' . $config['allowPrefix']; + } + }else{ + throw new Exception("allowPrefix == null"); + } + $policy = array( + 'version'=> '2.0', + 'statement'=> array( + array( + 'action'=> $config['allowActions'], + 'effect'=> 'allow', + 'principal'=> array('qcs'=> array('*')), + 'resource'=> array( + 'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':' . $config['bucket'] . $config['allowPrefix'] + ) + ) + ) + ); + } + $policyStr = str_replace('\\/', '/', json_encode($policy)); + $Action = 'GetFederationToken'; + $Nonce = rand(10000, 20000); + $Timestamp = time(); + $Method = 'POST'; + if(array_key_exists('durationSeconds', $config)){ + if(!(is_integer($config['durationSeconds']))){ + throw new exception("durationSeconds must be a int type"); + } + } + $params = array( + 'SecretId'=> $config['secretId'], + 'Timestamp'=> $Timestamp, + 'Nonce'=> $Nonce, + 'Action'=> $Action, + 'DurationSeconds'=> $config['durationSeconds'], + 'Version'=>'2018-08-13', + 'Name'=> 'cos', + 'Region'=> $config['region'], + 'Policy'=> urlencode($policyStr) + ); + $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config); + $url = $config['url']; + $ch = curl_init($url); + if(array_key_exists('proxy', $config)){ + $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']); + } + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0); + curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params)); + $result = curl_exec($ch); + if(curl_errno($ch)) $result = curl_error($ch); + curl_close($ch); + $result = json_decode($result, 1); + if (isset($result['Response'])) { + $result = $result['Response']; + if(isset($result['Error'])){ + throw new Exception("get cam failed"); + } + $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds']; + } + $result = $this->backwardCompat($result); + $result['url'] = $this->uploadUrl . '/'; + $result['type'] = 'COS'; + $result['cdn'] = $this->cdn; + $result['bucket'] = $this->storageName; + $result['region'] = $this->storageRegion; + return $result; + }catch(Exception $e){ + if($result == null){ + $result = "error: " . + $e->getMessage(); + }else{ + $result = json_encode($result); + } + throw new Exception($result); + } + } + + /** + * 计算临时密钥用的签名 + * @param $opt + * @param $key + * @param $method + * @param $config + * @return string + */ + public function getSignature($opt, $key, $method, $config) { + $formatString = $method . $config['domain'] . '/?' . $this->json2str($opt, 1); + $sign = hash_hmac('sha1', $formatString, $key); + $sign = base64_encode($this->_hex2bin($sign)); + return $sign; + } + public function _hex2bin($data) { + $len = strlen($data); + return pack("H" . $len, $data); + } + // obj 转 query string + public function json2str($obj, $notEncode = false) { + ksort($obj); + $arr = array(); + if(!is_array($obj)){ + return $this->setError($obj . " must be a array"); + } + foreach ($obj as $key => $val) { + array_push($arr, $key . '=' . ($notEncode ? $val : rawurlencode($val))); + } + return join('&', $arr); + } + // v2接口的key首字母小写,v3改成大写,此处做了向下兼容 + public function backwardCompat($result) { + if(!is_array($result)){ + return $this->setError($result . " must be a array"); + } + $compat = array(); + foreach ($result as $key => $value) { + if(is_array($value)) { + $compat[lcfirst($key)] = $this->backwardCompat($value); + } elseif ($key == 'Token') { + $compat['sessionToken'] = $value; + } else { + $compat[lcfirst($key)] = $value; + } + } + return $compat; + } +} diff --git a/crmeb/services/upload/storage/Local.php b/crmeb/services/upload/storage/Local.php new file mode 100644 index 00000000..2f245692 --- /dev/null +++ b/crmeb/services/upload/storage/Local.php @@ -0,0 +1,375 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\upload\storage; + +use crmeb\basic\BaseUpload; +use crmeb\exceptions\UploadException; +use crmeb\services\DownloadImageService; +use think\exception\ValidateException; +use think\facade\Config; +use think\facade\Filesystem; +use think\File; +use think\Image; + +/** + * 本地上传 + * Class Local + * @package crmeb\services\upload\storage + */ +class Local extends BaseUpload +{ + + /** + * 默认存放路径 + * @var string + */ + protected $defaultPath; + protected $waterConfig; + protected $thumbConofig; + /** + * 缩略图开关 + * @var mixed|null + */ + protected $thumb_status; + + /** + * 缩略图比例 + * @var mixed|null + */ + protected $thumb_rate; + + public function initialize(array $config) + { + parent::initialize($config); + $this->defaultPath = Config::get('filesystem.disks.' . Config::get('filesystem.default') . '.url'); + $this->waterConfig = $config['water'] ?? []; + $this->thumb_status = $config['thumb_status']; + $this->thumb_rate = $config['thumb_rate']; + } + + protected function app() + { + // TODO: Implement app() method. + } + + public function getTempKeys() + { + return [ + 'type' => 'local' + ]; + } + + /** + * 生成上传文件目录 + * @param $path + * @param null $root + * @return string + */ + protected function uploadDir($path, $root = null) + { + if ($root === null) $root = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR; + return str_replace('\\', '/', $root . 'uploads' . DIRECTORY_SEPARATOR . $path); + } + + /** + * 检查上传目录不存在则生成 + * @param $dir + * @return bool + */ + protected function validDir($dir) + { + return is_dir($dir) == true || mkdir($dir, 0777, true) == true; + } + + /** + * 文件上传 + * @param string $file + * @return array|bool|mixed|\StdClass + */ + public function move(string $file = 'file', $thumb = true) + { + $fileHandle = app()->request->file($file); + if (!$fileHandle) { + return $this->setError('Upload file does not exist'); + } + if ($this->validate) { + try { + validate([$file => $this->validate])->check([$file => $fileHandle]); + } catch (ValidateException $e) { + return $this->setError($e->getMessage()); + } + } + $fileName = Filesystem::putFile($this->path, $fileHandle); + if (!$fileName) return $this->setError('Upload failure'); + $filePath = Filesystem::path($fileName); + $this->fileInfo->uploadInfo = new File($filePath); + $this->fileInfo->fileName = $this->fileInfo->uploadInfo->getFilename(); + $this->fileInfo->filePath = $this->defaultPath . '/' . str_replace('\\', '/', $fileName); + if ($thumb) $this->thumb($this->fileInfo->filePath); + return $this->fileInfo; + } + + /** + * 文件流上传 + * @param string $fileContent + * @param string|null $key + * @return array|bool|mixed|\StdClass + */ + public function stream(string $fileContent, string $key = null) + { + if (!$key) { + $key = $this->saveFileName(); + } + $dir = $this->uploadDir($this->path); + if (!$this->validDir($dir)) { + return $this->setError('Failed to generate upload directory, please check the permission!'); + } + $fileName = $dir . '/' . $key; + file_put_contents($fileName, $fileContent); + $this->fileInfo->uploadInfo = new File($fileName); + $this->fileInfo->fileName = $key; + $this->fileInfo->filePath = $this->defaultPath . '/' . $this->path . '/' . $key; + return $this->fileInfo; + } + + /** + * 删除文件 + * @param string $filePath + * @return bool|mixed + */ + public function delete(string $filePath) + { + if (file_exists($filePath)) { + try { + unlink($filePath); + return true; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + return false; + } + + /** + * 生成缩略图 + * @param string $filePath + * @param string $type + * @return array|mixed|string[] + */ + public function thumb(string $filePath = '', $savePath = null) + { + if ($this->thumb_status && $filePath) { + $filePath = $this->getFilePath($filePath, true); + $savePath = $savePath ?: $filePath; + //地址存在且不是远程地址 + if ($filePath && !$this->checkFilePathIsRemote($filePath)) { + try { + $Image = Image::open(root_path() . 'public' . $filePath); + $Image->thumb( + $Image->width() * ($this->thumb_rate ?: 0.8), + $Image->height() * ($this->thumb_rate ?: 0.8) + )->save(root_path() . 'public' . $savePath); + } catch (\Throwable $e) { + if ($e->getMessage() == 'Illegal image file') { + return; + } + throw new ValidateException($e->getMessage()); + } + } + return $savePath; + } + } + + public function water(string $filePath = '') + { + if (!$this->waterConfig['image_watermark_status']) return $filePath; + $filePath = $this->getFilePath($filePath, true); + //地址存在且不是远程地址 + $waterPath = $filePath; + if ($filePath && !$this->checkFilePathIsRemote($filePath)) { + switch ($this->waterConfig['watermark_type']) { + case 1: + if ($this->waterConfig['watermark_image']) + $waterPath = $this->image($filePath, $this->waterConfig, $waterPath); + break; + case 2: + $waterPath = $this->text($filePath, $this->waterConfig, $waterPath); + break; + } + } + return $waterPath; + } + + /** + * TODO + * @param string $filePath + * @return bool + * @author Qinii + * @day 12/14/21s + */ + public function checkFilePathIsRemote(string $filePath) + { + return strpos($filePath, 'https:') !== false || strpos($filePath, 'http:') !== false || substr($filePath, 0, 2) === '//'; + } + + /** + * 生成与配置相关的文件名称以及路径 + * @param string $filePath 原地址 + * @param string $toPath 保存目录 + * @param array $config 配置相关参数 + * @param string $root + * @return string + */ + public function createSaveFilePath(string $filePath, string $toPath, array $config = [], $root = '/') + { + [$path, $ext] = $this->getFileName($filePath); + $fileName = md5(json_encode($config) . $filePath); + $this->validDir($toPath); + return $this->uploadDir($toPath, $root) . '/' . $fileName . '.' . $ext; + } + + /** + * 提取文件后缀以及之前部分 + * @param string $path + * @return false|string[] + */ + protected function getFileName(string $path) + { + $_empty = ['', '']; + if (!$path) return $_empty; + if (strpos($path, '?')) { + $_tarr = explode('?', $path); + $path = trim($_tarr[0]); + } + $arr = explode('.', $path); + if (!is_array($arr) || count($arr) <= 1) return $_empty; + $ext_name = trim($arr[count($arr) - 1]); + $ext_name = !$ext_name ? 'jpg' : $ext_name; + return [explode('.' . $ext_name, $path)[0], $ext_name]; + } + + /** + * 获取图片地址 + * @param string $filePath + * @param bool $is_parse_url + * @return string + */ + protected function getFilePath(string $filePath = '', bool $is_parse_url = false) + { + $path = $filePath ? $filePath : $this->path; + if ($is_parse_url) { + $data = parse_url($path); + //远程地址处理 + if (isset($data['host']) && isset($data['path'])) { + if (file_exists(app()->getRootPath() . 'public' . $data['path'])) { + $path = $data['path']; + } + } + } + return $path; + } + + /** + * 图片水印 + * @param string $filePath + * @param array $waterConfig + * @param string $waterPath + * @return string + */ + public function image(string $filePath, array $waterConfig = [], string $waterPath = '') + { + if (!$waterConfig) $waterConfig = $this->waterConfig; + $watermark_image = $waterConfig['watermark_image']; + + //远程图片 + if ($watermark_image && $this->checkFilePathIsRemote($watermark_image)) { + //看是否在本地 + $pathName = $this->getFilePath($watermark_image, true); + + if ($pathName == $watermark_image) { //不再本地 继续下载 + [$p, $e] = $this->getFileName($watermark_image); + $name = 'water_image_' . md5($watermark_image) . '.' . $e; + $watermark_image = '.' . $this->defaultPath . '/' . $this->path . '/' . $name; + if (!file_exists($watermark_image)) { + try { + /** @var DownloadImageService $down */ + $down = app()->make(DownloadImageService::class); + $data = $down->path($this->path)->downloadImage($waterConfig['watermark_image'], $name); + $watermark_image = $data['path'] ?? ''; + } catch (\Throwable $e) { + throw new ValidateException('远程水印图片下载失败,原因:' . $e->getMessage()); + } + } + } else { + $watermark_image = '.' . $pathName; + } + } + + if (!$watermark_image) { + throw new ValidateException('请先配置水印图片'); + } + + if (!$waterPath) { + [$path, $ext] = $this->getFileName($filePath); + $waterPath = $path . '_water_image.' . $ext; + } + try { + $Image = Image::open(app()->getRootPath() . 'public' . $filePath); + $Image->water( + app()->getRootPath() . 'public' . $watermark_image, + $waterConfig['watermark_position'] ?: 1, + $waterConfig['watermark_opacity'] + )->save(root_path() . 'public' . $waterPath); + } catch (\Throwable $e) { + throw new ValidateException($e->getMessage()); + } + return $waterPath; + } + + /** + * 文字水印 + * @param string $filePath + * @param array $waterConfig + * @param string $waterPath + * @return string + */ + public function text(string $filePath, array $waterConfig = [], string $waterPath = '') + { + if (!$waterConfig) { + $waterConfig = $this->waterConfig; + } + if (!$waterConfig['watermark_text']) { + throw new ValidateException('请先配置水印文字'); + } + if (!$waterPath) { + [$path, $ext] = $this->getFileName($filePath); + $waterPath = $path . '_water_text.' . $ext; + } + try { + if (!file_exists(root_path() . 'public' . $waterPath)) { + $Image = Image::open(app()->getRootPath() . 'public' . $filePath); + if (strlen($waterConfig['watermark_text_color']) < 7) { + $waterConfig['watermark_text_color'] = substr($waterConfig['watermark_text_color'], 1); + $waterConfig['watermark_text_color'] = '#' . $waterConfig['watermark_text_color'] . $waterConfig['watermark_text_color']; + } + if (strlen($waterConfig['watermark_text_color']) > 7) { + $waterConfig['watermark_text_color'] = substr($waterConfig['watermark_text_color'], 0, 7); + } + $Image->text($waterConfig['watermark_text'], public_path() . 'font/simsunb.ttf', $waterConfig['watermark_text_size'], $waterConfig['watermark_text_color'], $waterConfig['watermark_position'], [$waterConfig['watermark_x'], $waterConfig['watermark_y'], $waterConfig['watermark_text_angle']])->save(root_path() . 'public' . $waterPath); + } + } catch (\Throwable $e) { + throw new ValidateException($e->getMessage() . $e->getLine()); + } + return $waterPath; + } +} diff --git a/crmeb/services/upload/storage/Obs.php b/crmeb/services/upload/storage/Obs.php new file mode 100644 index 00000000..97a82ebe --- /dev/null +++ b/crmeb/services/upload/storage/Obs.php @@ -0,0 +1,267 @@ +accessKey = $config['accessKey'] ?? null; + $this->secretKey = $config['secretKey'] ?? null; + $this->uploadUrl = $this->checkUploadUrl($config['uploadUrl'] ?? ''); + $this->storageName = $config['storageName'] ?? null; + $this->storageRegion = $config['storageRegion'] ?? null; + $this->cdn = $config['cdn'] ?? null; + $this->thumb_status = $config['thumb_status']; + $this->thumb_rate = $config['thumb_rate']; + } + + /** + * 初始化obs + * @return ObsClient + * @throws ObsException + */ + protected function app() + { + if (!$this->accessKey || !$this->secretKey) { + throw new UploadException('Please configure accessKey and secretKey'); + } + $this->handle= new ObsClient([ + 'key' => $this->accessKey, + 'secret' => $this->secretKey, + 'endpoint' => $this->storageRegion + ]); + return $this->handle; + } + + /** + * 上传文件 + * @param string $file + * @return array|bool|mixed|\StdClass + */ + public function move(string $file = 'file', $thubm = true) + { + $fileHandle = app()->request->file($file); + if (!$fileHandle) { + return $this->setError('Upload file does not exist'); + } + if ($this->validate) { + try { + validate([$file => $this->validate])->check([$file => $fileHandle]); + } catch (ValidateException $e) { + return $this->setError($e->getMessage()); + } + } + $key = $this->saveFileName($fileHandle->getRealPath(), $fileHandle->getOriginalExtension()); + try { + $uploadInfo = $this->app()->putObject( + [ + 'Bucket' => $this->storageName, + 'Key' => $key, + 'SourceFile' => $fileHandle->getRealPath() + ]); + + // $this->storageName, $key, $fileHandle->getRealPath()); ObjectURL HttpStatusCode + if (!isset($uploadInfo['HttpStatusCode'])) { + return $this->setError('Upload failure_obs'); + } + $src = rtrim(($this->cdn ?: $this->uploadUrl)).'/'. $key; + if ($thubm) $src = $this->thubm($src); + $this->fileInfo->uploadInfo = $uploadInfo; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 文件流上传 + * @param string $fileContent + * @param string|null $key + * @return bool|mixed + */ + public function stream(string $fileContent, string $key = null, $thubm = true) + { + try { + if (!$key) { + $key = $this->saveFileName(); + } + $fileContent = (string)EntityBody::factory($fileContent); + $uploadInfo = $this->app()->putObject( + [ + 'Bucket' => $this->storageName, + 'Key' => $key, + 'Body' => $fileContent + ]); + if ((int)$uploadInfo['HttpStatusCode'] != 200) { + return $this->setError('Upload failure obs str'); + } + $src = $this->uploadUrl . '/'.$key; + if ($thubm) $src = $this->thubm($src); + + $this->fileInfo->uploadInfo = $uploadInfo; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + public function thubm(string $key) + { + if ($this->thumb_status && $key) { + $key = $key.'?x-image-process=image/resize'. urlencode(',').'p_'. $this->thumb_rate; + } + return $key; + } + + + /** + * 获取上传配置信息 + * @return array + */ + public function getSystem() + { + $token = $this->app()->uploadToken($this->storageName); + $domain = $this->uploadUrl; + $key = $this->saveFileName(); + return compact('token', 'domain', 'key'); + } + + /** + * 删除资源 + * @param $key + * @return mixed + */ + public function delete(string $key) + { + try { + return $this->app()->deleteObject([$this->storageName, $key]); + } catch (ObsException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 获取OBS上传密钥 + * @return mixed|void + */ + public function getTempKeys($callbackUrl = '', $dir = '') + { + // TODO: Implement getTempKeys() method. + $base64CallbackBody = base64_encode(json_encode([ + 'callbackUrl' => $callbackUrl, + 'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}', + 'callbackBodyType' => "application/x-www-form-urlencoded" + ])); + + $policy = json_encode([ + 'expiration' => $this->gmtIso8601(time() + 300), + 'conditions' => + [ + [0 => 'content-length-range', 1 => 0, 2 => 1048576000], + ['bucket' => $this->storageName], + [0 => 'starts-with', 1 => '$key', 2 => $dir], + ] + ]); + $base64Policy = base64_encode($policy); + $signature = base64_encode(hash_hmac('sha1', $base64Policy, $this->secretKey, true)); + return [ + 'accessid' => $this->accessKey, + 'host' => $this->uploadUrl, + 'policy' => $base64Policy, + 'signature' => $signature, + 'expire' => time() + 30, + 'callback' => $base64CallbackBody, + 'cdn' => $this->cdn, + 'type' => 'OBS' + ]; + } + /** + * 获取ISO时间格式 + * @param $time + * @return string + */ + protected function gmtIso8601($time) + { + $dtStr = date("c", $time); + $mydatetime = new \DateTime($dtStr); + $expiration = $mydatetime->format(\DateTime::ISO8601); + $pos = strpos($expiration, '+'); + $expiration = substr($expiration, 0, $pos); + return $expiration . "Z"; + } + +} diff --git a/crmeb/services/upload/storage/Oss.php b/crmeb/services/upload/storage/Oss.php new file mode 100644 index 00000000..081d190b --- /dev/null +++ b/crmeb/services/upload/storage/Oss.php @@ -0,0 +1,268 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\upload\storage; + +use crmeb\basic\BaseUpload; +use crmeb\exceptions\UploadException; +use Guzzle\Http\EntityBody; +use OSS\Core\OssException; +use OSS\OssClient; +use think\exception\ValidateException; +use think\Image; + + +/** + * 阿里云OSS上传 + * Class OSS + */ +class Oss extends BaseUpload +{ + /** + * accessKey + * @var mixed + */ + protected $accessKey; + + /** + * secretKey + * @var mixed + */ + protected $secretKey; + + /** + * 句柄 + * @var \OSS\OssClient + */ + protected $handle; + + /** + * 空间域名 Domain + * @var mixed + */ + protected $uploadUrl; + + /** + * 存储空间名称 公开空间 + * @var mixed + */ + protected $storageName; + + /** + * COS使用 所属地域 + * @var mixed|null + */ + protected $storageRegion; + + /** + * cdn 域名 + * @var + */ + protected $cdn; + + /** + * 缩略图配置 + * @var + */ + protected $thumbConfig; + + /** + * 缩略图开关 + * @var mixed|null + */ + protected $thumb_status; + + /** + * 缩略图比例 + * @var mixed|null + */ + protected $thumb_rate; + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + protected function initialize(array $config) + { + parent::initialize($config); + $this->accessKey = $config['accessKey'] ?? null; + $this->secretKey = $config['secretKey'] ?? null; + $this->uploadUrl = tidy_url($this->checkUploadUrl($config['uploadUrl'] ?? '')); + $this->storageName = $config['storageName'] ?? null; + $this->storageRegion = $config['storageRegion'] ?? null; + $this->cdn = $config['cdn'] ?? null; + $this->thumb_status = $config['thumb_status']; + $this->thumb_rate = $config['thumb_rate']; + } + + /** + * 初始化oss + * @return OssClient + * @throws OssException + */ + protected function app() + { + if (!$this->accessKey || !$this->secretKey) { + throw new UploadException('Please configure accessKey and secretKey'); + } + $this->handle = new OssClient($this->accessKey, $this->secretKey, $this->storageRegion); + if (!$this->handle->doesBucketExist($this->storageName)) { + $this->handle->createBucket($this->storageName, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE); + } + return $this->handle; + } + + /** + * 上传文件 + * @param string $file + * @return array|bool|mixed|\StdClass + */ + public function move(string $file = 'file',$thumb = true) + { + $fileHandle = app()->request->file($file); + if (!$fileHandle) { + return $this->setError('Upload file does not exist'); + } + if ($this->validate) { + try { + validate([$file => $this->validate])->check([$file => $fileHandle]); + } catch (ValidateException $e) { + return $this->setError($e->getMessage()); + } + } + $key = $this->saveFileName($fileHandle->getRealPath(), $fileHandle->getOriginalExtension()); + $path = ($this->path ? trim($this->path , '/') . '/' : ''); + try { + $uploadInfo = $this->app()->uploadFile($this->storageName, $path . $key, $fileHandle->getRealPath()); + if (!isset($uploadInfo['info']['url'])) { + return $this->setError('Upload failure'); + } + $src = rtrim(($this->cdn ?: $this->uploadUrl)) . '/'.$path.$key; + if ($thumb) $src = $this->thumb($src); + $this->fileInfo->uploadInfo = $uploadInfo; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 文件流上传 + * @param string $fileContent + * @param string|null $key + * @return bool|mixed + */ + public function stream(string $fileContent, string $key = null, $thumb = true) + { + try { + if (!$key) { + $key = $this->saveFileName(); + } + $path = ($this->path ? trim($this->path , '/') . '/' : ''); + $fileContent = (string)EntityBody::factory($fileContent); + $uploadInfo = $this->app()->putObject($this->storageName, $path . $key, $fileContent); + if (!isset($uploadInfo['info']['url'])) { + return $this->setError('Upload failure'); + } + $src = $uploadInfo['info']['url']; + if ($thumb) $src = $this->thumb($src); + $this->fileInfo->uploadInfo = $uploadInfo; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 缩略图 + * @param string $filePath + * @param string $type + * @return mixed|string[] + */ + public function thumb(string $key = '') + { + if ($this->thumb_status && $key) { + $param = ('x-oss-process=image/resize' . urlencode(',') . 'p_' . $this->thumb_rate); + $key = $key . '?' . $param; + } + return $key; + } + + + /** + * 删除资源 + * @param $key + * @return mixed + */ + public function delete(string $key) + { + try { + return $this->app()->deleteObject($this->storageName, $key); + } catch (OssException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 获取OSS上传密钥 + * @return mixed|void + */ + public function getTempKeys($callbackUrl = '', $dir = '') + { + // TODO: Implement getTempKeys() method. + $base64CallbackBody = base64_encode(json_encode([ + 'callbackUrl' => $callbackUrl, + 'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}', + 'callbackBodyType' => "application/x-www-form-urlencoded" + ])); + + $policy = json_encode([ + 'expiration' => $this->gmtIso8601(time() + 30), + 'conditions' => + [ + [0 => 'content-length-range', 1 => 0, 2 => 1048576000], + [0 => 'starts-with', 1 => '$key', 2 => $dir] + ] + ]); + $base64Policy = base64_encode($policy); + $signature = base64_encode(hash_hmac('sha1', $base64Policy, $this->secretKey, true)); + return [ + 'accessid' => $this->accessKey, + 'host' => $this->uploadUrl, + 'policy' => $base64Policy, + 'signature' => $signature, + 'cdn' => $this->cdn, + 'expire' => time() + 30, + 'callback' => $base64CallbackBody, + 'type' => 'OSS' + ]; + } + /** + * 获取ISO时间格式 + * @param $time + * @return string + */ + protected function gmtIso8601($time) + { + $dtStr = date("c", $time); + $mydatetime = new \DateTime($dtStr); + $expiration = $mydatetime->format(\DateTime::ISO8601); + $pos = strpos($expiration, '+'); + $expiration = substr($expiration, 0, $pos); + return $expiration . "Z"; + } +} diff --git a/crmeb/services/upload/storage/Qiniu.php b/crmeb/services/upload/storage/Qiniu.php new file mode 100644 index 00000000..9d885ffb --- /dev/null +++ b/crmeb/services/upload/storage/Qiniu.php @@ -0,0 +1,237 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\upload\storage; + +use crmeb\basic\BaseUpload; +use crmeb\exceptions\UploadException; +use Qiniu\Auth; +use Qiniu\Config; +use Qiniu\Storage\BucketManager; +use Qiniu\Storage\UploadManager; +use think\exception\ValidateException; + + +/** + * TODO 七牛云上传 + * Class Qiniu + */ +class Qiniu extends BaseUpload +{ + /** + * accessKey + * @var mixed + */ + protected $accessKey; + + /** + * secretKey + * @var mixed + */ + protected $secretKey; + + /** + * 句柄 + * @var object + */ + protected $handle; + + /** + * 空间域名 Domain + * @var mixed + */ + protected $uploadUrl; + + /** + * 存储空间名称 公开空间 + * @var mixed + */ + protected $storageName; + + /** + * COS使用 所属地域 + * @var mixed|null + */ + protected $storageRegion; + + /** + * cdn 域名 + * @var + */ + protected $cdn; + + /** + * 缩略图配置 + * @var + */ + protected $thumbConfig; + + /** + * 缩略图开关 + * @var mixed|null + */ + protected $thumb_status; + + /** + * 缩略图比例 + * @var mixed|null + */ + protected $thumb_rate; + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + public function initialize(array $config) + { + parent::initialize($config); + $this->accessKey = $config['accessKey'] ?? null; + $this->secretKey = $config['secretKey'] ?? null; + $this->uploadUrl = tidy_url($this->checkUploadUrl($config['uploadUrl'] ?? '')); + $this->storageName = $config['storageName'] ?? null; + $this->storageRegion = $config['storageRegion'] ?? null; + $this->cdn = $config['cdn'] ?? null; + $this->thumb_status = $config['thumb_status']; + $this->thumb_rate = $config['thumb_rate']; + } + + /** + * 实例化七牛云 + * @return object|Auth + */ + protected function app() + { + if (!$this->accessKey || !$this->secretKey) { + throw new UploadException('Please configure accessKey and secretKey'); + } + $this->handle = new Auth($this->accessKey, $this->secretKey); + return $this->handle; + } + + /** + * 上传文件 + * @param string $file + * @return array|bool|mixed|\StdClass|string + */ + public function move(string $file = 'file', $thumb = true) + { + $fileHandle = app()->request->file($file); + if (!$fileHandle) { + return $this->setError('Upload file does not exist'); + } + if ($this->validate) { + try { + validate([$file => $this->validate])->check([$file => $fileHandle]); + } catch (ValidateException $e) { + return $this->setError($e->getMessage()); + } + } + $key = $this->saveFileName($fileHandle->getRealPath(), $fileHandle->getOriginalExtension()); + $path = ($this->path ? trim($this->path, '/') . '/' : ''); + $token = $this->app()->uploadToken($this->storageName); + try { + $uploadMgr = new UploadManager(); + [$result, $error] = $uploadMgr->putFile($token, $path . $key, $fileHandle->getRealPath()); + if ($error !== null) { + return $this->setError($error->message()); + } + $src = rtrim(($this->cdn ?: $this->uploadUrl), '/') . '/' . $path . $key; + if ($thumb) $src = $this->thumb($src); + $this->fileInfo->uploadInfo = $result; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 文件流上传 + * @param string $fileContent + * @param string|null $key + * @return array|bool|mixed|\StdClass + */ + public function stream(string $fileContent, string $key = null, $thumb = true) + { + $token = $this->app()->uploadToken($this->storageName); + if (!$key) { + $key = $this->saveFileName(); + } + $path = ($this->path ? trim($this->path, '/') . '/' : ''); + try { + $uploadMgr = new UploadManager(); + [$result, $error] = $uploadMgr->put($token, $path . $key, $fileContent); + if ($error !== null) { + return $this->setError($error->message()); + } + + $src = rtrim(($this->cdn ?: $this->uploadUrl), '/') . '/' . $path . $key; + if ($thumb) $src = $this->thumb($src); + + $this->fileInfo->uploadInfo = $result; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + public function thumb(string $key = '') + { + if ($this->thumb_status && $key) { + $key = $key . '?imageMogr2/thumbnail/!' . $this->thumb_rate . 'p'; + } + return $key; + } + + + /** + * 获取上传配置信息 + * @return array + */ + public function getSystem() + { + $token = $this->app()->uploadToken($this->storageName); + $domain = $this->uploadUrl; + $key = $this->saveFileName(); + return compact('token', 'domain', 'key'); + } + + /** + * TODO 删除资源 + * @param $key + * @param $bucket + * @return mixed + */ + public function delete(string $key) + { + $bucketManager = new BucketManager($this->app(), new Config()); + return $bucketManager->delete($this->storageName, $key); + } + + /** + * 获取七牛云上传密钥 + * @return mixed|string + */ + public function getTempKeys() + { + $token = $this->app()->uploadToken($this->storageName); + $domain = $this->uploadUrl; + $key = $this->saveFileName(NULL, 'mp4'); + $type = 'QINIU'; + $cdn = $this->cdn; + return compact('token', 'domain', 'key', 'type', 'cdn'); + } +} diff --git a/crmeb/services/upload/storage/Us3.php b/crmeb/services/upload/storage/Us3.php new file mode 100644 index 00000000..496ca230 --- /dev/null +++ b/crmeb/services/upload/storage/Us3.php @@ -0,0 +1,253 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\services\upload\storage; + +use crmeb\basic\BaseUpload; +use crmeb\exceptions\UploadException; +use crmeb\services\upload\client\UploadManager; +use think\exception\ValidateException; +use UCloud\Auth; + + +/** + * TODO Ucloud us3 + * Class Us3 + */ +class Us3 extends BaseUpload +{ + /** + * accessKey + * @var mixed + */ + protected $accessKey; + + /** + * secretKey + * @var mixed + */ + protected $secretKey; + + /** + * 句柄 + * @var object + */ + public $handle; + + /** + * 空间域名 Domain + * @var mixed + */ + protected $uploadUrl; + + /** + * 存储空间名称 公开空间 + * @var mixed + */ + protected $storageName; + + /** + * COS使用 所属地域 + * @var mixed|null + */ + protected $storageRegion; + + /** + * cdn 域名 + * @var + */ + protected $cdn; + + /** + * 缩略图配置 + * @var + */ + protected $thumbConfig; + + /** + * 缩略图开关 + * @var mixed|null + */ + protected $thumb_status; + + /** + * 缩略图比例 + * @var mixed|null + */ + protected $thumb_rate; + + + /** + * 初始化 + * @param array $config + * @return mixed|void + */ + public function initialize(array $config) + { + parent::initialize($config); + $this->accessKey = $config['accessKey'] ?? null; + $this->secretKey = $config['secretKey'] ?? null; + $this->storageName = $config['storageName'] ?? null; + $this->storageRegion = $config['storageRegion'] ?? null; + $this->cdn = $config['cdn'] ?? null; + $this->thumb_status = $config['thumb_status']; + $this->thumb_rate = $config['thumb_rate']; + $this->uploadUrl = substr($config['uploadUrl'],strlen($config['storageName'])); + } + + /** + * 实例化 + * @return object|Auth + */ + public function app() + { + if (!$this->accessKey || !$this->secretKey) { + throw new UploadException('Please configure accessKey and secretKey'); + } + if (!$this->handle) + $this->handle = new Auth($this->accessKey, $this->secretKey, $this->uploadUrl); + return $this->handle; + } + + /** + * 上传文件 + * @param string $file + * @return array|bool|mixed|\StdClass|string + */ + public function move(string $file = 'file', $thubm = true) + { + $fileHandle = app()->request->file($file); + if (!$fileHandle) { + return $this->setError('Upload file does not exist'); + } + if ($this->validate) { + try { + validate([$file => $this->validate])->check([$file => $fileHandle]); + } catch (ValidateException $e) { + return $this->setError($e->getMessage()); + } + } + $key = $this->saveFileName($fileHandle->getRealPath(), $fileHandle->getOriginalExtension()); + $path = ($this->path ? trim($this->path, '/') . '/' : ''); + + try { + $uploadMgr = new UploadManager($this->app()); + [$result, $error] = $uploadMgr->PutFile($this->storageName, $path . $key, $fileHandle->getRealPath()); + if ($error !== null) { + return $this->setError($error); + } + + if ($this->cdn) { + $src = $this->cdn . $path . $key; + } else { + $src = 'https://' . $uploadMgr->MakePublicUrl($this->storageName, $path . $key); + } + + if ($thubm) $src = $this->thubm($src); + $this->fileInfo->uploadInfo = $result; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + /** + * 文件流上传 + * @param string $fileContent + * @param string|null $key + * @return array|bool|mixed|\StdClass + */ + public function stream(string $fileContent, string $key = null, $thubm = true) + { + $file = sys_get_temp_dir() . $key; + file_put_contents($file, $fileContent, true); + if (!$key) { + $key = $this->saveFileName(); + } + $path = ($this->path ? trim($this->path, '/') . '/' : ''); + + + try { + $uploadMgr = new UploadManager($this->app()); + list($result, $err) = $uploadMgr->MultipartForm($this->storageName, $path . $key, $file); + unlink($file); + if ($err !== null) { + return array(null, $err); + } + if ($this->cdn) { + $src = $this->cdn . '/'.$path . $key; + } else { + $src = 'https://' . $uploadMgr->MakePublicUrl($this->storageName, $path . $key); + } + + if ($thubm) $src = $this->thubm($src); + $this->fileInfo->uploadInfo = $result; + $this->fileInfo->filePath = $src; + $this->fileInfo->fileName = $key; + return $this->fileInfo; + } catch (UploadException $e) { + return $this->setError($e->getMessage()); + } + } + + public function thubm(string $key) + { + if ($this->thumb_status && $key) { + $key = $key . '?iopcmd=thumbnail&type=1&scale=' . $this->thumb_rate; + } + return $key; + } + + + /** + * 获取上传配置信息 + * @return array + */ + public function getSystem() + { + $token = $this->app()->uploadToken($this->storageName); + $domain = $this->uploadUrl; + $key = $this->saveFileName(); + return compact('token', 'domain', 'key'); + } + + /** + * TODO 删除资源 + * @param $key + * @param $bucket + * @return mixed + */ + public function delete(string $key) + { + $bucketManager = new UploadManager($this->app()); + return $bucketManager->delete($this->storageName, $key); + } + + /** + * + * @return mixed|string + */ + public function getTempKeys() + { + + return [ + 'accessid' => $this->accessKey, + 'secretKey' => $this->secretKey, + 'host' => $this->uploadUrl, + 'storageName' => $this->storageName, + 'cdn' => $this->cdn, + 'type' => 'US3' + ]; + } +} diff --git a/crmeb/traits/CategoresDao.php b/crmeb/traits/CategoresDao.php new file mode 100644 index 00000000..b456c8dd --- /dev/null +++ b/crmeb/traits/CategoresDao.php @@ -0,0 +1,251 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\traits; + +trait CategoresDao +{ + public $path = 'path'; + public $pathTag = '/'; + public $level = 'level'; + public $maxLevel = 3; + public $parentId = 'pid'; + public $status = 'is_show'; + + /** + * @return mixed + * @author Qinii + */ + public function getPath():string + { + return $this->path; + } + + /** + * @return mixed + * @author Qinii + */ + public function getPathTag():string + { + return $this->pathTag; + } + + /** + * @return mixed + */ + public function getLevel():string + { + return $this->level; + } + + /** + * @return int + * @author Qinii + */ + public function getMaxLevel():int + { + return $this->maxLevel; + } + + /** + * @return int + * @return string + */ + public function getParentId(): string + { + return $this->parentId; + } + + /** + * @return int + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + /** + * 获取所有分类 + * @param int $mer_id + * @return mixed + * @author Qinii + */ + public function getAll($mer_id = 0,$status = null) + { + return $this->getModel()::getDB()->where('mer_id', $mer_id)->when(($status !== null),function($query)use($status){ + $query->where($this->getStatus(),$status); + })->order('sort DESC,'.$this->getPk().' DESC')->select(); + } + + /** + * 通过id 获取path + * @param int $id 需要检测的数据 + * @return string + * @author Qinii + * @date 2020-03-30 + */ + public function getPathById($id) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->value($this->getPath()); + } + + /** + * 根据id 获取 等级 + * @param $id + * @return mixed + * @author Qinii + */ + public function getLevelById($id) + { + return ($this->getModel())::getDB()->where($this->getPk(), $id)->value(($this->getLevel())); + } + + /** + * 根据 字段名查询 + * @param int $merId + * @param $field + * @param $value + * @param null $except + * @return bool + * @author Qinii + */ + public function merFieldExists(int $merId, $field, $value, $except = null) + { + return ($this->getModel())::getDB() + ->when($except, function ($query, $except) use ($field) { + $query->where($field, '<>', $except); + }) + ->where('mer_id', $merId) + ->where($field, $value)->count() > 0; + } + + /** + * 获取子集 等级 数组 + * @param $id + * @return array + * @author Qinii + */ + public function getChildLevelById($id) + { + $level = ($this->getModel()::getDB())->where($this->getPath(),'like',$this->getPathById($id).$id.$this->getPathTag().'%')->column($this->getLevel()); + return (is_array($level) && !empty($level)) ? $level : [0]; + } + + /** + * 查询修改目标是否为自己到子集 + * @param int $id + * @param int $pid + * @return mixed + * @author Qinii + */ + public function checkChangeToChild(int $id,int $pid) + { + return ($this->getModel()::getDB()) + ->where($this->getPath(),'like',$this->getPathById($id).$id.$this->getPathTag().'%') + ->where($this->getPk(),$pid) + ->count(); + } + + /** + * 是否存在子集 + * @param int $id + * @return mixed + * @author Qinii + */ + public function hasChild(int $id) + { + return ($this->getModel()::getDB())->where($this->getPath(),'like',$this->getPathById($id).$id.$this->getPathTag().'%')->count(); + } + + /** + * 编辑 + * @param int $id + * @param array $data + * @author Qinii + */ + public function updateParent(int $id,array $data) + { + ($this->getModel()::getDB())->transaction(function()use($id,$data){ + $change = $data['change']; + unset($data['change']); + ($this->getModel()::getDB())->where($this->getPk(),$id)->update($data); + + $this->updateChild($change['oldPath'],$change['newPath'],$change['changeLevel']); + }); + } + + /** + * 修改子类 + * @param string $oldPath + * @param string $newPath + * @param $changeLevel + * @author Qinii + */ + public function updateChild(string $oldPath,string $newPath, $changeLevel) + { + $query = ($this->getModel()::getDB())->where($this->getPath(),'like',$oldPath.'%') + ->select(); + if ($query) { + $query->each(function ($item) use ($oldPath, $newPath, $changeLevel) { + $child = ($this->getModel()::getDB())->find($item[$this->getPk()]); + $child->path = str_replace($oldPath, $newPath, $child->path); + $child->level = $child->level + $changeLevel; + $child->save(); + }); + } + } + + /** + * 修改状态 + * @param int $id + * @param int $status + * @return mixed + * @author Qinii + */ + public function switchStatus(int $id,int $status) + { + return ($this->getModel()::getDB())->where($this->getPk(),$id)->update([ + $this->getStatus() => $status + ]); + } + + + /** + * 获取列表 -- 筛选用 + * @Author:Qinii + * @Date: 2020/5/16 + * @param int|null $mer_id + * @return mixed + */ + public function getAllOptions($mer_id = null,$status = null,$level = null) + { + $field = $this->getParentId().',cate_name'; + $query = ($this->getModel()::getDB()); + $query->when(($mer_id !== null),function($query)use($mer_id){ + $query->where('mer_id', $mer_id); + }) + ->when($status,function($query)use($status){ + $query->where($this->getStatus(),$status); + }) + ->when(($level != '' && $level != null),function($query)use($level){ + $query->where($this->getLevel(),'<',$level); + }); + return $query->order('sort DESC,'.$this->getPk().' DESC')->column($field, $this->getPk()); + } + + public function switchStatusAndChild(int $id,$status) + { + $parent = $this->getModel()::find($id); + ($this->getModel()::getDB())->where($this->getPk(),$id)->update([$this->getStatus() => $status]); + return ($this->getModel()::getDB())->where('path','like',$parent->path.$id.'/%')->update([$this->getStatus() => $status]); + } +} diff --git a/crmeb/traits/CategoresRepository.php b/crmeb/traits/CategoresRepository.php new file mode 100644 index 00000000..9bcb3ec4 --- /dev/null +++ b/crmeb/traits/CategoresRepository.php @@ -0,0 +1,226 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\traits; + +trait CategoresRepository +{ + + /** + * 获得分级 列表 + * @param $merID + * @return array + * @author Qinii + */ + public function getFormatList($merID,$status = null) + { + return formatCategory($this->dao->getAll($merID,$status)->hidden(['path'])->toArray(), $this->dao->getPk()); + } + + /** + * @Author:Qinii + * @Date: 2020/5/28 + * @param $merID + * @param null $status + * @return array + */ + public function getApiFormatList($merID,$status = null) + { + return formatCategory($this->dao->getAll($merID,$status)->hidden(['path','level','mer_id','create_time'])->toArray(), $this->dao->getPk()); + } + + /** + * 筛选用 + * @Author:Qinii + * @Date: 2020/5/16 + * @param int $merId + * @return array + */ + public function getTreeList(int $merId = 0,$status = 0) + { + $data = $this->dao->getAllOptions($merId,$status); + return formatCascaderData($data,'cate_name'); + } + + /** + * 提交的pid 是否等于当前pid + * @param int $id + * @param int $pid + * @author Qinii + */ + public function checkUpdate(int $id,int $pid) + { + return (($this->dao->get($id))[$this->dao->getParentId()] == $pid) ? true : false; + } + + /** + * 检测是否超过最低等级限制 + * @param int $id + * @param int $level + * @return bool + * @author Qinii + */ + public function checkLevel(int $id,int $level = 0) + { + + $check = $this->getLevelById($id); + if($level) $check = $level; + return ($check < $this->dao->getMaxLevel()) ? true : false; + } + + + /** + * 根据ID 查询是否存在 + * @param int $merId + * @param int $id + * @param null $except + * @return mixed + * @author Qinii + */ + public function merExists(int $merId, int $id, $except = null) + { + return ($this->dao->merFieldExists($merId, $this->getPk(), $id, $except)); + } + + /** + * 通过id获取 path + * @param int $id + * @return string + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function getPathById(int $id) + { + $path = $this->dao->getPathById($id); + if ($path) $path = $path.$id.$this->dao->getPathTag(); + return $path ?? $this->dao->getPathTag(); + } + + /** + * 通过id获取 + 1等级 + * @param int $id + * @return int|mixed + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function getLevelById(int $id) + { + $level = 0; + if(($parentLevel = $this->dao->getLevelById($id)) !== null) + $level = $parentLevel + 1; + return $level; + } + + + /** + * 编辑时 子集是否 超过最低限制 + * @param int $id + * @param int $pid + * @return bool + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function checkChildLevel(int $id,int $pid) + { + //计算子集最大的数组等级 + + $childLevel = max($this->dao->getChildLevelById($id)); //1 + $changLevel = $childLevel + ($this->changeLevel($id,$pid)); //2 + return $this->checkLevel($id, $changLevel); + } + + /** + * 变动等级差 + * @param int $id + * @param int $pid + * @return int|mixed + * @author Qinii + * 0->1 1-> 2 2-> 3 + * 3->2 2-> 1 1-> 0 + */ + public function changeLevel(int $id,int $pid) + { + $level = $this->dao->getLevelById($pid); + return ($level + 1 ) - ($level); + } + + /** + * 检测 是否修改到 子集 + * @param int $id + * @param int $pid + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function checkChangeToChild(int $id, int $pid) + { + return ($this->dao->checkChangeToChild($id,$pid) > 0) ? false : true; + } + + /** + * 子集是否存在 + * @param int $id + * @return bool + * @author Qinii + */ + public function hasChild(int $id) + { + return (($this->dao->hasChild($id)) > 0) ? true : false ; + } + + /** + * 添加 + * @param array $data + * @return \app\common\dao\BaseDao|\think\Model + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author Qinii + */ + public function create(array $data) + { + $data[$this->dao->getPath()] = $this->getPathById($data[$this->dao->getParentId()]); + $data[$this->dao->getLevel()] = $this->getLevelById($data[$this->dao->getParentId()]); + return ($this->dao->create($data)); + } + + /** + * 修改 + * @param int $id + * @param array $data + * @author Qinii + */ + public function update(int $id,array $data) + { + + if($this->checkUpdate($id,$data['pid'])){ + $this->dao->update($id,$data); + } else { + $data[$this->dao->getPath()] = $this->getPathById($data[$this->dao->getParentId()]); + $data[$this->dao->getLevel()] = $this->getLevelById($data[$this->dao->getParentId()]); + + $data['change'] = [ + 'oldPath' => $this->dao->getPathById($id).$id.$this->getPathTag(), + 'newPath' => $data[$this->dao->getPath()].$id.$this->getPathTag(), + 'changeLevel' => $this->changeLevel($id,$data[$this->getParentId()]), + ]; + $this->dao->updateParent($id,$data); + } + } +} diff --git a/crmeb/traits/ErrorTrait.php b/crmeb/traits/ErrorTrait.php new file mode 100644 index 00000000..a126b044 --- /dev/null +++ b/crmeb/traits/ErrorTrait.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\traits; + +/** + * + * Class BaseError + * @package crmeb\basic + */ +trait ErrorTrait +{ + /** + * 错误信息 + * @var string + */ + protected $error; + + /** + * 设置错误信息 + * @param string|null $error + * @return bool + */ + protected function setError(?string $error = null) + { + $this->error = $error ?: '未知错误'; + return false; + } + + /** + * 获取错误信息 + * @return string + */ + public function getError() + { + $error = $this->error; + $this->error = null; + return $error; + } +} diff --git a/crmeb/traits/Macro.php b/crmeb/traits/Macro.php new file mode 100644 index 00000000..c87417fa --- /dev/null +++ b/crmeb/traits/Macro.php @@ -0,0 +1,73 @@ + +// +---------------------------------------------------------------------- + + +namespace crmeb\traits; + + +use BadMethodCallException; +use Closure; + +trait Macro +{ + protected $macroList = []; + + /** + * @param string $name + * @param $macro + * @author xaboy + * @day 2020-04-10 + */ + public function macro(string $name, $macro) + { + $this->macroList[$name] = $macro; + } + + /** + * @param array $names + * @param $macro + * @author xaboy + * @day 2020-04-10 + */ + public function macros(array $names, $macro) + { + foreach ($names as $name) { + $this->macro($name, $macro); + } + } + + /** + * @param string $name + * @return bool + * @author xaboy + * @day 2020-04-10 + */ + public function hasMacro(string $name): bool + { + return isset($this->macroList[$name]); + } + + public function __call($method, $parameters) + { + if (!$this->hasMacro($method)) { + throw new BadMethodCallException("Method {$method} does not exist."); + } + + $macro = $this->macroList[$method]; + + if ($macro instanceof Closure) { + return call_user_func_array($macro->bindTo($this, static::class), $parameters); + } + + return call_user_func_array($macro, $parameters); + } +} diff --git a/crmeb/utils/ApiErrorCode.php b/crmeb/utils/ApiErrorCode.php new file mode 100644 index 00000000..80446a7e --- /dev/null +++ b/crmeb/utils/ApiErrorCode.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\utils; + +/** + * 错误码统一存放类 + * Class ApiErrorCode + * @package crmeb\services + */ +class ApiErrorCode +{ + + const SUCCESS = [200, 'SUCCESS']; + const ERROR = [400, 'ERROR']; + + const ERR_LOGIN_INVALID = [410000, 'Landing overdue']; + const ERR_AUTH = [400011, 'You do not have permission to access for the time being']; + const ERR_RULE = [400012, 'Interface is not authorized, you cannot access']; + const ERR_ADMINID_VOID = [400013, 'Failed to get administrator ID']; + //保存token失败 + const ERR_SAVE_TOKEN = [400, 'Failed to save token']; + //登陆状态不正确 + const ERR_LOGIN_STATUS = [410002, 'The login status is incorrect. Please login again.']; + //请登陆 + const ERR_LOGIN = [410000, 'Please login']; + + //公众号访问错误请求码 + const ERROR_WECHAT_MESSAGE = [ + 45007 => 'graphic message limit exceeded', + 45008 => 'voice playback time exceeds the limit', + 45006 => 'image link field exceeds limit', + 45005 => 'link field exceeds limit', + 45004 => 'description field exceeds limit', + 45003 => 'header field exceeds limit', + 45002 => 'message content exceeds limit', + 45001 => 'multimedia file size exceeds limit', + 44004 => 'the text message content is empty', + 44003 => 'text message content is empty', + 44001 => 'the multimedia file is empty', + 44002 => 'multimedia file is empty The packet of 44002 post is empty', + 43019 => 'the recipient needs to be removed from the blacklist', + 43005 => 'need a friend relationship', + 43004 => 'needs attention of receiver', + 43005 => 'need to be friends', + 43003 => 'requires HTTPS request', + 43002 => 'post request required', + 43001 => 'get request required', + 42007 => 'user changes wechat password, accesstoken and refreshtoken are invalid and need to be re authorized', + 42003 => 'oauth_ Code timeout', + 42002 => 'refresh_ Token timeout', + 42001 => 'access_ Token timeout, please check access_ For the validity of token, please refer to basic support - access_ In token, for access_ Detailed description of token mechanism', + 41009 => 'missing openid', + 41008 => 'missing OAuth code', + 41007 => 'missing submenu data', + 41006 => 'lack of media_ ID parameter', + 41005 => 'missing multimedia file data', + 41004 => 'missing secret parameter', + 41003 => 'missing refresh_ Token parameter', + 41002 => 'missing appid parameter', + 41001 => 'missing access_ Token parameter', + 40163 => 'oauth_ Code used', + 40155 => 'do not add any other official account\'s home page links.', + 40137 => 'image format not supported', + 40132 => 'illegal micro signal', + 40125 => 'invalid appsecret', + 40121 => 'illegal media_ ID type', + 40120 => 'sub button type error', + 40119 => 'button type error', + 40118 => 'media_ Illegal ID size', + 40117 => 'illegal group name', + 40060 => 'when deleting a single text, the specified article_ Illegal idx', + 40051 => 'illegal group name', + 40048 => 'invalid URL', + 40050 => 'illegal group ID', + 40040 => 'invalid URL', + 40039 => 'illegal URL length', + 40038 => 'illegal request format', + 40035 => 'illegal parameter', + 40033 => "illegal request character, can't contain character in the format of 'uxxxx'", + 40032 => 'illegal openid list length', + 40031 => 'Illegal openid list', + 40030 => 'Illegal refresh_ token', + 40029 => 'invalid OAuth_ code', + 40028 => 'Illegal custom menu user', + 40027 => 'Illegal submenu button URL length', + 40026 => 'Illegal submenu button key length', + 40025 => 'Illegal submenu button name length', + 40024 => 'Illegal submenu button type', + 40023 => 'Illegal number of submenu buttons', + 40022 => 'Illegal submenu series', + 40021 => 'Illegal menu version number', + 40020 => 'Illegal button URL length', + 40019 => 'Illegal key length of button', + 40018 => 'Illegal button name length', + 40017 => 'Illegal button type', + 40016 => 'Number of illegal buttons', + 40015 => 'Illegal menu type', + 40014 => 'Illegal access_ Token, please compare access carefully_ The validity of token (if expired), or whether to call the interface for the appropriate official account.', + 40013 => 'Illegal appid, please check the correctness of appid, avoid abnormal characters and pay attention to case', + 40012 => 'Illegal thumbnail file size', + 40011 => 'Illegal video file size', + 40010 => 'Illegal voice file size', + 40009 => 'Illegal image file size', + 40008 => 'Illegal message type', + 40007 => 'Illegal media file ID', + 40006 => 'Illegal file size', + 40005 => 'Illegal file type', + 40004 => 'Illegal media file type', + 40002 => 'Illegal voucher type', + 40003 => 'Illegal OpenID, developers confirm whether OpenID has been concerned about the official account number, or whether it is OpenID of other official account.', + 40001 => 'Get access_ Appsecret error in token, or access_ Token is not valid. Developers are asked to compare the correctness of AppSecret with the official account, or to see if the interface is being invoked for the appropriate public number.' + ]; + + +} diff --git a/crmeb/utils/Start.php b/crmeb/utils/Start.php new file mode 100644 index 00000000..be94aa58 --- /dev/null +++ b/crmeb/utils/Start.php @@ -0,0 +1,110 @@ + +// +---------------------------------------------------------------------- + +namespace crmeb\utils; + +use think\App; + +/** + * Start输出类 + * Class Json + * @package crmeb\utils + */ +class Start +{ + protected $context = ''; + const LINE = '------------------------------------------------'.PHP_EOL; + public function show() + { + $this->opCacheClear(); + $this->context = $this->logo(); + $this->context .= self::LINE; + $this->displayItem('php version', phpversion()); + $this->displayItem('swoole version', phpversion('swoole')); + $this->displayItem('swoole_loader version', phpversion('swoole_loader')); + $this->displayItem('thinkphp version', App::VERSION); + $this->displayItem('crmeb version', get_crmeb_version()); + + //http配置 + $httpConf = \config("swoole.server"); + $this->displayItem('http host', $httpConf["host"]); + $this->displayItem('http port', $httpConf["port"]); + $this->displayItem('http worker_num', $httpConf['options']["worker_num"]); + + //websocket配置 + $this->displayItem('websocket enable', \config("swoole.websocket.enable")); + + //rpc配置 + $rpcConf = \config("swoole.rpc.server"); + $this->displayItem('rpc enable', $rpcConf["enable"]); + if ($rpcConf["enable"]) { + $this->displayItem('rpc host', $rpcConf["host"]); + $this->displayItem('rpc port', $rpcConf["port"]); + $this->displayItem('rpc worker_num', $rpcConf["worker_num"]); + } + + //队列配置 + $this->displayItem('queue enable', \config("swoole.queue.enable")); + + //热更新配置 + $this->displayItem('hot_update enable', (bool)\config("swoole.hot_update.enable")); + + //debug配置 + $this->displayItem('app_debug enable', (bool)env("APP_DEBUG")); + + $this->displayItem('time', date('Y-m-d H:i:s')); + + //打印信息 + echo $this->context; + } + + + private function logo() + { + return <<context .= "\e[32m" . str_pad($name, 25, ' ', STR_PAD_RIGHT) .'| '. "\e[34m" . $value . "\e[0m \n"; + $this->context .= self::LINE; + } + + private function opCacheClear() + { + if (function_exists('apc_clear_cache')) { + apc_clear_cache(); + } + if (function_exists('opcache_reset')) { + opcache_reset(); + } + } +} diff --git a/extend/.gitignore b/extend/.gitignore new file mode 100644 index 00000000..528d7ed7 --- /dev/null +++ b/extend/.gitignore @@ -0,0 +1,4 @@ +mp-weixin/* +download/* +!.gitignore +!express.xlsx diff --git a/think b/think new file mode 100644 index 00000000..2429d223 --- /dev/null +++ b/think @@ -0,0 +1,10 @@ +#!/usr/bin/env php +console->run(); \ No newline at end of file