正在显示
53 个修改的文件
包含
4764 行增加
和
0 行删除
addons/groupon/.addonrc
0 → 100644
1 | +{"files":["application\\admin\\controller\\groupon\\activity\\Activity.php","application\\admin\\controller\\groupon\\Admin.php","application\\admin\\controller\\groupon\\Area.php","application\\admin\\controller\\groupon\\Base.php","application\\admin\\controller\\groupon\\Category.php","application\\admin\\controller\\groupon\\Config.php","application\\admin\\controller\\groupon\\Coupons.php","application\\admin\\controller\\groupon\\Decorate.php","application\\admin\\controller\\groupon\\Express.php","application\\admin\\controller\\groupon\\Faq.php","application\\admin\\controller\\groupon\\Feedback.php","application\\admin\\controller\\groupon\\goods\\Comment.php","application\\admin\\controller\\groupon\\goods\\Goods.php","application\\admin\\controller\\groupon\\goods\\Service.php","application\\admin\\controller\\groupon\\goods\\Sku.php","application\\admin\\controller\\groupon\\goods\\SkuPrice.php","application\\admin\\controller\\groupon\\goods\\StockWarning.php","application\\admin\\controller\\groupon\\Link.php","application\\admin\\controller\\groupon\\Notification.php","application\\admin\\controller\\groupon\\order\\Order.php","application\\admin\\controller\\groupon\\order\\OrderItem.php","application\\admin\\controller\\groupon\\order\\StoreExpress.php","application\\admin\\controller\\groupon\\Richtext.php","application\\admin\\controller\\groupon\\store\\Apply.php","application\\admin\\controller\\groupon\\store\\Dashboard.php","application\\admin\\controller\\groupon\\store\\Store.php","application\\admin\\controller\\groupon\\store\\TakeLog.php","application\\admin\\controller\\groupon\\Upload.php","application\\admin\\controller\\groupon\\user\\Group.php","application\\admin\\controller\\groupon\\user\\Rule.php","application\\admin\\controller\\groupon\\user\\User.php","application\\admin\\controller\\groupon\\UserWalletApply.php","application\\admin\\lang\\zh-cn\\groupon\\area.php","application\\admin\\lang\\zh-cn\\groupon\\category.php","application\\admin\\lang\\zh-cn\\groupon\\config.php","application\\admin\\lang\\zh-cn\\groupon\\coupons.php","application\\admin\\lang\\zh-cn\\groupon\\decorate.php","application\\admin\\lang\\zh-cn\\groupon\\faq.php","application\\admin\\lang\\zh-cn\\groupon\\feedback.php","application\\admin\\lang\\zh-cn\\groupon\\goods\\comment.php","application\\admin\\lang\\zh-cn\\groupon\\goods\\goods.php","application\\admin\\lang\\zh-cn\\groupon\\goods\\service.php","application\\admin\\lang\\zh-cn\\groupon\\goods\\sku.php","application\\admin\\lang\\zh-cn\\groupon\\goods\\sku_price.php","application\\admin\\lang\\zh-cn\\groupon\\link.php","application\\admin\\lang\\zh-cn\\groupon\\notification\\config.php","application\\admin\\lang\\zh-cn\\groupon\\notification.php","application\\admin\\lang\\zh-cn\\groupon\\order\\order.php","application\\admin\\lang\\zh-cn\\groupon\\order\\order_item.php","application\\admin\\lang\\zh-cn\\groupon\\order\\refund_log.php","application\\admin\\lang\\zh-cn\\groupon\\richtext.php","application\\admin\\lang\\zh-cn\\groupon\\share.php","application\\admin\\lang\\zh-cn\\groupon\\store\\apply.php","application\\admin\\lang\\zh-cn\\groupon\\upload.php","application\\admin\\lang\\zh-cn\\groupon\\user\\group.php","application\\admin\\lang\\zh-cn\\groupon\\user\\rule.php","application\\admin\\lang\\zh-cn\\groupon\\user\\user.php","application\\admin\\lang\\zh-cn\\groupon\\user_wallet_apply.php","application\\admin\\model\\groupon\\activity\\Activity.php","application\\admin\\model\\groupon\\Area.php","application\\admin\\model\\groupon\\Category.php","application\\admin\\model\\groupon\\Config.php","application\\admin\\model\\groupon\\Coupons.php","application\\admin\\model\\groupon\\Decorate.php","application\\admin\\model\\groupon\\DecorateContent.php","application\\admin\\model\\groupon\\DecoratePage.php","application\\admin\\model\\groupon\\dispatch\\ExpressCompany.php","application\\admin\\model\\groupon\\Express.php","application\\admin\\model\\groupon\\Faq.php","application\\admin\\model\\groupon\\Feedback.php","application\\admin\\model\\groupon\\goods\\Comment.php","application\\admin\\model\\groupon\\goods\\Goods.php","application\\admin\\model\\groupon\\goods\\Service.php","application\\admin\\model\\groupon\\goods\\Sku.php","application\\admin\\model\\groupon\\goods\\SkuPrice.php","application\\admin\\model\\groupon\\goods\\StockWarning.php","application\\admin\\model\\groupon\\Link.php","application\\admin\\model\\groupon\\notification\\Config.php","application\\admin\\model\\groupon\\Notification.php","application\\admin\\model\\groupon\\order\\Order.php","application\\admin\\model\\groupon\\order\\OrderAction.php","application\\admin\\model\\groupon\\order\\OrderExpress.php","application\\admin\\model\\groupon\\order\\OrderExpressLog.php","application\\admin\\model\\groupon\\order\\OrderItem.php","application\\admin\\model\\groupon\\order\\OrderStoreExpress.php","application\\admin\\model\\groupon\\order\\RefundLog.php","application\\admin\\model\\groupon\\Richtext.php","application\\admin\\model\\groupon\\Share.php","application\\admin\\model\\groupon\\store\\Apply.php","application\\admin\\model\\groupon\\store\\Recruit.php","application\\admin\\model\\groupon\\store\\Store.php","application\\admin\\model\\groupon\\store\\TakeLog.php","application\\admin\\model\\groupon\\Upload.php","application\\admin\\model\\groupon\\user\\Coupon.php","application\\admin\\model\\groupon\\user\\Favorite.php","application\\admin\\model\\groupon\\user\\Group.php","application\\admin\\model\\groupon\\user\\MoneyLog.php","application\\admin\\model\\groupon\\user\\Oauth.php","application\\admin\\model\\groupon\\user\\ScoreLog.php","application\\admin\\model\\groupon\\user\\User.php","application\\admin\\model\\groupon\\user\\View.php","application\\admin\\model\\groupon\\UserFake.php","application\\admin\\model\\groupon\\UserWalletApply.php","application\\admin\\model\\groupon\\wechat\\Fans.php","application\\admin\\model\\groupon\\wechat\\Wechat.php","application\\admin\\validate\\groupon\\activity\\Activity.php","application\\admin\\validate\\groupon\\Area.php","application\\admin\\validate\\groupon\\Category.php","application\\admin\\validate\\groupon\\Config.php","application\\admin\\validate\\groupon\\Coupons.php","application\\admin\\validate\\groupon\\Decorate.php","application\\admin\\validate\\groupon\\Faq.php","application\\admin\\validate\\groupon\\Feedback.php","application\\admin\\validate\\groupon\\Goods.php","application\\admin\\validate\\groupon\\GoodsComment.php","application\\admin\\validate\\groupon\\GoodsService.php","application\\admin\\validate\\groupon\\GoodsSku.php","application\\admin\\validate\\groupon\\GoodsSkuPrice.php","application\\admin\\validate\\groupon\\Link.php","application\\admin\\validate\\groupon\\notification\\Config.php","application\\admin\\validate\\groupon\\Notification.php","application\\admin\\validate\\groupon\\Notification_config.php","application\\admin\\validate\\groupon\\order\\Order.php","application\\admin\\validate\\groupon\\order\\OrderItem.php","application\\admin\\validate\\groupon\\Richtext.php","application\\admin\\validate\\groupon\\store\\Apply.php","application\\admin\\validate\\groupon\\Upload.php","application\\admin\\validate\\groupon\\UserWalletApply.php","application\\admin\\view\\groupon\\activity\\activity\\edit.html","application\\admin\\view\\groupon\\activity\\activity\\index.html","application\\admin\\view\\groupon\\activity\\activity\\recyclebin.html","application\\admin\\view\\groupon\\activity\\activity\\select.html","application\\admin\\view\\groupon\\area\\add.html","application\\admin\\view\\groupon\\area\\edit.html","application\\admin\\view\\groupon\\area\\index.html","application\\admin\\view\\groupon\\area\\select.html","application\\admin\\view\\groupon\\category\\index.html","application\\admin\\view\\groupon\\category\\select.html","application\\admin\\view\\groupon\\config\\add.html","application\\admin\\view\\groupon\\config\\edit.html","application\\admin\\view\\groupon\\config\\index.html","application\\admin\\view\\groupon\\config\\platform.html","application\\admin\\view\\groupon\\coupons\\add.html","application\\admin\\view\\groupon\\coupons\\edit.html","application\\admin\\view\\groupon\\coupons\\index.html","application\\admin\\view\\groupon\\coupons\\recyclebin.html","application\\admin\\view\\groupon\\coupons\\select.html","application\\admin\\view\\groupon\\decorate\\custom.html","application\\admin\\view\\groupon\\decorate\\dodecorate.html","application\\admin\\view\\groupon\\decorate\\lists.html","application\\admin\\view\\groupon\\decorate\\recyclebin.html","application\\admin\\view\\groupon\\decorate\\select.html","application\\admin\\view\\groupon\\express\\add.html","application\\admin\\view\\groupon\\express\\edit.html","application\\admin\\view\\groupon\\express\\index.html","application\\admin\\view\\groupon\\faq\\add.html","application\\admin\\view\\groupon\\faq\\edit.html","application\\admin\\view\\groupon\\faq\\index.html","application\\admin\\view\\groupon\\faq\\recyclebin.html","application\\admin\\view\\groupon\\feedback\\edit.html","application\\admin\\view\\groupon\\feedback\\index.html","application\\admin\\view\\groupon\\feedback\\recyclebin.html","application\\admin\\view\\groupon\\goods\\comment\\add.html","application\\admin\\view\\groupon\\goods\\comment\\edit.html","application\\admin\\view\\groupon\\goods\\comment\\index.html","application\\admin\\view\\groupon\\goods\\comment\\recyclebin.html","application\\admin\\view\\groupon\\goods\\goods\\add.html","application\\admin\\view\\groupon\\goods\\goods\\edit.html","application\\admin\\view\\groupon\\goods\\goods\\index.html","application\\admin\\view\\groupon\\goods\\goods\\recyclebin.html","application\\admin\\view\\groupon\\goods\\goods\\select.html","application\\admin\\view\\groupon\\goods\\goods\\sku.html","application\\admin\\view\\groupon\\goods\\goods\\skuedit.html","application\\admin\\view\\groupon\\goods\\service\\add.html","application\\admin\\view\\groupon\\goods\\service\\edit.html","application\\admin\\view\\groupon\\goods\\service\\index.html","application\\admin\\view\\groupon\\goods\\service\\recyclebin.html","application\\admin\\view\\groupon\\goods\\sku\\add.html","application\\admin\\view\\groupon\\goods\\sku\\edit.html","application\\admin\\view\\groupon\\goods\\sku\\index.html","application\\admin\\view\\groupon\\goods\\sku_price\\add.html","application\\admin\\view\\groupon\\goods\\sku_price\\edit.html","application\\admin\\view\\groupon\\goods\\sku_price\\index.html","application\\admin\\view\\groupon\\goods\\sku_price\\recyclebin.html","application\\admin\\view\\groupon\\goods\\stock_warning\\index.html","application\\admin\\view\\groupon\\goods\\stock_warning\\recyclebin.html","application\\admin\\view\\groupon\\link\\add.html","application\\admin\\view\\groupon\\link\\edit.html","application\\admin\\view\\groupon\\link\\index.html","application\\admin\\view\\groupon\\link\\recyclebin.html","application\\admin\\view\\groupon\\link\\select.html","application\\admin\\view\\groupon\\notification\\config.html","application\\admin\\view\\groupon\\order\\order\\detail.html","application\\admin\\view\\groupon\\order\\order\\index.html","application\\admin\\view\\groupon\\order\\order\\recyclebin.html","application\\admin\\view\\groupon\\order\\order_item\\add.html","application\\admin\\view\\groupon\\order\\order_item\\edit.html","application\\admin\\view\\groupon\\order\\order_item\\index.html","application\\admin\\view\\groupon\\order\\order_item\\recyclebin.html","application\\admin\\view\\groupon\\order\\store_express\\add.html","application\\admin\\view\\groupon\\order\\store_express\\detail.html","application\\admin\\view\\groupon\\order\\store_express\\index.html","application\\admin\\view\\groupon\\richtext\\add.html","application\\admin\\view\\groupon\\richtext\\edit.html","application\\admin\\view\\groupon\\richtext\\index.html","application\\admin\\view\\groupon\\richtext\\recyclebin.html","application\\admin\\view\\groupon\\richtext\\select.html","application\\admin\\view\\groupon\\store\\apply\\add.html","application\\admin\\view\\groupon\\store\\apply\\detail.html","application\\admin\\view\\groupon\\store\\apply\\edit.html","application\\admin\\view\\groupon\\store\\apply\\index.html","application\\admin\\view\\groupon\\store\\dashboard\\index.html","application\\admin\\view\\groupon\\store\\store\\add.html","application\\admin\\view\\groupon\\store\\store\\edit.html","application\\admin\\view\\groupon\\store\\store\\index.html","application\\admin\\view\\groupon\\store\\store\\recyclebin.html","application\\admin\\view\\groupon\\store\\take_log\\index.html","application\\admin\\view\\groupon\\user\\group\\add.html","application\\admin\\view\\groupon\\user\\group\\edit.html","application\\admin\\view\\groupon\\user\\group\\index.html","application\\admin\\view\\groupon\\user\\rule\\add.html","application\\admin\\view\\groupon\\user\\rule\\edit.html","application\\admin\\view\\groupon\\user\\rule\\index.html","application\\admin\\view\\groupon\\user\\user\\index.html","application\\admin\\view\\groupon\\user\\user\\money_recharge.html","application\\admin\\view\\groupon\\user\\user\\profile.html","application\\admin\\view\\groupon\\user\\user\\score_recharge.html","application\\admin\\view\\groupon\\user_wallet_apply\\index.html","public\\assets\\addons\\groupon\\img\\activity\\full_discount.png","public\\assets\\addons\\groupon\\img\\activity\\full_gift.png","public\\assets\\addons\\groupon\\img\\activity\\full_reduce.png","public\\assets\\addons\\groupon\\img\\category\\edit.png","public\\assets\\addons\\groupon\\img\\category\\img-1.png","public\\assets\\addons\\groupon\\img\\category\\img-2.png","public\\assets\\addons\\groupon\\img\\category\\img-3.png","public\\assets\\addons\\groupon\\img\\category\\img-4.png","public\\assets\\addons\\groupon\\img\\category\\selected.png","public\\assets\\addons\\groupon\\img\\config\\alipay-icon.png","public\\assets\\addons\\groupon\\img\\config\\App-icon.png","public\\assets\\addons\\groupon\\img\\config\\apple-icon.png","public\\assets\\addons\\groupon\\img\\config\\chat-icon.png","public\\assets\\addons\\groupon\\img\\config\\groupon-icon.png","public\\assets\\addons\\groupon\\img\\config\\h5-icon.png","public\\assets\\addons\\groupon\\img\\config\\order-icon.png","public\\assets\\addons\\groupon\\img\\config\\score-icon.png","public\\assets\\addons\\groupon\\img\\config\\services-icon.png","public\\assets\\addons\\groupon\\img\\config\\share-icon.png","public\\assets\\addons\\groupon\\img\\config\\store-icon.png","public\\assets\\addons\\groupon\\img\\config\\user-icon.png","public\\assets\\addons\\groupon\\img\\config\\wallet-icon.png","public\\assets\\addons\\groupon\\img\\config\\wechat-icon.png","public\\assets\\addons\\groupon\\img\\config\\withdraw-icon.png","public\\assets\\addons\\groupon\\img\\config\\wxMiniProgram-icon.png","public\\assets\\addons\\groupon\\img\\config\\wxOfficialAccount-icon.png","public\\assets\\addons\\groupon\\img\\decorate\\activity-fire.png","public\\assets\\addons\\groupon\\img\\decorate\\adv-default-2.png","public\\assets\\addons\\groupon\\img\\decorate\\adv.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_01.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_02.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_03.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_04.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_05.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_06.png","public\\assets\\addons\\groupon\\img\\decorate\\adv_07.png","public\\assets\\addons\\groupon\\img\\decorate\\banner.png","public\\assets\\addons\\groupon\\img\\decorate\\banner_default.png","public\\assets\\addons\\groupon\\img\\decorate\\cat.png","public\\assets\\addons\\groupon\\img\\decorate\\category_tabs.png","public\\assets\\addons\\groupon\\img\\decorate\\coupons.png","public\\assets\\addons\\groupon\\img\\decorate\\coupons_bg.png","public\\assets\\addons\\groupon\\img\\decorate\\float-button.png","public\\assets\\addons\\groupon\\img\\decorate\\goods-group.png","public\\assets\\addons\\groupon\\img\\decorate\\goods-list.png","public\\assets\\addons\\groupon\\img\\decorate\\header.png","public\\assets\\addons\\groupon\\img\\decorate\\hot-label.png","public\\assets\\addons\\groupon\\img\\decorate\\image-default.png","public\\assets\\addons\\groupon\\img\\decorate\\image-default2.png","public\\assets\\addons\\groupon\\img\\decorate\\image-default3.png","public\\assets\\addons\\groupon\\img\\decorate\\limit-time.png","public\\assets\\addons\\groupon\\img\\decorate\\menu.png","public\\assets\\addons\\groupon\\img\\decorate\\menu_default.gif","public\\assets\\addons\\groupon\\img\\decorate\\popup.png","public\\assets\\addons\\groupon\\img\\decorate\\special-image.png","public\\assets\\addons\\groupon\\img\\decorate\\store-image.jpg","public\\assets\\addons\\groupon\\img\\decorate\\store.png","public\\assets\\addons\\groupon\\img\\decorate\\tabs-active.png","public\\assets\\addons\\groupon\\img\\decorate\\template_name.png","public\\assets\\addons\\groupon\\img\\decorate\\title-block.png","public\\assets\\addons\\groupon\\img\\decorate\\title1.png","public\\assets\\addons\\groupon\\img\\decorate\\title2.png","public\\assets\\addons\\groupon\\img\\decorate\\title3.png","public\\assets\\addons\\groupon\\img\\decorate\\title4.png","public\\assets\\addons\\groupon\\img\\decorate\\title5.png","public\\assets\\addons\\groupon\\img\\decorate\\wxMiniProgram.png","public\\assets\\addons\\groupon\\img\\decorate\\zujian.png","public\\assets\\addons\\groupon\\img\\default-avatar.png","public\\assets\\addons\\groupon\\img\\derocate_down.png","public\\assets\\addons\\groupon\\img\\derocate_up.png","public\\assets\\addons\\groupon\\img\\goods\\active.png","public\\assets\\addons\\groupon\\img\\goods\\batch.png","public\\assets\\addons\\groupon\\img\\goods\\close.png","public\\assets\\addons\\groupon\\img\\goods\\hover.png","public\\assets\\addons\\groupon\\img\\goods\\move.png","public\\assets\\addons\\groupon\\img\\goods\\selected.png","public\\assets\\addons\\groupon\\img\\notification\\wxMiniProgram.png","public\\assets\\addons\\groupon\\img\\sku_close.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\aftersale.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\allordernum.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\noget.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\nosend.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\orderpersonnum.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\payed.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\paymoney.png","public\\assets\\addons\\groupon\\img\\store\\dashboard\\refund.png","public\\assets\\addons\\groupon\\img\\store\\position-icon.png","public\\assets\\addons\\groupon\\img\\user_wallet_apply\\alipay.png","public\\assets\\addons\\groupon\\img\\user_wallet_apply\\bank.png","public\\assets\\addons\\groupon\\img\\user_wallet_apply\\wechat.png","public\\assets\\addons\\groupon\\libs\\antv.js","public\\assets\\addons\\groupon\\libs\\clipboard.min.js","public\\assets\\addons\\groupon\\libs\\color-thief.js","public\\assets\\addons\\groupon\\libs\\common.css","public\\assets\\addons\\groupon\\libs\\element\\element.css","public\\assets\\addons\\groupon\\libs\\element\\element.js","public\\assets\\addons\\groupon\\libs\\element\\fonts\\element-icons.ttf","public\\assets\\addons\\groupon\\libs\\element\\fonts\\element-icons.woff","public\\assets\\addons\\groupon\\libs\\groupon.js","public\\assets\\addons\\groupon\\libs\\moment.js","public\\assets\\addons\\groupon\\libs\\require-text.js","public\\assets\\addons\\groupon\\libs\\Sortable.min.js","public\\assets\\addons\\groupon\\libs\\vue-dev.js","public\\assets\\addons\\groupon\\libs\\vue.js","public\\assets\\addons\\groupon\\libs\\vuedraggable.js","public\\assets\\js\\backend\\groupon\\activity\\activity.js","public\\assets\\js\\backend\\groupon\\area.js","public\\assets\\js\\backend\\groupon\\category.js","public\\assets\\js\\backend\\groupon\\config.js","public\\assets\\js\\backend\\groupon\\coupons.js","public\\assets\\js\\backend\\groupon\\decorate.js","public\\assets\\js\\backend\\groupon\\express.js","public\\assets\\js\\backend\\groupon\\faq.js","public\\assets\\js\\backend\\groupon\\feedback.js","public\\assets\\js\\backend\\groupon\\goods\\comment.js","public\\assets\\js\\backend\\groupon\\goods\\goods.js","public\\assets\\js\\backend\\groupon\\goods\\service.js","public\\assets\\js\\backend\\groupon\\goods\\sku.js","public\\assets\\js\\backend\\groupon\\goods\\sku_price.js","public\\assets\\js\\backend\\groupon\\goods\\stock_warning.js","public\\assets\\js\\backend\\groupon\\link.js","public\\assets\\js\\backend\\groupon\\notification.js","public\\assets\\js\\backend\\groupon\\order\\order.js","public\\assets\\js\\backend\\groupon\\order\\order_item.js","public\\assets\\js\\backend\\groupon\\order\\store_express.js","public\\assets\\js\\backend\\groupon\\richtext.js","public\\assets\\js\\backend\\groupon\\store\\apply.js","public\\assets\\js\\backend\\groupon\\store\\dashboard.js","public\\assets\\js\\backend\\groupon\\store\\store.js","public\\assets\\js\\backend\\groupon\\store\\take_log.js","public\\assets\\js\\backend\\groupon\\upload.js","public\\assets\\js\\backend\\groupon\\user\\group.js","public\\assets\\js\\backend\\groupon\\user\\user.js","public\\assets\\js\\backend\\groupon\\user_wallet_apply.js"],"license":"regular","licenseto":"44234","licensekey":"oO7jRk8tbSxzT2hJ QYIUbhnu2J0xrMQyJb0sfQ==","domains":[],"licensecodes":[],"validations":[],"menus":["groupon","groupon\/config","groupon\/config\/index","groupon\/config\/add","groupon\/config\/edit","groupon\/config\/del","groupon\/config\/multi","groupon\/config\/platform","groupon\/decorate","groupon\/decorate\/lists","groupon\/decorate\/add","groupon\/decorate\/edit","groupon\/decorate\/del","groupon\/decorate\/multi","groupon\/decorate\/recyclebin","groupon\/decorate\/destroy","groupon\/decorate\/restore","groupon\/decorate\/dodecorate","groupon\/decorate\/preview","groupon\/decorate\/custom","groupon\/decorate\/publish","groupon\/decorate\/dodecorate_save","groupon\/decorate\/copy","groupon\/decorate\/index","groupon\/decorate\/down","groupon\/coupons","groupon\/coupons\/index","groupon\/coupons\/recyclebin","groupon\/coupons\/add","groupon\/coupons\/edit","groupon\/coupons\/del","groupon\/coupons\/destroy","groupon\/coupons\/restore","groupon\/coupons\/multi","groupon\/coupons\/select","groupon\/product","groupon\/category","groupon\/category\/index","groupon\/category\/add","groupon\/category\/edit","groupon\/category\/del","groupon\/category\/multi","groupon\/category\/select","groupon\/category\/update","groupon\/goods\/goods","groupon\/goods\/goods\/index","groupon\/goods\/goods\/recyclebin","groupon\/goods\/goods\/add","groupon\/goods\/goods\/edit","groupon\/goods\/goods\/del","groupon\/goods\/goods\/destroy","groupon\/goods\/goods\/restore","groupon\/goods\/goods\/multi","groupon\/goods\/goods\/select","groupon\/goods\/goods\/detail","groupon\/goods\/goods\/setstatus","groupon\/goods\/service","groupon\/goods\/service\/index","groupon\/goods\/service\/recyclebin","groupon\/goods\/service\/add","groupon\/goods\/service\/edit","groupon\/goods\/service\/del","groupon\/goods\/service\/destroy","groupon\/goods\/service\/restore","groupon\/goods\/service\/multi","groupon\/goods\/comment","groupon\/goods\/comment\/index","groupon\/goods\/comment\/recyclebin","groupon\/goods\/comment\/add","groupon\/goods\/comment\/edit","groupon\/goods\/comment\/del","groupon\/goods\/comment\/destroy","groupon\/goods\/comment\/restore","groupon\/goods\/comment\/multi","groupon\/goods\/stock_warning","groupon\/goods\/stock_warning\/index","groupon\/goods\/stock_warning\/recyclebin","groupon\/goods\/stock_warning\/addstock","groupon\/goods\/stock_warning\/destroy","groupon\/material","groupon\/express","groupon\/express\/index","groupon\/express\/add","groupon\/express\/edit","groupon\/express\/del","groupon\/express\/multi","groupon\/express\/select","groupon\/richtext","groupon\/richtext\/index","groupon\/richtext\/recyclebin","groupon\/richtext\/add","groupon\/richtext\/edit","groupon\/richtext\/del","groupon\/richtext\/destroy","groupon\/richtext\/restore","groupon\/richtext\/multi","groupon\/richtext\/select","groupon\/link","groupon\/link\/index","groupon\/link\/recyclebin","groupon\/link\/add","groupon\/link\/edit","groupon\/link\/del","groupon\/link\/destroy","groupon\/link\/restore","groupon\/link\/multi","groupon\/link\/select","groupon\/area","groupon\/area\/index","groupon\/area\/add","groupon\/area\/edit","groupon\/area\/del","groupon\/area\/multi","groupon\/area\/select","groupon\/faq","groupon\/faq\/index","groupon\/faq\/recyclebin","groupon\/faq\/add","groupon\/faq\/edit","groupon\/faq\/del","groupon\/faq\/destroy","groupon\/faq\/restore","groupon\/faq\/multi","groupon\/user_wallet_apply","groupon\/user_wallet_apply\/index","groupon\/user_wallet_apply\/gettype","groupon\/user_wallet_apply\/handle","groupon\/user_wallet_apply\/log","groupon\/order","groupon\/order\/order","groupon\/order\/order\/index","groupon\/order\/order\/recyclebin","groupon\/order\/order\/add","groupon\/order\/order\/edit","groupon\/order\/order\/del","groupon\/order\/order\/destroy","groupon\/order\/order\/restore","groupon\/order\/order\/multi","groupon\/order\/order\/detail","groupon\/order\/order\/send","groupon\/order\/order\/aftersalefinish","groupon\/order\/order\/refund","groupon\/order\/order\/editmemo","groupon\/order\/order\/gettype","groupon\/order\/order\/refundrefuse","groupon\/order\/order\/export","groupon\/order\/order\/actions","groupon\/order\/order\/editconsignee","groupon\/order\/order\/sendstore","groupon\/order\/order_item","groupon\/order\/order_item\/index","groupon\/order\/order_item\/recyclebin","groupon\/order\/order_item\/add","groupon\/order\/order_item\/edit","groupon\/order\/order_item\/del","groupon\/order\/order_item\/destroy","groupon\/order\/order_item\/restore","groupon\/order\/order_item\/multi","groupon\/store\/dashboard","groupon\/store\/dashboard\/index","groupon\/order\/store_express","groupon\/order\/store_express\/getexpress","groupon\/order\/store_express\/index","groupon\/order\/store_express\/add","groupon\/order\/store_express\/send","groupon\/order\/store_express\/detail","groupon\/order\/store_express\/setexpress","groupon\/order\/store_express\/export","groupon\/feedback","groupon\/feedback\/index","groupon\/feedback\/recyclebin","groupon\/feedback\/add","groupon\/feedback\/edit","groupon\/feedback\/del","groupon\/feedback\/destroy","groupon\/feedback\/restore","groupon\/feedback\/multi","groupon\/feedback\/detail","groupon\/notification","groupon\/notification\/index","groupon\/notification\/recyclebin","groupon\/notification\/add","groupon\/notification\/edit","groupon\/notification\/del","groupon\/notification\/destroy","groupon\/notification\/restore","groupon\/notification\/config","groupon\/notification\/set_template","groupon\/notification\/set_status","groupon\/store","groupon\/store\/store","groupon\/store\/store\/add","groupon\/store\/store\/edit","groupon\/store\/store\/del","groupon\/store\/store\/recyclebin","groupon\/store\/store\/setstatus","groupon\/store\/store\/select","groupon\/store\/store\/index","groupon\/store\/store\/all","groupon\/store\/store\/restore","groupon\/store\/store\/destroy","groupon\/store\/apply","groupon\/store\/apply\/applyoper","groupon\/store\/apply\/index","groupon\/store\/apply\/detail","groupon\/store\/take_log","groupon\/store\/take_log\/index","groupon\/store\/take_log\/run_money","groupon\/store\/take_log\/back_money","groupon\/user\/user","groupon\/user\/user\/index","groupon\/user\/user\/select","groupon\/user\/user\/profile","groupon\/user\/user\/del","groupon\/user\/user\/order_log","groupon\/user\/user\/login_log","groupon\/user\/user\/money_log","groupon\/user\/user\/score_log","groupon\/user\/user\/share_log","groupon\/user\/user\/goods_favorite","groupon\/user\/user\/coupon_log","groupon\/user\/user\/goods_view","groupon\/user\/user\/recyclebin","groupon\/user\/user\/update","groupon\/user\/user\/money_recharge","groupon\/user\/user\/score_recharge","groupon\/activity","groupon\/activity\/activity","groupon\/activity\/activity\/index","groupon\/activity\/activity\/add","groupon\/activity\/activity\/edit","groupon\/activity\/activity\/del","groupon\/activity\/activity\/gettype","groupon\/activity\/activity\/recyclebin"]} |
addons/groupon/Groupon.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon; | ||
4 | + | ||
5 | +use think\Addons; | ||
6 | +use app\common\library\Menu; | ||
7 | +use app\admin\model\AuthRule; | ||
8 | +use addons\groupon\library\Hook; | ||
9 | +use think\Exception; | ||
10 | +use think\exception\PDOException; | ||
11 | +use think\Loader; | ||
12 | + | ||
13 | +/** | ||
14 | + * Groupon插件 | ||
15 | + */ | ||
16 | +class Groupon extends Addons | ||
17 | +{ | ||
18 | + | ||
19 | + /** | ||
20 | + * 插件安装方法 | ||
21 | + * @return bool | ||
22 | + */ | ||
23 | + public function install() | ||
24 | + { | ||
25 | + $menu = self::getMenu(); | ||
26 | + Menu::create($menu['new']); | ||
27 | + return true; | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * 插件卸载方法 | ||
32 | + * @return bool | ||
33 | + */ | ||
34 | + public function uninstall() | ||
35 | + { | ||
36 | + Menu::delete('groupon'); | ||
37 | + return true; | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * 插件启用方法 | ||
42 | + */ | ||
43 | + public function enable() | ||
44 | + { | ||
45 | + Menu::enable('groupon'); | ||
46 | + return true; | ||
47 | + } | ||
48 | + | ||
49 | + /** | ||
50 | + * 插件更新方法 | ||
51 | + */ | ||
52 | + public function upgrade() | ||
53 | + { | ||
54 | + $menu = self::getMenu(); | ||
55 | + if (method_exists(Menu::class, 'upgrade')) { | ||
56 | + Menu::upgrade('groupon', $menu['new']); | ||
57 | + } else { | ||
58 | + //使用Groupon自带的更新操作 | ||
59 | + self::menuCreateOrUpdate($menu['new'], $menu['old']); | ||
60 | + } | ||
61 | + | ||
62 | + return true; | ||
63 | + } | ||
64 | + | ||
65 | + /** | ||
66 | + * 插件禁用方法 | ||
67 | + */ | ||
68 | + public function disable() | ||
69 | + { | ||
70 | + Menu::disable('groupon'); | ||
71 | + return true; | ||
72 | + } | ||
73 | + | ||
74 | + | ||
75 | + /** | ||
76 | + * 应用初始化 | ||
77 | + */ | ||
78 | + public function appInit() | ||
79 | + { | ||
80 | + // 公共方法 | ||
81 | + require_once __DIR__ . '/helper.php'; | ||
82 | + // 补丁 | ||
83 | + if (!class_exists('\GuzzleHttp\UriTemplate')) { | ||
84 | + require_once __DIR__ . '/patch/storage.php'; | ||
85 | + Loader::addNamespace('GuzzleHttp', $this->addons_path . str_replace('/', DS, 'patch/storage')); | ||
86 | + } | ||
87 | + | ||
88 | + // 全局注册行为事件 | ||
89 | + Hook::register(); | ||
90 | + } | ||
91 | + | ||
92 | + private static function getMenu() | ||
93 | + { | ||
94 | + $newMenu = []; | ||
95 | + $config_file = ADDON_PATH . "groupon" . DS . 'config' . DS . "menu.php"; | ||
96 | + if (is_file($config_file)) { | ||
97 | + $newMenu = include $config_file; | ||
98 | + } | ||
99 | + $oldMenu = AuthRule::where('name', 'like', "groupon%")->select(); | ||
100 | + $oldMenu = array_column($oldMenu, null, 'name'); | ||
101 | + return ['new' => $newMenu, 'old' => $oldMenu]; | ||
102 | + } | ||
103 | + | ||
104 | + private static function menuCreateOrUpdate($newMenu, $oldMenu, $parent = 0) | ||
105 | + { | ||
106 | + if (!is_numeric($parent)) { | ||
107 | + $parentRule = AuthRule::getByName($parent); | ||
108 | + $pid = $parentRule ? $parentRule['id'] : 0; | ||
109 | + } else { | ||
110 | + $pid = $parent; | ||
111 | + } | ||
112 | + $allow = array_flip(['file', 'name', 'title', 'icon', 'condition', 'remark', 'ismenu', 'weigh']); | ||
113 | + foreach ($newMenu as $k => $v) { | ||
114 | + $hasChild = isset($v['sublist']) && $v['sublist'] ? true : false; | ||
115 | + $data = array_intersect_key($v, $allow); | ||
116 | + $data['ismenu'] = isset($data['ismenu']) ? $data['ismenu'] : ($hasChild ? 1 : 0); | ||
117 | + $data['icon'] = isset($data['icon']) ? $data['icon'] : ($hasChild ? 'fa fa-list' : 'fa fa-circle-o'); | ||
118 | + $data['pid'] = $pid; | ||
119 | + $data['status'] = 'normal'; | ||
120 | + try { | ||
121 | + if (!isset($oldMenu[$data['name']])) { | ||
122 | + $menu = AuthRule::create($data); | ||
123 | + } else { | ||
124 | + $menu = $oldMenu[$data['name']]; | ||
125 | + } | ||
126 | + if ($hasChild) { | ||
127 | + self::menuCreateOrUpdate($v['sublist'], $oldMenu, $menu['id']); | ||
128 | + } | ||
129 | + } catch (PDOException $e) { | ||
130 | + throw new Exception($e->getMessage()); | ||
131 | + } | ||
132 | + } | ||
133 | + } | ||
134 | +} |
addons/groupon/config/cache.php
0 → 100644
addons/groupon/config/menu.php
0 → 100644
此 diff 太大无法显示。
addons/groupon/controller/Address.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\model\UserAddress; | ||
7 | +use addons\groupon\model\Area; | ||
8 | + | ||
9 | +class Address extends Base | ||
10 | +{ | ||
11 | + | ||
12 | + protected $noNeedLogin = ['area']; | ||
13 | + protected $noNeedRight = ['*']; | ||
14 | + | ||
15 | + public function index() | ||
16 | + { | ||
17 | + $this->success('收货地址', UserAddress::getUserAddress()); | ||
18 | + } | ||
19 | + | ||
20 | + public function defaults() | ||
21 | + { | ||
22 | + $this->success('默认收货地址', UserAddress::getUserDefaultAddress()); | ||
23 | + } | ||
24 | + | ||
25 | + public function area() | ||
26 | + { | ||
27 | + $data['provinceData'] = Area::where('level', 1)->order('id asc')->field('id as value, name as label, pid, level')->select(); | ||
28 | + foreach ($data['provinceData'] as $k => $p) { | ||
29 | + $data['cityData'][$k] = Area::where(['level' => 2, 'pid' => $p->value])->order('id asc')->field('id as value, name as label, pid, level')->select(); | ||
30 | + foreach ($data['cityData'][$k] as $i => $c) { | ||
31 | + $data['areaData'][$k][$i] = Area::where(['level' => 3, 'pid' => $c->value])->order('id asc')->field('id as value, name as label, pid, level')->select(); | ||
32 | + } | ||
33 | + } | ||
34 | + | ||
35 | + $this->success('省市区', $data); | ||
36 | + | ||
37 | + } | ||
38 | + | ||
39 | + public function edit() | ||
40 | + { | ||
41 | + $params = $this->request->post(); | ||
42 | + | ||
43 | + // 表单验证 | ||
44 | + $this->grouponValidate($params, get_class(), 'edit'); | ||
45 | + | ||
46 | + $this->success('编辑地址', UserAddress::edit($params)); | ||
47 | + } | ||
48 | + | ||
49 | + public function info() | ||
50 | + { | ||
51 | + $params = $this->request->get(); | ||
52 | + $this->success('地址详情', UserAddress::info($params)); | ||
53 | + } | ||
54 | + | ||
55 | + public function del() | ||
56 | + { | ||
57 | + $params = $this->request->post(); | ||
58 | + $this->success('地址详情', UserAddress::del($params)); | ||
59 | + | ||
60 | + } | ||
61 | + | ||
62 | + | ||
63 | +} |
addons/groupon/controller/Base.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use app\common\controller\Api; | ||
7 | +use think\Lang; | ||
8 | + | ||
9 | +class Base extends Api | ||
10 | +{ | ||
11 | + public function _initialize() | ||
12 | + { | ||
13 | + | ||
14 | + parent::_initialize(); | ||
15 | + $controllername = strtolower($this->request->controller()); | ||
16 | + $this->loadlang($controllername); | ||
17 | + | ||
18 | + } | ||
19 | + | ||
20 | + protected function loadlang($name) | ||
21 | + { | ||
22 | + Lang::load(ADDON_PATH . 'groupon/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php'); | ||
23 | + } | ||
24 | + | ||
25 | + | ||
26 | + protected function grouponValidate($params, $class, $scene, $rules = []) { | ||
27 | + $validate = validate(str_replace('controller', 'validate', $class)); | ||
28 | + if (!$validate->check($params, $rules, $scene)) { | ||
29 | + $this->error($validate->getError()); | ||
30 | + } | ||
31 | + } | ||
32 | +} |
addons/groupon/controller/Cart.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\model\Cart as CartModel; | ||
6 | + | ||
7 | +class Cart extends Base | ||
8 | +{ | ||
9 | + | ||
10 | + protected $noNeedLogin = []; | ||
11 | + protected $noNeedRight = ['*']; | ||
12 | + | ||
13 | + public function index() | ||
14 | + { | ||
15 | + $data = CartModel::info(); | ||
16 | + $this->success('我的购物车', $data); | ||
17 | + } | ||
18 | + | ||
19 | + public function add() | ||
20 | + { | ||
21 | + $params = $this->request->post(); | ||
22 | + | ||
23 | + // 表单验证 | ||
24 | + $this->grouponValidate($params, get_class(), 'add'); | ||
25 | + | ||
26 | + $goodsList = $params['goods_list']; | ||
27 | + $this->success('已添加', CartModel::add($goodsList)); | ||
28 | + } | ||
29 | + | ||
30 | + public function edit() | ||
31 | + { | ||
32 | + $params = $this->request->post(); | ||
33 | + | ||
34 | + // 表单验证 | ||
35 | + $this->grouponValidate($params, get_class(), 'edit'); | ||
36 | + | ||
37 | + $this->success('', CartModel::edit($params)); | ||
38 | + } | ||
39 | + | ||
40 | +} |
addons/groupon/controller/Category.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\model\Category as CategoryModel; | ||
6 | +use addons\groupon\model\Goods; | ||
7 | + | ||
8 | +/** | ||
9 | + * 分类管理 | ||
10 | + * | ||
11 | + * @icon fa fa-list | ||
12 | + * @remark 用于统一管理网站的所有分类,分类可进行无限级分类,分类类型请在常规管理->系统配置->字典配置中添加 | ||
13 | + */ | ||
14 | + | ||
15 | +class Category extends Base | ||
16 | +{ | ||
17 | + protected $noNeedLogin = ['*']; | ||
18 | + protected $noNeedRight = ['*']; | ||
19 | + | ||
20 | + | ||
21 | + | ||
22 | + public function detail () { | ||
23 | + $id = $this->request->get('id'); | ||
24 | + | ||
25 | + $data = CategoryModel::getCategoryDetail($id); | ||
26 | + $this->success('商城分类', $data); | ||
27 | + } | ||
28 | + | ||
29 | + public function index() | ||
30 | + { | ||
31 | + $id = $this->request->get('id'); | ||
32 | + $data = CategoryModel::getCategoryList($id); | ||
33 | + $this->success('商城分类', $data); | ||
34 | + | ||
35 | + } | ||
36 | + | ||
37 | + | ||
38 | + // 获取指定 ids 分类列表 | ||
39 | + public function list() | ||
40 | + { | ||
41 | + $ids = $this->request->get('ids'); | ||
42 | + $data = CategoryModel::getCategoryListByIds($ids); | ||
43 | + $this->success('商城分类', $data); | ||
44 | + } | ||
45 | + | ||
46 | + | ||
47 | + public function goods() { | ||
48 | + $params = $this->request->get(); | ||
49 | + $category_id = $params['category_id']; | ||
50 | + | ||
51 | + $categories = CategoryModel::where('pid', $category_id)->where('status', 'normal')->select(); | ||
52 | + | ||
53 | + // 获取这个分类下面的所有商品 | ||
54 | + $goodsList = Goods::getGoodsList($params, false); | ||
55 | + | ||
56 | + foreach($categories as $key => $category) { | ||
57 | + $categoryIds = ',' . $category['id'] . ','; | ||
58 | + | ||
59 | + $currentCategoryGoods = []; | ||
60 | + foreach ($goodsList as $k => $goods) { | ||
61 | + $goodsCategoryIds = ',' . $goods['category_ids'] . ','; | ||
62 | + | ||
63 | + if (strpos($goodsCategoryIds, $categoryIds) !== false) { | ||
64 | + $currentCategoryGoods[] = $goods; | ||
65 | + } | ||
66 | + } | ||
67 | + | ||
68 | + $categories[$key]['goods'] = $currentCategoryGoods; | ||
69 | + } | ||
70 | + | ||
71 | + $this->success('商城分类商品', $categories); | ||
72 | + } | ||
73 | +} |
addons/groupon/controller/Coupons.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class Coupons extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = ['lists', 'detail', 'goods']; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + // 领券中心,自己的优惠券 | ||
13 | + public function index() | ||
14 | + { | ||
15 | + $type = $this->request->get('type'); | ||
16 | + $this->success('优惠券中心', \addons\groupon\model\Coupons::getCouponsList($type)); | ||
17 | + } | ||
18 | + | ||
19 | + public function lists() | ||
20 | + { | ||
21 | + $ids = $this->request->get('ids'); | ||
22 | + $this->success('优惠券列表', \addons\groupon\model\Coupons::getCouponsListByIds($ids)); | ||
23 | + | ||
24 | + } | ||
25 | + | ||
26 | + public function get() | ||
27 | + { | ||
28 | + $id = $this->request->get('id'); | ||
29 | + $this->success('领取成功', \addons\groupon\model\Coupons::getCoupon($id)); | ||
30 | + } | ||
31 | + | ||
32 | + public function detail() | ||
33 | + { | ||
34 | + $id = $this->request->get('id'); | ||
35 | + $user_coupons_id = $this->request->get('user_coupons_id', 0); | ||
36 | + $detail = \addons\groupon\model\Coupons::getCouponsDetail($id, $user_coupons_id); | ||
37 | + | ||
38 | + $this->success('优惠券详情', $detail); | ||
39 | + } | ||
40 | + | ||
41 | + public function goods() | ||
42 | + { | ||
43 | + $id = $this->request->get('id'); | ||
44 | + $detail = \addons\groupon\model\Coupons::getGoodsByCoupons($id); | ||
45 | + | ||
46 | + $this->success('优惠券详情', $detail); | ||
47 | + } | ||
48 | + | ||
49 | + | ||
50 | + | ||
51 | + | ||
52 | +} |
addons/groupon/controller/Express.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\model\Order; | ||
7 | +use addons\groupon\model\User; | ||
8 | +use think\Db; | ||
9 | +use think\Log; | ||
10 | + | ||
11 | +class Express extends Base | ||
12 | +{ | ||
13 | + | ||
14 | + protected $noNeedLogin = ['callback']; | ||
15 | + protected $noNeedRight = ['*']; | ||
16 | + | ||
17 | + | ||
18 | + /** | ||
19 | + * 物流信息订阅回调接口 | ||
20 | + */ | ||
21 | + public function callback() | ||
22 | + { | ||
23 | + $requestData = $this->request->post(); | ||
24 | + | ||
25 | + $expressLib = new \addons\groupon\library\Express(); | ||
26 | + | ||
27 | + // 信息记录日志 | ||
28 | + // \think\Log::write('expresscallback:'. json_encode($requestData)); | ||
29 | + | ||
30 | + $data = json_decode(html_entity_decode($requestData['RequestData']), true); | ||
31 | + $expressData = $data['Data']; | ||
32 | + | ||
33 | + foreach ($expressData as $key => $express) { | ||
34 | + $order_code = $express['OrderCode'] ?? ''; | ||
35 | + | ||
36 | + $orderExpress = null; | ||
37 | + if (substr($order_code, 0, 1) == 'S') { | ||
38 | + // 门店包裹 | ||
39 | + $orderExpress = \addons\groupon\model\OrderStoreExpress::where('code', $order_code)->find(); | ||
40 | + } | ||
41 | + | ||
42 | + if (!$orderExpress) { | ||
43 | + // 包裹不存在,记录日志信息,然后继续下一个 | ||
44 | + \think\Log::write('orderExpressNotFound:' . json_encode($express)); | ||
45 | + continue; | ||
46 | + } | ||
47 | + | ||
48 | + if (!$express['Success']) { | ||
49 | + // 失败了 | ||
50 | + if (isset($express['Reason']) && ($express['Reason'] == '三天无轨迹' || $express['Reason'] == '七天无轨迹')) { | ||
51 | + // 需要重新订阅 | ||
52 | + $expressLib->subscribe([ | ||
53 | + 'express_code' => $express['ShipperCode'], | ||
54 | + 'express_no' => $express['LogisticCode'], | ||
55 | + 'order_code' => $orderExpress->code ? $orderExpress->code : '' | ||
56 | + ], $orderExpress, $orderExpress->order ?? null); | ||
57 | + } | ||
58 | + | ||
59 | + \think\Log::write('orderExpressReason:' . json_encode($express)); | ||
60 | + continue; | ||
61 | + } | ||
62 | + | ||
63 | + $expressLib->checkAndAddTraces($orderExpress, $express); | ||
64 | + } | ||
65 | + | ||
66 | + $result = $expressLib->setPushResult(true); | ||
67 | + | ||
68 | + return json($result); | ||
69 | + } | ||
70 | +} |
addons/groupon/controller/Faq.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class Faq extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = ['*']; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + | ||
13 | + // faq 列表 | ||
14 | + public function index() | ||
15 | + { | ||
16 | + $this->success('获取成功', \addons\groupon\model\Faq::order('id', 'DESC')->paginate(10)); | ||
17 | + } | ||
18 | + | ||
19 | + | ||
20 | + public function detail () { | ||
21 | + $id = $this->request->get('id'); | ||
22 | + | ||
23 | + $this->success('签到成功', \addons\groupon\model\Faq::where('id', $id)->find()); | ||
24 | + } | ||
25 | + | ||
26 | +} |
addons/groupon/controller/Feedback.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class Feedback extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = ['type']; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + | ||
13 | + public function type() | ||
14 | + { | ||
15 | + $this->success('反馈类型', array_values(\addons\groupon\model\Feedback::$typeAll)); | ||
16 | + } | ||
17 | + | ||
18 | + | ||
19 | + public function add() { | ||
20 | + $params = $this->request->post(); | ||
21 | + | ||
22 | + // 表单验证 | ||
23 | + $this->grouponValidate($params, get_class(), 'add'); | ||
24 | + | ||
25 | + $this->success('反馈成功', \addons\groupon\model\Feedback::add($params)); | ||
26 | + } | ||
27 | + | ||
28 | +} |
addons/groupon/controller/Goods.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
7 | +use PhpOffice\PhpSpreadsheet\Writer\Xlsx; | ||
8 | +use PhpOffice\PhpSpreadsheet\Style\Alignment; | ||
9 | +use PhpOffice\PhpSpreadsheet\Style\Fill; | ||
10 | +use PhpOffice\PhpSpreadsheet\Style\Border; | ||
11 | + | ||
12 | + | ||
13 | +class Goods extends Base | ||
14 | +{ | ||
15 | + | ||
16 | + protected $noNeedLogin = ['index', 'detail', 'lists', 'activity', 'seckillList', 'grouponList', 'store']; | ||
17 | + protected $noNeedRight = ['*']; | ||
18 | + | ||
19 | + public function index() | ||
20 | + { | ||
21 | + | ||
22 | + } | ||
23 | + | ||
24 | + public function detail() | ||
25 | + { | ||
26 | + $id = $this->request->get('id'); | ||
27 | + $detail = \addons\groupon\model\Goods::getGoodsDetail($id); | ||
28 | + | ||
29 | + // 记录足记 | ||
30 | + \addons\groupon\model\UserView::addView($detail); | ||
31 | + | ||
32 | + $sku_price = $detail['sku_price']; // 处理过的规格 | ||
33 | + // tp bug json_encode 或者 toArray 的时候 sku_price 会重新查询数据库,导致被处理过的规格又还原回去了 | ||
34 | + $detail = json_decode(json_encode($detail), true); | ||
35 | + $detail['sku_price'] = $sku_price; | ||
36 | + | ||
37 | + $this->success('商品详情', $detail); | ||
38 | + } | ||
39 | + | ||
40 | + public function lists() | ||
41 | + { | ||
42 | + $params = $this->request->get(); | ||
43 | + $data = \addons\groupon\model\Goods::getGoodsList($params); | ||
44 | + | ||
45 | + $this->success('商品列表', $data); | ||
46 | + | ||
47 | + } | ||
48 | + | ||
49 | + | ||
50 | + | ||
51 | + public function favorite() | ||
52 | + { | ||
53 | + $params = $this->request->post(); | ||
54 | + $result = \addons\groupon\model\UserFavorite::edit($params); | ||
55 | + $this->success($result ? '收藏成功' : '取消收藏', $result); | ||
56 | + } | ||
57 | + | ||
58 | + public function favoriteList() | ||
59 | + { | ||
60 | + $data = \addons\groupon\model\UserFavorite::getGoodsList(); | ||
61 | + $this->success('商品收藏列表', $data); | ||
62 | + } | ||
63 | + | ||
64 | + | ||
65 | + public function viewDelete() | ||
66 | + { | ||
67 | + $params = $this->request->post(); | ||
68 | + $result = \addons\groupon\model\UserView::del($params); | ||
69 | + $this->success('删除成功', $result); | ||
70 | + } | ||
71 | + | ||
72 | + | ||
73 | + public function viewList() | ||
74 | + { | ||
75 | + $data = \addons\groupon\model\UserView::getGoodsList(); | ||
76 | + $this->success('商品浏览列表', $data); | ||
77 | + } | ||
78 | + | ||
79 | + | ||
80 | + | ||
81 | +} |
addons/groupon/controller/GoodsComment.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class GoodsComment extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = ['index', 'type']; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + | ||
13 | + public function index() | ||
14 | + { | ||
15 | + $params = $this->request->get(); | ||
16 | + | ||
17 | + $goodsComments = \addons\groupon\model\GoodsComment::getList($params); | ||
18 | + | ||
19 | + $this->success('评价详情', $goodsComments); | ||
20 | + } | ||
21 | + | ||
22 | + | ||
23 | + public function type() { | ||
24 | + $goods_id = $this->request->get('goods_id', 0); | ||
25 | + | ||
26 | + $type = array_values(\addons\groupon\model\GoodsComment::$typeAll); | ||
27 | + | ||
28 | + foreach ($type as $key => $val) { | ||
29 | + // 只查询 count 比查出来所有评论,在判断状态要快 | ||
30 | + $comment = \addons\groupon\model\GoodsComment::where('goods_id', $goods_id); | ||
31 | + if ($val['code'] != 'all') { | ||
32 | + $comment = $comment->{$val['code']}(); | ||
33 | + } | ||
34 | + $comment = $comment->count(); | ||
35 | + $type[$key]['num'] = $comment; | ||
36 | + } | ||
37 | + | ||
38 | + $this->success('筛选类型', $type); | ||
39 | + } | ||
40 | +} |
addons/groupon/controller/Index.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\model\Config; | ||
6 | +use think\Db; | ||
7 | +use think\Config as FaConfig; | ||
8 | +use fast\Random; | ||
9 | +use think\exception\HttpResponseException; | ||
10 | + | ||
11 | +class Index extends Base | ||
12 | +{ | ||
13 | + | ||
14 | + protected $noNeedLogin = ['*']; | ||
15 | + protected $noNeedRight = ['*']; | ||
16 | + | ||
17 | + public function index() | ||
18 | + { | ||
19 | + } | ||
20 | + | ||
21 | + //初始化商城数据 服务器压力大可以把最后的data数据存入cache缓存中来调用,防止多次查sql | ||
22 | + public function init() | ||
23 | + { | ||
24 | + $params = $this->request->get(); | ||
25 | + $platform = $this->request->header('platform'); | ||
26 | + | ||
27 | + $config = new \addons\groupon\model\Config; | ||
28 | + | ||
29 | + $platformConfig = json_decode($config->where(['name' => $platform])->value('value'), true); | ||
30 | + $paymentConfig = $config->where('group', 'payment')->select(); | ||
31 | + $payment = []; | ||
32 | + foreach ($paymentConfig as $key => $config) { | ||
33 | + $val = json_decode($config->value, true); | ||
34 | + if ($val && in_array($platform, $val['platform'])) { | ||
35 | + $payment[] = $config->name; | ||
36 | + } | ||
37 | + } | ||
38 | + | ||
39 | + // 处理微信支付 v3 | ||
40 | + $pay_version = pay_version(); | ||
41 | + if ($pay_version == 'v3' && in_array('wechatv3', $payment) && !in_array('wechat', $payment)) { | ||
42 | + $payment[] = 'wechat'; | ||
43 | + }; | ||
44 | + $data['payment'] = $payment; // 平台支持的支付方式 | ||
45 | + | ||
46 | + $groupon = json_decode(Config::where(['name' => 'groupon'])->value('value'), true); | ||
47 | + $data['info'] = $groupon; | ||
48 | + $data['info']['logo'] = cdnurl($data['info']['logo'], true); | ||
49 | + $autologin = false; | ||
50 | + if (isset($platformConfig['auto_login']) && $platformConfig['auto_login'] == 1) { | ||
51 | + $autologin = true; | ||
52 | + } | ||
53 | + $data['wechat'] = [ | ||
54 | + 'appid' => isset($platformConfig['app_id']) ? $platformConfig['app_id'] : '', | ||
55 | + 'autologin' => $autologin, | ||
56 | + ]; | ||
57 | + $share = json_decode(Config::where(['name' => 'share'])->value('value'), true); | ||
58 | + | ||
59 | + $data['share'] = [ | ||
60 | + 'title' => $share['title'], | ||
61 | + 'image' => isset($share['image']) ? cdnurl($share['image'], true) : '', | ||
62 | + 'goods_poster_bg' => isset($share['goods_poster_bg']) ? cdnurl($share['goods_poster_bg'], true) : '', | ||
63 | + 'user_poster_bg' => isset($share['user_poster_bg']) ? cdnurl($share['user_poster_bg'], true) : '', | ||
64 | + 'groupon_poster_bg' => isset($share['groupon_poster_bg']) ? cdnurl($share['groupon_poster_bg'], true) : '', | ||
65 | + 'store_poster_bg' => isset($share['store_poster_bg']) ? cdnurl($share['store_poster_bg'], true) : '', | ||
66 | + ]; | ||
67 | + $data['addons'] = array_keys(get_addon_list()); | ||
68 | + $data['chat'] = json_decode(Config::where(['name' => 'chat'])->value('value'), true); | ||
69 | + $this->success('初始化数据', $data); | ||
70 | + | ||
71 | + } | ||
72 | + | ||
73 | + //商城模板数据 | ||
74 | + public function template() | ||
75 | + { | ||
76 | + $get = $this->request->get(); | ||
77 | + $platform = $this->request->header('platform'); | ||
78 | + if (isset($get['shop_id'])) { | ||
79 | + $template = \addons\groupon\model\Decorate::getCurrentPlatformDecorate('preview', $get['shop_id']); | ||
80 | + } else { | ||
81 | + $template = \addons\groupon\model\Decorate::getCurrentPlatformDecorate($platform); | ||
82 | + } | ||
83 | + $this->success('模板数据', $template); | ||
84 | + } | ||
85 | + | ||
86 | + //自定义页面 | ||
87 | + public function custom() | ||
88 | + { | ||
89 | + $get = $this->request->get(); | ||
90 | + $decorate = \addons\groupon\model\Decorate::get($get['id']); | ||
91 | + if (!$decorate) { | ||
92 | + $this->error('未找到自定义页面'); | ||
93 | + } | ||
94 | + $decorate->template = \addons\groupon\model\Decorate::getCustomDecorate($get['id']); | ||
95 | + $this->success('自定义模板数据', $decorate); | ||
96 | + } | ||
97 | + | ||
98 | + //富文本详情 | ||
99 | + public function richtext() | ||
100 | + { | ||
101 | + $id = $this->request->get('id'); | ||
102 | + $data = \addons\groupon\model\Richtext::get(['id' => $id]); | ||
103 | + $this->success($data->title, $data); | ||
104 | + } | ||
105 | + | ||
106 | + //同步前端所有页面链接 | ||
107 | + public function asyncLink() | ||
108 | + { | ||
109 | + $post = $this->request->post(); | ||
110 | + $newLink = $post['data']; | ||
111 | + $existLink = Db::name('groupon_link')->select(); | ||
112 | + $newLinkPath = array_column($newLink, 'path'); | ||
113 | + $existLinkPath = array_flip(array_column($existLink, 'path')); | ||
114 | + $insertData = []; | ||
115 | + $count = 1; | ||
116 | + foreach ($newLinkPath as $key => $item) { | ||
117 | + if (!isset($existLinkPath[$item]) && isset($newLink[$key]['meta']['async']) && $newLink[$key]['meta']['async']) { | ||
118 | + $insertData[] = [ | ||
119 | + 'name' => isset($newLink[$key]['meta']['title']) ? $newLink[$key]['meta']['title'] : '新链接' . $count, | ||
120 | + 'path' => $item, | ||
121 | + 'group' => isset($newLink[$key]['meta']['group']) ? $newLink[$key]['meta']['group'] : '其它', | ||
122 | + 'createtime' => time(), | ||
123 | + 'updatetime' => time() | ||
124 | + ]; | ||
125 | + $count++; | ||
126 | + } | ||
127 | + } | ||
128 | + if ($insertData !== []) { | ||
129 | + Db::name('groupon_link')->insertAll($insertData); | ||
130 | + } | ||
131 | + } | ||
132 | + | ||
133 | + | ||
134 | + //店铺装修 截图商城首页 | ||
135 | + public function asyncDecorateScreenShot() | ||
136 | + { | ||
137 | + $params = $this->request->post(); | ||
138 | + \addons\groupon\model\Decorate::asyncDecorateScreenShot($params); | ||
139 | + } | ||
140 | + | ||
141 | + /** | ||
142 | + * 上传文件 | ||
143 | + * @ApiMethod (POST) | ||
144 | + * @param File $file 文件流 | ||
145 | + */ | ||
146 | + public function upload() | ||
147 | + { | ||
148 | + $file = $this->request->file('file'); | ||
149 | + if (empty($file)) { | ||
150 | + $this->error(__('No file upload or server upload limit exceeded')); | ||
151 | + } | ||
152 | + | ||
153 | + //判断是否已经存在附件 | ||
154 | + $sha1 = $file->hash(); | ||
155 | + | ||
156 | + $upload = FaConfig::get('upload'); | ||
157 | + | ||
158 | + preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches); | ||
159 | + $type = strtolower($matches[2]); | ||
160 | + $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; | ||
161 | + $size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0); | ||
162 | + $fileInfo = $file->getInfo(); | ||
163 | + $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)); | ||
164 | + $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file'; | ||
165 | + | ||
166 | + $mimetypeArr = explode(',', strtolower($upload['mimetype'])); | ||
167 | + $typeArr = explode('/', $fileInfo['type']); | ||
168 | + | ||
169 | + //禁止上传PHP和HTML文件 | ||
170 | + if (in_array($fileInfo['type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) { | ||
171 | + $this->error(__('Uploaded file format is limited')); | ||
172 | + } | ||
173 | + //验证文件后缀 | ||
174 | + if ($upload['mimetype'] !== '*' && | ||
175 | + ( | ||
176 | + !in_array($suffix, $mimetypeArr) | ||
177 | + || (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))) | ||
178 | + ) | ||
179 | + ) { | ||
180 | + $this->error(__('Uploaded file format is limited')); | ||
181 | + } | ||
182 | + //验证是否为图片文件 | ||
183 | + $imagewidth = $imageheight = 0; | ||
184 | + if (in_array($fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) { | ||
185 | + $imgInfo = getimagesize($fileInfo['tmp_name']); | ||
186 | + if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { | ||
187 | + $this->error(__('Uploaded file is not a valid image')); | ||
188 | + } | ||
189 | + $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth; | ||
190 | + $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight; | ||
191 | + } | ||
192 | + | ||
193 | + // 文件 md5 | ||
194 | + $fileMd5 = md5_file($fileInfo['tmp_name']); | ||
195 | + | ||
196 | + $replaceArr = [ | ||
197 | + '{year}' => date("Y"), | ||
198 | + '{mon}' => date("m"), | ||
199 | + '{day}' => date("d"), | ||
200 | + '{hour}' => date("H"), | ||
201 | + '{min}' => date("i"), | ||
202 | + '{sec}' => date("s"), | ||
203 | + '{random}' => Random::alnum(16), | ||
204 | + '{random32}' => Random::alnum(32), | ||
205 | + '{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'], | ||
206 | + '{suffix}' => $suffix, | ||
207 | + '{.suffix}' => $suffix ? '.' . $suffix : '', | ||
208 | + '{filemd5}' => $fileMd5, | ||
209 | + ]; | ||
210 | + $savekey = $upload['savekey']; | ||
211 | + $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey); | ||
212 | + | ||
213 | + $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1); | ||
214 | + $fileName = substr($savekey, strripos($savekey, '/') + 1); | ||
215 | + // | ||
216 | + | ||
217 | + if (in_array($upload['storage'], ['cos', 'alioss', 'qiniu'])) { // upyun:又拍云 ,bos:百度BOS,ucloud: Ucloud, 如果要使用这三种,请自行安装插件配置,并将标示填入前面数组,进行测试 | ||
218 | + $token_name = $upload['storage'] . 'token'; // costoken, aliosstoken, qiniutoken | ||
219 | + $controller_name = '\\addons\\' . $upload['storage'] . '\\controller\\Index'; | ||
220 | + | ||
221 | + $storageToken[$token_name] = $upload['multipart'] && $upload['multipart'][$token_name] ? $upload['multipart'][$token_name] : ''; | ||
222 | + $domain = request()->domain(); | ||
223 | + | ||
224 | + try { | ||
225 | + $uploadCreate = \think\Request::create('foo', 'POST', array_merge([ | ||
226 | + 'key' => $savekey, | ||
227 | + 'name' => $fileInfo['name'], | ||
228 | + 'md5' => $fileMd5, | ||
229 | + 'chunk' => 0, | ||
230 | + ], $storageToken)); | ||
231 | + | ||
232 | + // 重新设置跨域允许域名 | ||
233 | + $cors = config('fastadmin.cors_request_domain'); | ||
234 | + config('fastadmin.cors_request_domain', $cors . ',' . $domain); | ||
235 | + | ||
236 | + $uploadController = new $controller_name($uploadCreate); | ||
237 | + $uploadController->upload(); | ||
238 | + } catch (HttpResponseException $e) { | ||
239 | + $result = $e->getResponse()->getData(); | ||
240 | + if (isset($result['code']) && $result['code'] == 0) { | ||
241 | + $this->error($result['msg']); | ||
242 | + } | ||
243 | + | ||
244 | + $resultData = $result['data']; | ||
245 | + } | ||
246 | + } else { | ||
247 | + $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName); | ||
248 | + | ||
249 | + if ($splInfo) { | ||
250 | + $resultData = [ | ||
251 | + 'url' => $uploadDir . $splInfo->getSaveName(), | ||
252 | + 'fullurl' => request()->domain() . $uploadDir . $splInfo->getSaveName() | ||
253 | + ]; | ||
254 | + } else { | ||
255 | + // 上传失败获取错误信息 | ||
256 | + $this->error($file->getError()); | ||
257 | + } | ||
258 | + } | ||
259 | + | ||
260 | + $params = array( | ||
261 | + 'admin_id' => 0, | ||
262 | + 'user_id' => (int)$this->auth->id, | ||
263 | + 'filename' => substr(htmlspecialchars(strip_tags($fileInfo['name'])), 0, 100), | ||
264 | + 'filesize' => $fileInfo['size'], | ||
265 | + 'imagewidth' => $imagewidth, | ||
266 | + 'imageheight' => $imageheight, | ||
267 | + 'imagetype' => $suffix, | ||
268 | + 'imageframes' => 0, | ||
269 | + 'mimetype' => $fileInfo['type'] == 'application/octet-stream' && in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp']) ? 'image/' . $suffix : $fileInfo['type'], | ||
270 | + 'url' => $resultData['url'], | ||
271 | + 'uploadtime' => time(), | ||
272 | + 'storage' => $upload['storage'], | ||
273 | + 'sha1' => $sha1, | ||
274 | + ); | ||
275 | + $attachment = new \app\common\model\Attachment; | ||
276 | + $attachment->data(array_filter($params)); | ||
277 | + $attachment->save(); | ||
278 | + \think\Hook::listen("upload_after", $attachment); | ||
279 | + $this->success(__('Upload successful'), $resultData); | ||
280 | + } | ||
281 | + | ||
282 | + | ||
283 | + | ||
284 | + /** | ||
285 | + * 上传 base64 图片 | ||
286 | + * @ApiMethod (POST) | ||
287 | + * @param base64 内容 | ||
288 | + */ | ||
289 | + public function uploadBase64() | ||
290 | + { | ||
291 | + $content = $this->request->post('content', ''); | ||
292 | + | ||
293 | + if (empty($content) || !preg_match('/^(data:\s*image\/(\w+);base64,)/', $content, $matches)) { | ||
294 | + $this->error(__('No file upload or server upload limit exceeded')); | ||
295 | + } | ||
296 | + | ||
297 | + $upload = FaConfig::get('upload'); | ||
298 | + | ||
299 | + $suffix = $matches[2]; //图片后缀 | ||
300 | + | ||
301 | + $mimetypeArr = explode(',', strtolower($upload['mimetype'])); | ||
302 | + | ||
303 | + // 判断是否允许的后缀 | ||
304 | + if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr)) { | ||
305 | + $this->error(__('Uploaded file format is limited')); | ||
306 | + } | ||
307 | + | ||
308 | + $replaceArr = [ | ||
309 | + '{year}' => date("Y"), | ||
310 | + '{mon}' => date("m"), | ||
311 | + '{day}' => date("d"), | ||
312 | + '{hour}' => date("H"), | ||
313 | + '{min}' => date("i"), | ||
314 | + '{sec}' => date("s"), | ||
315 | + '{random}' => Random::alnum(16), | ||
316 | + '{random32}' => Random::alnum(32), | ||
317 | + '{filename}' => "店铺装修截图", | ||
318 | + '{suffix}' => $suffix, | ||
319 | + '{.suffix}' => $suffix ? '.' . $suffix : '', | ||
320 | + '{filemd5}' => md5($content), | ||
321 | + ]; | ||
322 | + $savekey = $upload['savekey']; | ||
323 | + $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey); | ||
324 | + | ||
325 | + $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1); | ||
326 | + $fileName = substr($savekey, strripos($savekey, '/') + 1); | ||
327 | + $fullDir = ROOT_PATH . '/public' . $uploadDir; | ||
328 | + | ||
329 | + $uploadPath = $uploadDir . $fileName; | ||
330 | + $fullPath = $fullDir . $fileName; | ||
331 | + | ||
332 | + if (!is_dir($fullDir)) { | ||
333 | + mkdir($fullDir, 0777, true); | ||
334 | + } | ||
335 | + | ||
336 | + $imageContent = base64_decode(str_replace($matches[1], '', $content)); | ||
337 | + if (file_put_contents($fullPath, $imageContent)) { | ||
338 | + $imgInfo = getimagesize($fullPath); | ||
339 | + | ||
340 | + $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : 0; | ||
341 | + $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : 0; | ||
342 | + | ||
343 | + $params = array( | ||
344 | + 'admin_id' => 0, | ||
345 | + 'user_id' => (int) $this->auth->id, | ||
346 | + 'filesize' => strlen($content), | ||
347 | + 'imagewidth' => $imagewidth, | ||
348 | + 'imageheight' => $imageheight, | ||
349 | + 'imagetype' => $suffix, | ||
350 | + 'imageframes' => 0, | ||
351 | + 'mimetype' => isset($imgInfo['mime']) ? $imgInfo['mime'] : 'image/' . $suffix, | ||
352 | + 'url' => $uploadPath, | ||
353 | + 'uploadtime' => time(), | ||
354 | + 'storage' => 'local', | ||
355 | + 'sha1' => hash_file('sha1', $fullPath), | ||
356 | + ); | ||
357 | + $attachment = new \app\common\model\Attachment; | ||
358 | + $attachment->data(array_filter($params)); | ||
359 | + $attachment->save(); | ||
360 | + | ||
361 | + \think\Hook::listen("upload_after", $attachment); | ||
362 | + $this->success(__('Upload successful'), [ | ||
363 | + 'url' => $uploadPath, | ||
364 | + 'full_url' => request()->domain() . $uploadPath | ||
365 | + ]); | ||
366 | + } else { | ||
367 | + $this->error("文件上传失败"); | ||
368 | + } | ||
369 | + } | ||
370 | + | ||
371 | + public function debugLog() | ||
372 | + { | ||
373 | + $params = $this->request->post(); | ||
374 | + \think\Log::write($params, 'notice'); | ||
375 | + } | ||
376 | + | ||
377 | +} |
addons/groupon/controller/Live.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\library\Wechat; | ||
6 | +use addons\groupon\exception\Exception; | ||
7 | +use think\Cache; | ||
8 | + | ||
9 | +class Live extends Base | ||
10 | +{ | ||
11 | + | ||
12 | + protected $noNeedLogin = ['*']; | ||
13 | + protected $noNeedRight = ['*']; | ||
14 | + | ||
15 | + | ||
16 | + public function index() | ||
17 | + { | ||
18 | + $params = $this->request->get(); | ||
19 | + | ||
20 | + $type = $params['type'] ?? 'all'; | ||
21 | + $ids = array_filter(isset($params['ids']) ? explode(',', $params['ids']) : []); | ||
22 | + | ||
23 | + if (!in_array($type, ['all', 'notice', 'living', 'lived'])) { | ||
24 | + $this->error('参数错误'); | ||
25 | + } | ||
26 | + | ||
27 | + // 同步直播 | ||
28 | + \addons\groupon\model\Live::autoSyncLive(); | ||
29 | + | ||
30 | + if ($type != 'all') { | ||
31 | + $lives = \addons\groupon\model\Live::{$type}() | ||
32 | + ->with('goods') | ||
33 | + ->order('id', 'desc') | ||
34 | + ->paginate(10); | ||
35 | + } else { | ||
36 | + $lives = \addons\groupon\model\Live::order('live_status', 'asc') | ||
37 | + ->with('goods') | ||
38 | + ->order('id', 'desc'); | ||
39 | + | ||
40 | + if (isset($params['ids'])) { | ||
41 | + // 首页根据 id 获取 | ||
42 | + $lives = $lives->where('id', 'in', $ids)->select(); | ||
43 | + } else { | ||
44 | + // 直播列表 | ||
45 | + $lives = $lives->paginate(10); | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | + $this->success('获取成功', $lives); | ||
50 | + } | ||
51 | + | ||
52 | + | ||
53 | +} |
addons/groupon/controller/Notification.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\model\NotificationConfig; | ||
7 | +use think\Cache; | ||
8 | + | ||
9 | + | ||
10 | +class Notification extends Base | ||
11 | +{ | ||
12 | + | ||
13 | + protected $noNeedLogin = ['*']; | ||
14 | + protected $noNeedRight = ['*']; | ||
15 | + | ||
16 | + | ||
17 | + public function template() | ||
18 | + { | ||
19 | + // 获取小程序模板消息所有配置 | ||
20 | + $notificationConfig = NotificationConfig::cache(300)->where('platform', 'wxMiniProgram')->select(); | ||
21 | + | ||
22 | + $templates = []; | ||
23 | + foreach ($notificationConfig as $k => $config) { | ||
24 | + if ($config['status'] && $config['content_arr'] && $config['content_arr']['template_id']) { | ||
25 | + $templates[$config['event']] = $config['content_arr']['template_id']; | ||
26 | + } | ||
27 | + } | ||
28 | + | ||
29 | + $this->success('获取成功', $templates); | ||
30 | + } | ||
31 | + | ||
32 | + | ||
33 | +} |
addons/groupon/controller/Order.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class Order extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = ['remind']; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + | ||
13 | + public function index() | ||
14 | + { | ||
15 | + $params = $this->request->get(); | ||
16 | + | ||
17 | + $this->success('订单列表', \addons\groupon\model\Order::getList($params)); | ||
18 | + } | ||
19 | + | ||
20 | + | ||
21 | + | ||
22 | + public function detail() | ||
23 | + { | ||
24 | + $params = $this->request->get(); | ||
25 | + $this->success('订单详情', \addons\groupon\model\Order::detail($params)); | ||
26 | + } | ||
27 | + | ||
28 | + | ||
29 | + public function itemDetail() | ||
30 | + { | ||
31 | + $params = $this->request->get(); | ||
32 | + $this->success('订单商品', \addons\groupon\model\Order::itemDetail($params)); | ||
33 | + } | ||
34 | + | ||
35 | + // | ||
36 | + public function statusNum () { | ||
37 | + $this->success('订单数量', \addons\groupon\model\Order::statusNum()); | ||
38 | + } | ||
39 | + | ||
40 | + | ||
41 | + // 取消订单 | ||
42 | + public function cancel() | ||
43 | + { | ||
44 | + $params = $this->request->post(); | ||
45 | + | ||
46 | + // 表单验证 | ||
47 | + $this->grouponValidate($params, get_class(), 'cancel'); | ||
48 | + | ||
49 | + $this->success('取消成功', \addons\groupon\model\Order::operCancel($params)); | ||
50 | + } | ||
51 | + | ||
52 | + // 删除订单 | ||
53 | + public function delete() | ||
54 | + { | ||
55 | + $params = $this->request->post(); | ||
56 | + | ||
57 | + // 表单验证 | ||
58 | + $this->grouponValidate($params, get_class(), 'delete'); | ||
59 | + | ||
60 | + $this->success('删除成功', \addons\groupon\model\Order::operDelete($params)); | ||
61 | + } | ||
62 | + | ||
63 | + // 确认收货订单 | ||
64 | + public function confirm() | ||
65 | + { | ||
66 | + repeat_filter(); // 防抖 | ||
67 | + $params = $this->request->post(); | ||
68 | + | ||
69 | + // 表单验证 | ||
70 | + $this->grouponValidate($params, get_class(), 'confirm'); | ||
71 | + | ||
72 | + $this->success('收货成功', \addons\groupon\model\Order::operConfirm($params)); | ||
73 | + } | ||
74 | + | ||
75 | + | ||
76 | + // 确认收货订单商品 | ||
77 | + public function confirmItem() | ||
78 | + { | ||
79 | + $params = $this->request->post(); | ||
80 | + | ||
81 | + // 表单验证 | ||
82 | + $this->grouponValidate($params, get_class(), 'confirm_item'); | ||
83 | + | ||
84 | + $this->success('收货成功', \addons\groupon\model\Order::operConfirmItem($params)); | ||
85 | + } | ||
86 | + | ||
87 | + | ||
88 | + public function comment () | ||
89 | + { | ||
90 | + $params = $this->request->post(); | ||
91 | + | ||
92 | + // 表单验证 | ||
93 | + $this->grouponValidate($params, get_class(), 'comment'); | ||
94 | + | ||
95 | + $this->success('评价成功', \addons\groupon\model\Order::operComment($params)); | ||
96 | + } | ||
97 | + | ||
98 | + | ||
99 | + public function pre() | ||
100 | + { | ||
101 | + $params = $this->request->post(); | ||
102 | + | ||
103 | + // 表单验证 | ||
104 | + $this->grouponValidate($params, get_class(), 'pre'); | ||
105 | + | ||
106 | + $result = \addons\groupon\model\Order::pre($params); | ||
107 | + | ||
108 | + $this->success('计算成功', $result); | ||
109 | + } | ||
110 | + | ||
111 | + | ||
112 | + public function createOrder() | ||
113 | + { | ||
114 | + repeat_filter(); // 防抖 | ||
115 | + $params = $this->request->post(); | ||
116 | + | ||
117 | + // 表单验证 | ||
118 | + $this->grouponValidate($params, get_class(), 'createOrder'); | ||
119 | + | ||
120 | + $order = \addons\groupon\model\Order::createOrder($params); | ||
121 | + | ||
122 | + $this->success('订单添加成功', $order); | ||
123 | + } | ||
124 | + | ||
125 | + | ||
126 | + // 获取可用优惠券列表 | ||
127 | + public function coupons () { | ||
128 | + $params = $this->request->post(); | ||
129 | + | ||
130 | + // 表单验证 | ||
131 | + $this->grouponValidate($params, get_class(), 'coupons'); | ||
132 | + | ||
133 | + $coupons = \addons\groupon\model\Order::coupons($params); | ||
134 | + | ||
135 | + $this->success('获取成功', $coupons); | ||
136 | + } | ||
137 | + | ||
138 | + | ||
139 | + public function remind() { | ||
140 | + // 查询最近三天的 20 个订单,的用户头像昵称 | ||
141 | + $reminds = \addons\groupon\model\Order::getRemind(); | ||
142 | + | ||
143 | + $this->success('获取成功', $reminds); | ||
144 | + } | ||
145 | +} |
addons/groupon/controller/Pay.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\epay\library\Service; | ||
6 | +use fast\Random; | ||
7 | +use think\addons\Controller; | ||
8 | +use addons\groupon\exception\Exception; | ||
9 | +use addons\groupon\model\Order; | ||
10 | +use addons\groupon\model\User; | ||
11 | +use think\Db; | ||
12 | +use think\Log; | ||
13 | +use Yansongda\Pay\Pay as YansongdaPay; | ||
14 | + | ||
15 | +class Pay extends Base | ||
16 | +{ | ||
17 | + | ||
18 | + protected $noNeedLogin = ['prepay', 'notifyx', 'notifyr', 'alipay']; | ||
19 | + protected $noNeedRight = ['*']; | ||
20 | + | ||
21 | + | ||
22 | + /** | ||
23 | + * 支付宝网页支付 | ||
24 | + */ | ||
25 | + public function alipay() | ||
26 | + { | ||
27 | + $pay_version = pay_version(); // 获取微信支付版本 | ||
28 | + | ||
29 | + $order_sn = $this->request->get('order_sn'); | ||
30 | + $platform = $this->request->get('platform'); | ||
31 | + | ||
32 | + $order = Order::where('order_sn', $order_sn)->find(); | ||
33 | + | ||
34 | + try { | ||
35 | + if (!$order) { | ||
36 | + throw new \Exception("订单不存在"); | ||
37 | + } | ||
38 | + if ($order->status > 0) { | ||
39 | + throw new \Exception("订单已支付"); | ||
40 | + } | ||
41 | + if ($order->status < 0) { | ||
42 | + throw new \Exception("订单已失效"); | ||
43 | + } | ||
44 | + | ||
45 | + $order_data = [ | ||
46 | + 'order_id' => $order->id, | ||
47 | + 'out_trade_no' => $order->order_sn, | ||
48 | + 'total_fee' => $order->total_fee, | ||
49 | + 'subject' => '商城订单支付', | ||
50 | + ]; | ||
51 | + | ||
52 | + if ($pay_version == 'v3') { | ||
53 | + $payService = new \addons\groupon\library\payv3\PayServiceV3('alipay', $platform); | ||
54 | + $result = $payService->pay($order_data, [], 'url'); | ||
55 | + | ||
56 | + $result = $result->getBody()->getContents(); | ||
57 | + } else { | ||
58 | + $notify_url = $this->request->root(true) . '/addons/groupon/pay/notifyx/payment/alipay/platform/H5'; | ||
59 | + $pay = new \addons\groupon\library\PayService('alipay', 'url', $notify_url); | ||
60 | + $result = $pay->create($order_data); | ||
61 | + | ||
62 | + $result = $result->getContent(); | ||
63 | + } | ||
64 | + | ||
65 | + $result = $pay->create($order_data); | ||
66 | + | ||
67 | + $result = $result->getContent(); | ||
68 | + | ||
69 | + echo $result; | ||
70 | + } catch (\Exception $e) { | ||
71 | + echo $e->getMessage(); | ||
72 | + } | ||
73 | + | ||
74 | + // $this->assign('result', $result); | ||
75 | + | ||
76 | + // return $this->view->fetch(); | ||
77 | + } | ||
78 | + | ||
79 | + | ||
80 | + /** | ||
81 | + * 拉起支付 | ||
82 | + */ | ||
83 | + public function prepay() | ||
84 | + { | ||
85 | + $user = User::info(); | ||
86 | + $pay_version = pay_version(); // 获取微信支付版本 | ||
87 | + | ||
88 | + $order_sn = $this->request->post('order_sn'); | ||
89 | + $payment = $this->request->post('payment'); | ||
90 | + $openid = $this->request->post('openid', ''); | ||
91 | + $platform = request()->header('platform'); | ||
92 | + | ||
93 | + $order = Order::nopay()->where('user_id', $user->id)->where('order_sn', $order_sn)->find(); | ||
94 | + | ||
95 | + if (!$order) { | ||
96 | + $this->error("订单不存在"); | ||
97 | + } | ||
98 | + | ||
99 | + if (in_array($order->status, [$order::STATUS_INVALID, $order::STATUS_CANCEL])) { | ||
100 | + $this->error("订单已失效"); | ||
101 | + } | ||
102 | + | ||
103 | + if (!$payment || !in_array($payment, ['wechat', 'alipay', 'wallet'])) { | ||
104 | + $this->error("支付类型不能为空"); | ||
105 | + } | ||
106 | + | ||
107 | + if ($payment == 'wallet') { | ||
108 | + // 余额支付 | ||
109 | + $this->walletPay($order, $payment, $platform); | ||
110 | + } | ||
111 | + | ||
112 | + $order_data = [ | ||
113 | + 'out_trade_no' => $order->order_sn, | ||
114 | + 'total_fee' => $order->total_fee, | ||
115 | + ]; | ||
116 | + | ||
117 | + // 微信公众号,小程序支付,必须有 openid | ||
118 | + if ($payment == 'wechat') { | ||
119 | + if (in_array($platform, ['wxOfficialAccount', 'wxMiniProgram'])) { | ||
120 | + if (isset($openid) && $openid) { | ||
121 | + // 如果传的有 openid | ||
122 | + $order_data['openid'] = $openid; | ||
123 | + } else { | ||
124 | + // 没有 openid 默认拿下单人的 openid | ||
125 | + $oauth = \addons\groupon\model\UserOauth::where([ | ||
126 | + 'user_id' => $order->user_id, | ||
127 | + 'provider' => 'Wechat', | ||
128 | + 'platform' => $platform | ||
129 | + ])->find(); | ||
130 | + | ||
131 | + $order_data['openid'] = $oauth ? $oauth->openid : ''; | ||
132 | + } | ||
133 | + | ||
134 | + if (empty($order_data['openid'])) { | ||
135 | + // 缺少 openid | ||
136 | + return $this->success('缺少 openid', 'no_openid'); | ||
137 | + } | ||
138 | + } | ||
139 | + | ||
140 | + $order_data['body'] = '商城订单支付'; | ||
141 | + } else { | ||
142 | + $order_data['subject'] = '商城订单支付'; | ||
143 | + } | ||
144 | + | ||
145 | + try { | ||
146 | + if ($pay_version == 'v3') { | ||
147 | + $payService = new \addons\groupon\library\payv3\PayServiceV3($payment); // 回调地址再 payServiceV3 中拼接 | ||
148 | + $result = $payService->pay($order_data); | ||
149 | + } else { | ||
150 | + $notify_url = $this->request->root(true) . '/addons/groupon/pay/notifyx/payment/' . $payment . '/platform/' . $platform; | ||
151 | + $pay = new \addons\groupon\library\PayService($payment, $platform, $notify_url); | ||
152 | + $result = $pay->create($order_data); | ||
153 | + } | ||
154 | + } catch (\Exception $e) { | ||
155 | + $this->error("支付配置错误:" . $e->getMessage()); | ||
156 | + } | ||
157 | + | ||
158 | + if ($platform == 'App') { | ||
159 | + if ($pay_version == 'v3') { | ||
160 | + if ($payment == 'wechat') { | ||
161 | + // Yansongda\Supports\Collection,可当数组,可当字符串, 因为前端会 JSON.parse 所以这里提前转字符串 | ||
162 | + $result = json_encode($result); | ||
163 | + } else { | ||
164 | + $result = $result->getBody()->getContents(); | ||
165 | + } | ||
166 | + } else { | ||
167 | + $result = $result->getContent(); | ||
168 | + } | ||
169 | + } | ||
170 | + if ($platform == 'H5' && $payment == 'wechat') { | ||
171 | + if ($pay_version == 'v3') { | ||
172 | + $result = [ | ||
173 | + 'h5_url' => $result->h5_url | ||
174 | + ]; | ||
175 | + } else { | ||
176 | + $result = $result->getContent(); | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + return $this->success('获取预付款成功', [ | ||
181 | + 'pay_data' => $result, | ||
182 | + ]); | ||
183 | + } | ||
184 | + | ||
185 | + | ||
186 | + | ||
187 | + // 余额支付 | ||
188 | + public function walletPay($order, $type, $method) | ||
189 | + { | ||
190 | + $order = Db::transaction(function () use ($order, $type, $method) { | ||
191 | + // 重新加锁读,防止连点问题 | ||
192 | + $order = Order::nopay()->where('order_sn', $order->order_sn)->lock(true)->find(); | ||
193 | + if (!$order) { | ||
194 | + $this->error("订单已支付"); | ||
195 | + } | ||
196 | + $total_fee = $order->total_fee; | ||
197 | + | ||
198 | + // 扣除余额 | ||
199 | + $user = User::info(); | ||
200 | + | ||
201 | + if (is_null($user)) { | ||
202 | + // 没有登录,请登录 | ||
203 | + $this->error(__('Please login first'), null, 401); | ||
204 | + } | ||
205 | + | ||
206 | + User::money(-$total_fee, $user->id, 'wallet_pay', $order->id, '', [ | ||
207 | + 'order_id' => $order->id, | ||
208 | + 'order_sn' => $order->order_sn, | ||
209 | + ]); | ||
210 | + | ||
211 | + // 支付后流程 | ||
212 | + $notify = [ | ||
213 | + 'order_sn' => $order['order_sn'], | ||
214 | + 'transaction_id' => '', | ||
215 | + 'notify_time' => date('Y-m-d H:i:s'), | ||
216 | + 'buyer_email' => $user->id, | ||
217 | + 'pay_fee' => $order->total_fee, | ||
218 | + 'pay_type' => 'wallet' // 支付方式 | ||
219 | + ]; | ||
220 | + $notify['payment_json'] = json_encode($notify); | ||
221 | + $order->paymentProcess($order, $notify); | ||
222 | + | ||
223 | + return $order; | ||
224 | + }); | ||
225 | + | ||
226 | + $this->success('支付成功', $order); | ||
227 | + } | ||
228 | + | ||
229 | + | ||
230 | + /** | ||
231 | + * 支付成功回调 | ||
232 | + */ | ||
233 | + public function notifyx() | ||
234 | + { | ||
235 | + Log::write('notifyx-comein:'); | ||
236 | + | ||
237 | + $pay_version = pay_version(); // 获取微信支付版本 | ||
238 | + | ||
239 | + $payment = $this->request->param('payment'); | ||
240 | + $platform = $this->request->param('platform'); | ||
241 | + | ||
242 | + if ($pay_version == 'v3') { | ||
243 | + $pay = new \addons\groupon\library\payv3\PayServiceV3($payment, $platform); | ||
244 | + } else { | ||
245 | + $pay = new \addons\groupon\library\PayService($payment, $platform); | ||
246 | + } | ||
247 | + | ||
248 | + $result = $pay->notify(function ($data, $pay = null) use ($payment, $pay_version) { | ||
249 | + Log::write('notifyx-result:' . json_encode($data)); | ||
250 | + // { // 微信回调参数 | ||
251 | + // "appid":"wx39cd0799d4567dd0", | ||
252 | + // "bank_type":"OTHERS", | ||
253 | + // "cash_fee":"1", | ||
254 | + // "fee_type":"CNY", | ||
255 | + // "is_subscribe":"N", | ||
256 | + // "mch_id":"1481069012", | ||
257 | + // "nonce_str":"dPpcZ6AzCDU8daNC", | ||
258 | + // "openid":"oD9ko4x7QMDQPZEuN8V5jtZjie3g", | ||
259 | + // "out_trade_no":"202010240834057843002700", | ||
260 | + // "result_code":"SUCCESS", | ||
261 | + // "return_code":"SUCCESS", | ||
262 | + // "sign":"3103B6D06F13D2B3959C5B3F7F1FD61C", | ||
263 | + // "time_end":"20200407102424", | ||
264 | + // "total_fee":"1", | ||
265 | + // "trade_type":"JSAPI", | ||
266 | + // "transaction_id":"4200000479202004070804485027" | ||
267 | + // } | ||
268 | + | ||
269 | + // { // 支付宝支付成功回调参数 | ||
270 | + // "gmt_create":"2020-04-10 19:15:00", | ||
271 | + // "charset":"utf-8", | ||
272 | + // "seller_email":"xptech@qq.com", | ||
273 | + // "subject":"\u5546\u57ce\u8ba2\u5355\u652f\u4ed8", | ||
274 | + // "sign":"AOiYZ1a2mEMOuIbHFCi6V6A0LJ97UMiHsCWgNdSU9dlzKFl15Ts8b0mL\/tN+Hhskl+94S3OUiNTBD3dD0Kv923SqaTWxNdj533PCdo2GDKsZIZgKbavnOvaccSKUdmQRE9KtmePPq9V9lFzEQvdUkKq1M8KAWO5K9LTy2iT2y5CUynpiu\/04GVzsTL9PqY+LDwqj6K+w7MgceWm1BWaFWg27AXIRw7wvsFckr3k9GGajgE2fufhoCYGYtGFbhGOp6ExtqS5RXBuPODOyRhBLpD8mwpOX38Oy0X+R4YQIrOi02dhqwPpvw79YjnvgXY3qZEQ66EdUsrT7EBdcPHK0Gw==", | ||
275 | + // "buyer_id":"2088902485164146", | ||
276 | + // "invoice_amount":"0.01", | ||
277 | + // "notify_id":"2020041000222191501064141414240102", | ||
278 | + // "fund_bill_list":"[{\"amount\":\"0.01\",\"fundChannel\":\"PCREDIT\"}]", | ||
279 | + // "notify_type":"trade_status_sync", | ||
280 | + // "trade_status":"TRADE_SUCCESS", | ||
281 | + // "receipt_amount":"0.01", | ||
282 | + // "buyer_pay_amount":"0.01", | ||
283 | + // "app_id":"2021001114666742", | ||
284 | + // "sign_type":"RSA2", | ||
285 | + // "seller_id":"2088721922277739", | ||
286 | + // "gmt_payment":"2020-04-10 19:15:00", | ||
287 | + // "notify_time":"2020-04-10 19:15:01", | ||
288 | + // "version":"1.0", | ||
289 | + // "out_trade_no":"202007144778322770017000", | ||
290 | + // "total_amount":"0.01", | ||
291 | + // "trade_no":"2020041022001464141443020240", | ||
292 | + // "auth_app_id":"2021001114666742", | ||
293 | + // "buyer_logon_id":"157***@163.com", | ||
294 | + // "point_amount":"0.00" | ||
295 | + // } | ||
296 | + | ||
297 | + // { // 支付宝退款成功(交易关闭)回调参数 | ||
298 | + // "gmt_create": "2020-08-15 14:48:32", | ||
299 | + // "charset": "utf-8", | ||
300 | + // "seller_email": "xptech@qq.com", | ||
301 | + // "gmt_payment": "2020-08-15 14:48:32", | ||
302 | + // "notify_time": "2020-08-15 16:11:45", | ||
303 | + // "subject": "商城订单支付", | ||
304 | + // "gmt_refund": "2020-08-15 16:11:45.140", | ||
305 | + // "sign": "b6ArkgzLIRteRL9FMGC6i\/jf6VwFYQbaGDGRx002W+pdmN5q9+O4edZ3ALF74fYaijSl9ksNr0dKdvanu3uYxBTcd\/GIS4N1CWzmCOv6pzgx5rO\/YvGoHLM3Yop0GKKuMxmnNsZ6jhYKEY7SYD3Y0L6PU9ZMdHV7yIiVj+zZmbKzUgK9MPDCEXs+nzpNAiSM8GTqYRSUvKobAK68hswG2k1QIcqr5z+ZmVYa\/nHHkoC9qXt5zwyGi4P+2eOsr6V2PjA3x8qqe7TN5aI1DeoZD5KqHPYYaYF17J2q6YPlgl3WUl1RhE7H86bivB1fIuYEv\/3+JR74WN\/o7krGw1RPHg==", | ||
306 | + // "out_biz_no": "R202004114414846255015300", | ||
307 | + // "buyer_id": "2088902485164146", | ||
308 | + // "version": "1.0", | ||
309 | + // "notify_id": "2020081500222161145064141453349793", | ||
310 | + // "notify_type": "trade_status_sync", | ||
311 | + // "out_trade_no": "202002460317545607015300", | ||
312 | + // "total_amount": "0.01", | ||
313 | + // "trade_status": "TRADE_CLOSED", | ||
314 | + // "refund_fee": "0.01", | ||
315 | + // "trade_no": "2020081522001464141438570535", | ||
316 | + // "auth_app_id": "2021001114666742", | ||
317 | + // "buyer_logon_id": "157***@163.com", | ||
318 | + // "gmt_close": "2020-08-15 16:11:45", | ||
319 | + // "app_id": "2021001114666742", | ||
320 | + // "sign_type": "RSA2", | ||
321 | + // "seller_id": "2088721922277739" | ||
322 | + // } | ||
323 | + | ||
324 | + try { | ||
325 | + $out_trade_no = $data['out_trade_no']; | ||
326 | + $out_refund_no = $data['out_biz_no'] ?? ''; | ||
327 | + | ||
328 | + | ||
329 | + | ||
330 | + // 判断是否是支付宝退款(支付宝退款成功会通知该接口) | ||
331 | + if ($payment == 'alipay' // 支付宝支付 | ||
332 | + && $data['notify_type'] == 'trade_status_sync' // 同步交易状态 | ||
333 | + && $data['trade_status'] == 'TRADE_CLOSED' // 交易关闭 | ||
334 | + && $out_refund_no // 退款单号 | ||
335 | + ) { | ||
336 | + // 退款回调 | ||
337 | + $this->refundFinish($out_trade_no, $out_refund_no); | ||
338 | + | ||
339 | + return $this->payResponse($pay, $payment); | ||
340 | + } | ||
341 | + | ||
342 | + | ||
343 | + // 判断支付宝微信是否是支付成功状态,如果不是,直接返回响应 | ||
344 | + if ($payment == 'alipay' && $data['trade_status'] != 'TRADE_SUCCESS') { | ||
345 | + // 不是交易成功的通知,直接返回成功 | ||
346 | + return $this->payResponse($pay, $payment); | ||
347 | + } | ||
348 | + | ||
349 | + if ($pay_version == 'v3') { | ||
350 | + // 支付成功流程 | ||
351 | + $pay_fee = $data['pay_fee']; | ||
352 | + } else { | ||
353 | + if ($payment == 'wechat' && ($data['result_code'] != 'SUCCESS' || $data['return_code'] != 'SUCCESS')) { | ||
354 | + // 微信交易未成功,返回 false,让微信再次通知 | ||
355 | + return false; | ||
356 | + } | ||
357 | + | ||
358 | + // 支付成功流程 | ||
359 | + $pay_fee = $payment == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100; | ||
360 | + } | ||
361 | + | ||
362 | + //你可以在此编写订单逻辑 | ||
363 | + $order = Order::where('order_sn', $out_trade_no)->find(); | ||
364 | + | ||
365 | + if (!$order || $order->status > 0) { | ||
366 | + // 订单不存在,或者订单已支付 | ||
367 | + return $this->payResponse($pay, $payment); | ||
368 | + } | ||
369 | + | ||
370 | + Db::transaction(function () use ($order, $data, $payment, $pay_fee) { | ||
371 | + $notify = [ | ||
372 | + 'order_sn' => $data['out_trade_no'], | ||
373 | + 'transaction_id' => $payment == 'alipay' ? $data['trade_no'] : $data['transaction_id'], | ||
374 | + 'notify_time' => date('Y-m-d H:i:s', (strtotime($data['time_end'] ?? $data['notify_time']))), | ||
375 | + 'buyer_email' => $payment == 'alipay' ? $data['buyer_logon_id'] : $data['openid'], | ||
376 | + 'payment_json' => json_encode($data), | ||
377 | + 'pay_fee' => $pay_fee, | ||
378 | + 'pay_type' => $payment // 支付方式 | ||
379 | + ]; | ||
380 | + $order->paymentProcess($order, $notify); | ||
381 | + }); | ||
382 | + | ||
383 | + return $this->payResponse($pay, $payment); | ||
384 | + } catch (\Exception $e) { | ||
385 | + Log::write('notifyx-error:' . json_encode($e->getMessage())); | ||
386 | + } | ||
387 | + }); | ||
388 | + | ||
389 | + return $result; | ||
390 | + } | ||
391 | + | ||
392 | + | ||
393 | + /** | ||
394 | + * 退款成功回调 | ||
395 | + */ | ||
396 | + public function notifyr() | ||
397 | + { | ||
398 | + Log::write('notifyreturn-comein:'); | ||
399 | + | ||
400 | + $pay_version = pay_version(); // 获取微信支付版本 | ||
401 | + $payment = $this->request->param('payment'); | ||
402 | + $platform = $this->request->param('platform'); | ||
403 | + | ||
404 | + if ($pay_version == 'v3') { | ||
405 | + $pay = new \addons\groupon\library\payv3\PayServiceV3($payment, $platform); | ||
406 | + } else { | ||
407 | + $pay = new \addons\groupon\library\PayService($payment, $platform); | ||
408 | + } | ||
409 | + | ||
410 | + $result = $pay->notifyRefund(function ($data, $pay = null) use ($payment, $platform) { | ||
411 | + try { | ||
412 | + $out_refund_no = $data['out_refund_no']; | ||
413 | + $out_trade_no = $data['out_trade_no']; | ||
414 | + | ||
415 | + // 退款 | ||
416 | + $this->refundFinish($out_trade_no, $out_refund_no); | ||
417 | + | ||
418 | + return $this->payResponse($pay, $payment); | ||
419 | + } catch (\Exception $e) { | ||
420 | + Log::write('notifyreturn-error:' . json_encode($e->getMessage())); | ||
421 | + return false; | ||
422 | + } | ||
423 | + }); | ||
424 | + | ||
425 | + return $result; | ||
426 | + } | ||
427 | + | ||
428 | + | ||
429 | + private function refundFinish($out_trade_no, $out_refund_no) | ||
430 | + { | ||
431 | + $order = Order::where('order_sn', $out_trade_no)->find(); | ||
432 | + $refundLog = \app\admin\model\groupon\order\RefundLog::where('refund_sn', $out_refund_no)->find(); | ||
433 | + | ||
434 | + if (!$order || !$refundLog || $refundLog->status != 0) { | ||
435 | + // 订单不存在,或者订单已退款 | ||
436 | + return true; | ||
437 | + } | ||
438 | + | ||
439 | + $item = \app\admin\model\groupon\order\OrderItem::where('id', $refundLog->order_item_id)->find(); | ||
440 | + | ||
441 | + Db::transaction(function () use ($order, $item, $refundLog) { | ||
442 | + \app\admin\model\groupon\order\Order::refundFinish($order, $item, $refundLog); | ||
443 | + }); | ||
444 | + | ||
445 | + return true; | ||
446 | + } | ||
447 | + | ||
448 | + | ||
449 | + /** | ||
450 | + * v2, v3 响应转换 | ||
451 | + */ | ||
452 | + private function payResponse($pay = null, $payment = null) | ||
453 | + { | ||
454 | + $pay_version = pay_version(); // 获取微信支付版本 | ||
455 | + | ||
456 | + if ($pay_version == 'v3') { | ||
457 | + $result = YansongdaPay::$payment()->success(); | ||
458 | + | ||
459 | + $content = $result->getBody()->getContents(); | ||
460 | + $content = $payment == 'wechat' ? json_decode($content, true) : $content; | ||
461 | + return response($content, 200, [], ($payment == 'wechat' ? 'json' : '')); | ||
462 | + } else { | ||
463 | + return $pay->success()->send(); | ||
464 | + } | ||
465 | + | ||
466 | + return $pay_version == 'v3' ? YansongdaPay::$payment()->success() : $pay->success()->send(); | ||
467 | + } | ||
468 | +} |
addons/groupon/controller/Share.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\model\Share as ShareModel; | ||
6 | + | ||
7 | +class Share extends Base | ||
8 | +{ | ||
9 | + | ||
10 | + protected $noNeedLogin = []; | ||
11 | + protected $noNeedRight = ['*']; | ||
12 | + | ||
13 | + | ||
14 | + /** | ||
15 | + * 获取分享记录 | ||
16 | + * | ||
17 | + * @return void | ||
18 | + */ | ||
19 | + public function index() | ||
20 | + { | ||
21 | + $params = $this->request->get(); | ||
22 | + | ||
23 | + $shares = ShareModel::getList($params); | ||
24 | + return $this->success('获取成功', $shares); | ||
25 | + } | ||
26 | + | ||
27 | + | ||
28 | + public function add() | ||
29 | + { | ||
30 | + $params = $this->request->post(); | ||
31 | + $params['platform'] = $this->request->header('platform'); | ||
32 | + $shareLog = ShareModel::add($params); | ||
33 | + if ($shareLog) { | ||
34 | + \think\Hook::listen('share_after', $shareLog); | ||
35 | + $this->success('添加分享记录', $shareLog); | ||
36 | + } | ||
37 | + | ||
38 | + $this->success('添加分享记录'); // 使用 success 前端不提示 | ||
39 | + } | ||
40 | +} |
addons/groupon/controller/Sms.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use app\common\library\Sms as Smslib; | ||
6 | +use addons\groupon\model\User; | ||
7 | +use think\Hook; | ||
8 | + | ||
9 | +/** | ||
10 | + * 手机短信接口 | ||
11 | + */ | ||
12 | +class Sms extends Base | ||
13 | +{ | ||
14 | + protected $noNeedLogin = '*'; | ||
15 | + protected $noNeedRight = '*'; | ||
16 | + | ||
17 | + /** | ||
18 | + * 发送验证码 | ||
19 | + * | ||
20 | + * @param string $mobile 手机号 | ||
21 | + * @param string $event 事件名称 | ||
22 | + */ | ||
23 | + public function send() | ||
24 | + { | ||
25 | + $mobile = $this->request->post("mobile"); | ||
26 | + $event = $this->request->post("event"); | ||
27 | + $event = $event ? $event : 'register'; | ||
28 | + | ||
29 | + if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) { | ||
30 | + $this->error(__('手机号不正确')); | ||
31 | + } | ||
32 | + $last = Smslib::get($mobile, $event); | ||
33 | + if ($last && time() - $last['createtime'] < 60) { | ||
34 | + $this->error(__('发送频繁')); | ||
35 | + } | ||
36 | + $ipSendTotal = \app\common\model\Sms::where(['ip' => $this->request->ip()])->whereTime('createtime', '-1 hours')->count(); | ||
37 | + if ($ipSendTotal >= 5) { | ||
38 | + $this->error(__('发送频繁')); | ||
39 | + } | ||
40 | + if ($event) { | ||
41 | + $userinfo = User::getByMobile($mobile); | ||
42 | + if ($event == 'register' && $userinfo) { | ||
43 | + //已被注册 | ||
44 | + $this->error(__('已被注册')); | ||
45 | + } elseif (in_array($event, ['changemobile']) && $userinfo) { | ||
46 | + //被占用 | ||
47 | + $this->error(__('已被占用')); | ||
48 | + } elseif (in_array($event, ['changepwd', 'resetpwd', 'mobilelogin']) && !$userinfo) { | ||
49 | + //未注册 | ||
50 | + $this->error(__('未注册')); | ||
51 | + } | ||
52 | + } | ||
53 | + if (!Hook::get('sms_send')) { | ||
54 | + $this->error(__('请在后台插件管理安装短信验证插件')); | ||
55 | + } | ||
56 | + $ret = Smslib::send($mobile, null, $event); | ||
57 | + if ($ret) { | ||
58 | + $this->success(__('发送成功')); | ||
59 | + } else { | ||
60 | + $this->error(__('发送失败,请检查短信配置是否正确')); | ||
61 | + } | ||
62 | + } | ||
63 | + | ||
64 | + /** | ||
65 | + * 检测验证码 | ||
66 | + * | ||
67 | + * @param string $mobile 手机号 | ||
68 | + * @param string $event 事件名称 | ||
69 | + * @param string $captcha 验证码 | ||
70 | + */ | ||
71 | + public function check() | ||
72 | + { | ||
73 | + $mobile = $this->request->post("mobile"); | ||
74 | + $event = $this->request->post("event"); | ||
75 | + $event = $event ? $event : 'register'; | ||
76 | + $captcha = $this->request->post("captcha"); | ||
77 | + | ||
78 | + if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) { | ||
79 | + $this->error(__('手机号不正确')); | ||
80 | + } | ||
81 | + if ($event) { | ||
82 | + $userinfo = User::getByMobile($mobile); | ||
83 | + if ($event == 'register' && $userinfo) { | ||
84 | + //已被注册 | ||
85 | + $this->error(__('已被注册')); | ||
86 | + } elseif (in_array($event, ['changemobile']) && $userinfo) { | ||
87 | + //被占用 | ||
88 | + $this->error(__('已被占用')); | ||
89 | + } elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) { | ||
90 | + //未注册 | ||
91 | + $this->error(__('未注册')); | ||
92 | + } | ||
93 | + } | ||
94 | + $ret = Smslib::check($mobile, $captcha, $event); | ||
95 | + if ($ret) { | ||
96 | + $this->success(__('成功')); | ||
97 | + } else { | ||
98 | + $this->error(__('验证码不正确')); | ||
99 | + } | ||
100 | + } | ||
101 | +} |
addons/groupon/controller/Store.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\model\Store as ModelStore; | ||
7 | +use addons\groupon\model\User; | ||
8 | +use addons\groupon\model\UserStore; | ||
9 | + | ||
10 | +class Store extends Base | ||
11 | +{ | ||
12 | + | ||
13 | + protected $noNeedLogin = ['nearby', 'detail']; | ||
14 | + protected $noNeedRight = ['*']; | ||
15 | + | ||
16 | + | ||
17 | + public function index() | ||
18 | + { | ||
19 | + $user = User::info(); | ||
20 | + $userStore = UserStore::where('user_id', $user->id)->select(); | ||
21 | + $store_id_arr = array_column($userStore, 'store_id'); | ||
22 | + | ||
23 | + $stores = []; | ||
24 | + if ($store_id_arr) { | ||
25 | + $stores = ModelStore::show()->where('id', 'in', $store_id_arr)->select(); | ||
26 | + } | ||
27 | + | ||
28 | + $this->success('获取自提点列表', $stores); | ||
29 | + } | ||
30 | + | ||
31 | + | ||
32 | + | ||
33 | + public function nearby() | ||
34 | + { | ||
35 | + $params = $this->request->get(); | ||
36 | + | ||
37 | + $stores = ModelStore::getStoreList($params); | ||
38 | + | ||
39 | + $this->success('获取自提点列表', $stores); | ||
40 | + } | ||
41 | + | ||
42 | + | ||
43 | + public function detail() { | ||
44 | + $params = $this->request->get(); | ||
45 | + | ||
46 | + $store = ModelStore::getStoreDetail($params); | ||
47 | + | ||
48 | + $this->success('获取自提点', $store); | ||
49 | + } | ||
50 | +} |
addons/groupon/controller/User.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use app\common\library\Ems; | ||
6 | +use app\common\library\Sms; | ||
7 | +use fast\Random; | ||
8 | +use think\Validate; | ||
9 | +use addons\groupon\library\Wechat; | ||
10 | +use think\Db; | ||
11 | +use addons\groupon\model\UserOauth; | ||
12 | +use addons\groupon\model\User as UserModel; | ||
13 | +use addons\groupon\model\UserStore; | ||
14 | + | ||
15 | +/** | ||
16 | + * 会员接口 | ||
17 | + */ | ||
18 | +class User extends Base | ||
19 | +{ | ||
20 | + protected $noNeedLogin = ['login', 'mobilelogin', 'accountLogin', 'register', 'resetpwd', 'changeemail', 'changemobile', 'third', 'wxMiniProgramOauth', 'getWxMiniProgramSessionKey', 'getUserDefaultFields']; | ||
21 | + protected $noNeedRight = '*'; | ||
22 | + | ||
23 | + public function _initialize() | ||
24 | + { | ||
25 | + return parent::_initialize(); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * 会员中心 | ||
30 | + */ | ||
31 | + public function index() | ||
32 | + { | ||
33 | + $auth = \app\common\library\Auth::instance(); | ||
34 | + $auth->setAllowFields(['id', 'username', 'nickname', 'mobile', 'avatar', 'score', 'birthday', 'money', 'group', 'group_id', 'child_user_count', 'child_user_count_1', 'child_user_count_2', 'total_consume']); | ||
35 | + $data = $auth->getUserinfo(); | ||
36 | + $data['avatar'] = $data['avatar'] ? cdnurl($data['avatar'], true) : ''; | ||
37 | + if (!isset($data['group'])) { | ||
38 | + $data['group'] = \addons\groupon\model\UserGroup::get($data['group_id']); | ||
39 | + } | ||
40 | + | ||
41 | + // 查询用户优惠券数量 | ||
42 | + $userCoupons = \addons\groupon\model\Coupons::getCouponsList(1); | ||
43 | + $data['coupons_num'] = count($userCoupons); | ||
44 | + | ||
45 | + // 查询用户是否是门店管理员 | ||
46 | + $userStores = UserStore::where('user_id', $data['id'])->select(); | ||
47 | + $data['is_store'] = $userStores ? 1 : 0; | ||
48 | + $data['store_id'] = 0; | ||
49 | + if (count($userStores) == 1) { | ||
50 | + // 只有一个店铺 直接进入店铺 | ||
51 | + $data['store_id'] = $userStores[0]['store_id']; | ||
52 | + } | ||
53 | + | ||
54 | + $this->success('用户信息', $data); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * 会员登录 | ||
59 | + * | ||
60 | + * @param string $account 账号 | ||
61 | + * @param string $password 密码 | ||
62 | + */ | ||
63 | + public function accountLogin() | ||
64 | + { | ||
65 | + $account = $this->request->post('account'); | ||
66 | + $password = $this->request->post('password'); | ||
67 | + if (!$account || !$password) { | ||
68 | + $this->error(__('Invalid parameters')); | ||
69 | + } | ||
70 | + $ret = $this->auth->login($account, $password); | ||
71 | + if ($ret) { | ||
72 | + $data = ['userinfo' => $this->auth->getUserinfo()]; | ||
73 | + $this->success(__('Logged in successful'), $data); | ||
74 | + } else { | ||
75 | + $this->error($this->auth->getError()); | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * 获取微信小程序session_key | ||
81 | + * | ||
82 | + * @param string $code 加密code | ||
83 | + * @param boolean $autoLogin 是否自动登录(需已注册会员) | ||
84 | + */ | ||
85 | + public function getWxMiniProgramSessionKey() | ||
86 | + { | ||
87 | + $post = $this->request->post(); | ||
88 | + $autoLogin = $post['autoLogin']; | ||
89 | + $wechat = new Wechat('wxMiniProgram'); | ||
90 | + $decryptSession = $wechat->code($post['code']); | ||
91 | + if (!isset($decryptSession['session_key'])) { | ||
92 | + $this->error('未获取session_key,请重启应用'); | ||
93 | + } | ||
94 | + $uuid = Random::uuid(); | ||
95 | + \think\Cache::set($uuid, $decryptSession, 24 * 3600 * 30); // 强制30天过期 | ||
96 | + $userOauth = UserOauth::get([ | ||
97 | + 'provider' => 'Wechat', | ||
98 | + 'platform' => 'wxMiniProgram', | ||
99 | + 'openid' => $decryptSession['openid'], | ||
100 | + 'user_id' => ['neq', 0] | ||
101 | + ]); | ||
102 | + if ($userOauth) { | ||
103 | + $userOauth->save(['session_key' => $decryptSession['session_key']]); | ||
104 | + } | ||
105 | + if ($autoLogin && $userOauth) { | ||
106 | + $ret = $this->auth->direct($userOauth->user_id); | ||
107 | + if ($ret) { | ||
108 | + $token = $this->auth->getToken(); | ||
109 | + $this->success(__('Logged in successful'), ['token' => $token, 'session_id' => $uuid, 'openid' => $decryptSession['openid']]); | ||
110 | + } else { | ||
111 | + $this->error($this->auth->getError()); | ||
112 | + } | ||
113 | + } | ||
114 | + | ||
115 | + $this->success('', ['session_id' => $uuid]); | ||
116 | + } | ||
117 | + /** | ||
118 | + * 微信小程序登录 | ||
119 | + * | ||
120 | + * @param string $session_key session_key | ||
121 | + * @param string $signature 校验签名 | ||
122 | + * @param string $iv 解密向量 | ||
123 | + * @param string $encryptedData 需解密完整用户信息 | ||
124 | + * @param boolean $refresh 重新获取或刷新最新的用户信息 (用户头像失效或微信客户端修改昵称等情况) | ||
125 | + */ | ||
126 | + public function wxMiniProgramOauth() | ||
127 | + { | ||
128 | + $post = $this->request->post(); | ||
129 | + $post['encryptedData'] = $this->request->post('encryptedData', null, null); | ||
130 | + | ||
131 | + $token = Db::transaction(function () use ($post) { | ||
132 | + try { | ||
133 | + $wechat = new Wechat('wxMiniProgram'); | ||
134 | + $decryptSession = \think\Cache::get($post['session_id']); | ||
135 | + if (!$decryptSession || !isset($decryptSession['openid'])) { | ||
136 | + throw new \Exception('未获取到登录态,请重试'); | ||
137 | + } | ||
138 | + $decryptUserInfo = $wechat->decryptData($decryptSession['session_key'], $post['iv'], $post['encryptedData']); // 客户端传值数据都不可信,需服务端解密用户信息 | ||
139 | + $decryptUserInfo = array_merge($decryptUserInfo, $decryptSession); | ||
140 | + //组装decryptData | ||
141 | + $decryptData = array_change_key_case($decryptUserInfo, CASE_LOWER); | ||
142 | + if (empty($decryptData['openid'])) { | ||
143 | + throw new \Exception('code错误,请重试'); | ||
144 | + } | ||
145 | + $decryptData['headimgurl'] = $decryptData['avatarurl']; | ||
146 | + $decryptData['sex'] = $decryptData['gender']; | ||
147 | + $decryptData['session_key'] = $decryptSession['session_key']; | ||
148 | + return $this->oauthLoginOrRegisterOrBindOrRefresh($post['event'], $decryptData, 'wxMiniProgram', 'Wechat'); | ||
149 | + } catch (\Exception $e) { | ||
150 | + $this->error($e->getMessage()); | ||
151 | + } | ||
152 | + }); | ||
153 | + | ||
154 | + if ($token) { | ||
155 | + $this->success(__('Logged in successful'), ['token' => $token]); | ||
156 | + } else { | ||
157 | + $this->error($this->auth->getError()); | ||
158 | + } | ||
159 | + } | ||
160 | + | ||
161 | + | ||
162 | + /** | ||
163 | + * 微信小程序登录 | ||
164 | + * | ||
165 | + * @param string $code 加密code | ||
166 | + */ | ||
167 | + public function wxMiniProgramPhone() | ||
168 | + { | ||
169 | + $user = $this->auth->getUser(); | ||
170 | + | ||
171 | + $post = $this->request->post(); | ||
172 | + $decryptSession = \think\Cache::get($post['session_id']); | ||
173 | + $wechat = new Wechat('wxMiniProgram'); | ||
174 | + $decryptUserInfo = $wechat->decryptData($decryptSession['session_key'], $post['iv'], $post['encryptedData']); | ||
175 | + | ||
176 | + $phone = $decryptUserInfo['purePhoneNumber']; | ||
177 | + | ||
178 | + if (empty($phone)) { | ||
179 | + $this->error('获取手机号授权失败'); | ||
180 | + } | ||
181 | + | ||
182 | + if ($post['type'] == 'bind') { | ||
183 | + // 绑定手机号 | ||
184 | + if (\app\common\model\User::where('mobile', $phone)->where('id', '<>', $user->id)->find()) { | ||
185 | + $this->error('手机号已存在'); | ||
186 | + } | ||
187 | + | ||
188 | + $verification = $user->verification; | ||
189 | + $verification->mobile = 1; | ||
190 | + $user->verification = $verification; | ||
191 | + $user->mobile = $phone; | ||
192 | + $user->save(); | ||
193 | + } | ||
194 | + | ||
195 | + $this->success("绑定成功", [ | ||
196 | + 'phone' => $phone | ||
197 | + ]); | ||
198 | + } | ||
199 | + | ||
200 | + /** | ||
201 | + * 第三方登录或自动注册 | ||
202 | + * | ||
203 | + * @param array $decryptData 解密参数 | ||
204 | + * @param string $platform 平台名称 | ||
205 | + * @param string $provider 厂商名称 | ||
206 | + * @param int $keeptime 有效时长 | ||
207 | + * @param boolean $refresh 刷新头像和昵称 | ||
208 | + */ | ||
209 | + private function oauthLoginOrRegisterOrBindOrRefresh($event, $decryptData, $platform, $provider, $keeptime = 0) | ||
210 | + { | ||
211 | + $oauthData = $decryptData; | ||
212 | + $oauthData = array_merge($oauthData, [ | ||
213 | + 'provider' => $provider, | ||
214 | + 'platform' => $platform, | ||
215 | + | ||
216 | + ]); | ||
217 | + if ($platform === 'wxMiniProgram' || $platform === 'App') { | ||
218 | + $oauthData['expire_in'] = 7200; | ||
219 | + $oauthData['expiretime'] = time() + 7200; | ||
220 | + } | ||
221 | + $userOauth = UserOauth::where(['openid' => $decryptData['openid'], 'user_id' => ['neq', 0]])->where('platform', $platform)->where('provider', $provider)->lock(true)->find(); | ||
222 | + switch ($event) { | ||
223 | + case 'login': // 登录(自动注册) | ||
224 | + if (!$userOauth) { // 没有找到第三方登录信息 创建新用户 | ||
225 | + //默认创建新用户 | ||
226 | + $user_id = 0; | ||
227 | + $createNewUser = true; | ||
228 | + $oauthData['logintime'] = time(); | ||
229 | + $oauthData['logincount'] = 1; | ||
230 | + // 判断是否有unionid 并且已存在oauth数据中 | ||
231 | + if (isset($oauthData['unionid'])) { | ||
232 | + //存在同厂商信息,添加oauthData数据,合并用户 | ||
233 | + $userUnionOauth = UserOauth::get(['unionid' => $oauthData['unionid'], 'provider' => $provider, 'user_id' => ['neq', 0]]); | ||
234 | + if ($userUnionOauth) { | ||
235 | + $existUser = $this->auth->direct($userUnionOauth->user_id); | ||
236 | + if ($existUser) { | ||
237 | + $createNewUser = false; | ||
238 | + } | ||
239 | + } | ||
240 | + } | ||
241 | + | ||
242 | + // 创建空用户 | ||
243 | + if ($createNewUser) { | ||
244 | + $username = Random::alnum(20); | ||
245 | + $password = ''; | ||
246 | + $domain = request()->host(); | ||
247 | + $extend = $this->getUserDefaultFields(); | ||
248 | + $extend['nickname'] = $oauthData['nickname'] ? $oauthData['nickname'] : $extend['nickname']; | ||
249 | + $extend['avatar'] = $oauthData['headimgurl'] ? $oauthData['headimgurl'] : $extend['avatar']; | ||
250 | + $this->auth->register($username, $password, $username . '@' . $domain, '', $extend, $keeptime); | ||
251 | + if (empty($oauthData['nickname'])) { | ||
252 | + $this->auth->getUser()->save(['nickname' => $extend['nickname'] . $this->auth->getUser()->id]); | ||
253 | + } | ||
254 | + } | ||
255 | + $oauthData['user_id'] = $this->auth->getUser()->id; | ||
256 | + $oauthData['createtime'] = time(); | ||
257 | + UserOauth::strict(false)->insert($oauthData); | ||
258 | + } else { | ||
259 | + // 找到第三方登录信息,直接登录 | ||
260 | + $user_id = $userOauth->user_id; | ||
261 | + if ($this->auth->direct($user_id) && $this->auth->getUser()) { // 获取到用户 | ||
262 | + $oauthData['logincount'] = $userOauth->logincount + 1; | ||
263 | + $oauthData['logintime'] = time(); | ||
264 | + $userOauth->allowField(true)->save($oauthData); | ||
265 | + } else { // 用户已被删除 重新执行登录 | ||
266 | + // throw new \Exception('此用户已删除'); | ||
267 | + $userOauth->delete(); | ||
268 | + $this->oauthLoginOrRegisterOrBindOrRefresh($event, $decryptData, $platform, $provider); | ||
269 | + } | ||
270 | + } | ||
271 | + break; | ||
272 | + case 'refresh': | ||
273 | + if (!$userOauth) { | ||
274 | + throw new \Exception('未找到第三方授权账户'); | ||
275 | + } | ||
276 | + if (!empty($oauthData['nickname'])) { | ||
277 | + $refreshFields['nickname'] = $oauthData['nickname']; | ||
278 | + } | ||
279 | + if (!empty($oauthData['headimgurl'])) { | ||
280 | + $refreshFields['avatar'] = $oauthData['headimgurl']; | ||
281 | + } | ||
282 | + $this->auth->getUser()->save($refreshFields); | ||
283 | + $userOauth->allowField(true)->save($oauthData); | ||
284 | + break; | ||
285 | + case 'bind': | ||
286 | + if (!$this->auth->getUser()) { | ||
287 | + throw new \Exception('请先登录'); | ||
288 | + } | ||
289 | + | ||
290 | + $oauthData['user_id'] = $this->auth->getUser()->id; | ||
291 | + | ||
292 | + if ($userOauth) { | ||
293 | + if ($userOauth['user_id'] != 0 && $userOauth['user_id'] != $this->auth->getUser()->id && UserModel::get($userOauth['user_id'])) { | ||
294 | + throw new \Exception('该账号已被其他用户绑定'); | ||
295 | + } | ||
296 | + $oauthData['id'] = $userOauth->id; | ||
297 | + $userOauth->strict(false)->update($oauthData); | ||
298 | + } else { | ||
299 | + $oauthData['logincount'] = 1; | ||
300 | + $oauthData['logintime'] = time(); | ||
301 | + $oauthData['createtime'] = time(); | ||
302 | + UserOauth::strict(false)->insert($oauthData); | ||
303 | + } | ||
304 | + break; | ||
305 | + } | ||
306 | + if ($this->auth->getUser()) { | ||
307 | + return $this->auth->getToken(); | ||
308 | + } | ||
309 | + return false; | ||
310 | + } | ||
311 | + | ||
312 | + | ||
313 | + /** | ||
314 | + * 手机验证码登录 | ||
315 | + * | ||
316 | + * @param string $mobile 手机号 | ||
317 | + * @param string $code 验证码 | ||
318 | + */ | ||
319 | + public function mobileLogin() | ||
320 | + { | ||
321 | + $mobile = $this->request->post('mobile'); | ||
322 | + $code = $this->request->post('code'); | ||
323 | + if (!$mobile || !$code) { | ||
324 | + $this->error(__('Invalid parameters')); | ||
325 | + } | ||
326 | + if (!Validate::regex($mobile, "^1\d{10}$")) { | ||
327 | + $this->error(__('Mobile is incorrect')); | ||
328 | + } | ||
329 | + if (!Sms::check($mobile, $code, 'mobilelogin')) { | ||
330 | + $this->error(__('Captcha is incorrect')); | ||
331 | + } | ||
332 | + $user = \app\common\model\User::getByMobile($mobile); | ||
333 | + if ($user) { | ||
334 | + if ($user->status != 'normal') { | ||
335 | + $this->error(__('Account is locked')); | ||
336 | + } | ||
337 | + //如果已经有账号则直接登录 | ||
338 | + $ret = $this->auth->direct($user->id); | ||
339 | + } | ||
340 | + if ($ret) { | ||
341 | + Sms::flush($mobile, 'mobilelogin'); | ||
342 | + $data = ['userinfo' => $this->auth->getUserinfo()]; | ||
343 | + $this->success(__('Logged in successful'), $data); | ||
344 | + } else { | ||
345 | + $this->error($this->auth->getError()); | ||
346 | + } | ||
347 | + } | ||
348 | + | ||
349 | + /** | ||
350 | + * 注册会员 | ||
351 | + * | ||
352 | + * @param string $username 用户名 | ||
353 | + * @param string $password 密码 | ||
354 | + * @param string $email 邮箱 | ||
355 | + * @param string $mobile 手机号 | ||
356 | + * @param string $code 验证码 | ||
357 | + */ | ||
358 | + public function register() | ||
359 | + { | ||
360 | + $username = $this->request->post('mobile'); | ||
361 | + $password = $this->request->post('password'); | ||
362 | + $email = $this->request->post('mobile') . '@' . request()->host(); | ||
363 | + | ||
364 | + $mobile = $this->request->post('mobile'); | ||
365 | + $code = $this->request->post('code'); | ||
366 | + if (!$password) { | ||
367 | + $this->error(__('请填写密码')); //TODO:密码规则校验 | ||
368 | + } | ||
369 | + if (strlen($password) < 6 || strlen($password) > 16) { | ||
370 | + $this->error(__('密码长度 6-16 位')); //TODO:密码规则校验 | ||
371 | + } | ||
372 | + if ($email && !Validate::is($email, "email")) { | ||
373 | + $this->error(__('邮箱填写错误')); | ||
374 | + } | ||
375 | + if ($mobile && !Validate::regex($mobile, "^1\d{10}$")) { | ||
376 | + $this->error(__('手机号填写错误')); | ||
377 | + } | ||
378 | + $ret = Sms::check($mobile, $code, 'register'); | ||
379 | + if (!$ret) { | ||
380 | + $this->error(__('Captcha is incorrect')); | ||
381 | + } | ||
382 | + $extend = $this->getUserDefaultFields(); | ||
383 | + $ret = $this->auth->register($username, $password, $email, $mobile, $extend); | ||
384 | + if ($ret) { | ||
385 | + $user = $this->auth->getUser(); | ||
386 | + $user->nickname = $user->nickname . $user->id; | ||
387 | + $user->save(); | ||
388 | + $data = ['userinfo' => $this->auth->getUserinfo()]; | ||
389 | + $this->success(__('注册成功'), $data); | ||
390 | + } else { | ||
391 | + $this->error($this->auth->getError()); | ||
392 | + } | ||
393 | + } | ||
394 | + | ||
395 | + /** | ||
396 | + * 注销登录 | ||
397 | + */ | ||
398 | + public function logout() | ||
399 | + { | ||
400 | + $this->auth->logout(); | ||
401 | + $this->success(__('Logout successful')); | ||
402 | + } | ||
403 | + | ||
404 | + /** | ||
405 | + * 修改会员个人信息 | ||
406 | + * | ||
407 | + * @param string $avatar 头像地址 | ||
408 | + * @param string $username 用户名 | ||
409 | + * @param string $nickname 昵称 | ||
410 | + * @param string $birthday 生日 | ||
411 | + * @param string $bio 个人简介 | ||
412 | + */ | ||
413 | + public function profile() | ||
414 | + { | ||
415 | + $user = $this->auth->getUser(); | ||
416 | + $username = $this->request->post('username'); | ||
417 | + $nickname = $this->request->post('nickname'); | ||
418 | + $bio = $this->request->post('bio', ''); | ||
419 | + $birthday = $this->request->post('birthday'); | ||
420 | + $avatar = $this->request->post('avatar', '', 'trim,strip_tags,htmlspecialchars'); | ||
421 | + if ($username) { | ||
422 | + $exists = \app\common\model\User::where('username', $username)->where('id', '<>', $this->auth->id)->find(); | ||
423 | + if ($exists) { | ||
424 | + $this->error(__('Username already exists')); | ||
425 | + } | ||
426 | + $user->username = $username; | ||
427 | + } | ||
428 | + $user->nickname = $nickname; | ||
429 | + $user->bio = $bio; | ||
430 | + $user->birthday = $birthday; | ||
431 | + $user->avatar = $avatar; | ||
432 | + $user->save(); | ||
433 | + $this->success(); | ||
434 | + } | ||
435 | + | ||
436 | + /** | ||
437 | + * 修改邮箱 | ||
438 | + * | ||
439 | + * @param string $email 邮箱 | ||
440 | + * @param string $captcha 验证码 | ||
441 | + */ | ||
442 | + public function changeemail() | ||
443 | + { | ||
444 | + $user = $this->auth->getUser(); | ||
445 | + $email = $this->request->post('email'); | ||
446 | + $captcha = $this->request->request('captcha'); | ||
447 | + if (!$email || !$captcha) { | ||
448 | + $this->error(__('Invalid parameters')); | ||
449 | + } | ||
450 | + if (!Validate::is($email, "email")) { | ||
451 | + $this->error(__('Email is incorrect')); | ||
452 | + } | ||
453 | + if (\app\common\model\User::where('email', $email)->where('id', '<>', $user->id)->find()) { | ||
454 | + $this->error(__('Email already exists')); | ||
455 | + } | ||
456 | + $result = Ems::check($email, $captcha, 'changeemail'); | ||
457 | + if (!$result) { | ||
458 | + $this->error(__('Captcha is incorrect')); | ||
459 | + } | ||
460 | + $verification = $user->verification; | ||
461 | + $verification->email = 1; | ||
462 | + $user->verification = $verification; | ||
463 | + $user->email = $email; | ||
464 | + $user->save(); | ||
465 | + | ||
466 | + Ems::flush($email, 'changeemail'); | ||
467 | + $this->success(); | ||
468 | + } | ||
469 | + | ||
470 | + /** | ||
471 | + * 修改手机号 | ||
472 | + * | ||
473 | + * @param string $mobile 手机号 | ||
474 | + * @param string $captcha 验证码 | ||
475 | + */ | ||
476 | + public function changemobile() | ||
477 | + { | ||
478 | + $user = $this->auth->getUser(); | ||
479 | + $mobile = $this->request->post('mobile'); | ||
480 | + $captcha = $this->request->post('captcha'); | ||
481 | + if (!$mobile || !$captcha) { | ||
482 | + $this->error(__('Invalid parameters')); | ||
483 | + } | ||
484 | + if (!Validate::regex($mobile, "^1\d{10}$")) { | ||
485 | + $this->error(__('Mobile is incorrect')); | ||
486 | + } | ||
487 | + if (\app\common\model\User::where('mobile', $mobile)->where('id', '<>', $user->id)->find()) { | ||
488 | + $this->error(__('Mobile already exists')); | ||
489 | + } | ||
490 | + $result = Sms::check($mobile, $captcha, 'changemobile'); | ||
491 | + if (!$result) { | ||
492 | + $this->error(__('Captcha is incorrect')); | ||
493 | + } | ||
494 | + $verification = $user->verification; | ||
495 | + $verification->mobile = 1; | ||
496 | + $user->verification = $verification; | ||
497 | + $user->mobile = $mobile; | ||
498 | + $user->save(); | ||
499 | + | ||
500 | + Sms::flush($mobile, 'changemobile'); | ||
501 | + $this->success(); | ||
502 | + } | ||
503 | + | ||
504 | + | ||
505 | + /** | ||
506 | + * 重置密码 | ||
507 | + * | ||
508 | + * @param string $mobile 手机号 | ||
509 | + * @param string $newpassword 新密码 | ||
510 | + * @param string $captcha 验证码 | ||
511 | + */ | ||
512 | + public function resetpwd() | ||
513 | + { | ||
514 | + $type = $this->request->post("type", 'mobile'); | ||
515 | + $mobile = $this->request->post("mobile"); | ||
516 | + $email = $this->request->post("email"); | ||
517 | + $newpassword = $this->request->post("newpassword"); | ||
518 | + $captcha = $this->request->post("captcha"); | ||
519 | + if (!$newpassword || !$captcha) { | ||
520 | + $this->error(__('Invalid parameters')); | ||
521 | + } | ||
522 | + if (strlen($newpassword) < 6 || strlen($newpassword) > 16) { | ||
523 | + $this->error(__('密码长度 6-16 位')); //TODO:密码规则校验 | ||
524 | + } | ||
525 | + if ($type == 'mobile') { | ||
526 | + if (!Validate::regex($mobile, "^1\d{10}$")) { | ||
527 | + $this->error(__('Mobile is incorrect')); | ||
528 | + } | ||
529 | + $user = \app\common\model\User::getByMobile($mobile); | ||
530 | + if (!$user) { | ||
531 | + $this->error(__('User not found')); | ||
532 | + } | ||
533 | + $ret = Sms::check($mobile, $captcha, 'resetpwd'); | ||
534 | + if (!$ret) { | ||
535 | + $this->error(__('Captcha is incorrect')); | ||
536 | + } | ||
537 | + Sms::flush($mobile, 'resetpwd'); | ||
538 | + } else { | ||
539 | + if (!Validate::is($email, "email")) { | ||
540 | + $this->error(__('Email is incorrect')); | ||
541 | + } | ||
542 | + $user = \app\common\model\User::getByEmail($email); | ||
543 | + if (!$user) { | ||
544 | + $this->error(__('User not found')); | ||
545 | + } | ||
546 | + $ret = Ems::check($email, $captcha, 'resetpwd'); | ||
547 | + if (!$ret) { | ||
548 | + $this->error(__('Captcha is incorrect')); | ||
549 | + } | ||
550 | + Ems::flush($email, 'resetpwd'); | ||
551 | + } | ||
552 | + //模拟一次登录 | ||
553 | + $this->auth->direct($user->id); | ||
554 | + $ret = $this->auth->changepwd($newpassword, '', true); | ||
555 | + if ($ret) { | ||
556 | + $this->success(__('Reset password successful')); | ||
557 | + } else { | ||
558 | + $this->error($this->auth->getError()); | ||
559 | + } | ||
560 | + } | ||
561 | + | ||
562 | + | ||
563 | + public function changepwd() | ||
564 | + { | ||
565 | + $user = $this->auth->getUser(); | ||
566 | + | ||
567 | + $oldpassword = $this->request->post("oldpassword"); | ||
568 | + $newpassword = $this->request->post("newpassword"); | ||
569 | + | ||
570 | + if (!$newpassword || !$oldpassword) { | ||
571 | + $this->error(__('Invalid parameters')); | ||
572 | + } | ||
573 | + if (strlen($newpassword) < 6 || strlen($newpassword) > 16) { | ||
574 | + $this->error(__('密码长度 6-16 位')); //TODO:密码规则校验 | ||
575 | + } | ||
576 | + | ||
577 | + $ret = $this->auth->changepwd($newpassword, $oldpassword); | ||
578 | + | ||
579 | + if ($ret) { | ||
580 | + $this->auth->direct($user->id); | ||
581 | + $data = ['userinfo' => $this->auth->getUserinfo()]; | ||
582 | + | ||
583 | + $this->success(__('Change password successful'), $data); | ||
584 | + } else { | ||
585 | + $this->error($this->auth->getError()); | ||
586 | + } | ||
587 | + } | ||
588 | + | ||
589 | + private function getUserDefaultFields() | ||
590 | + { | ||
591 | + $userConfig = json_decode(\addons\groupon\model\Config::get(['name' => 'user'])->value, true); | ||
592 | + return $userConfig; | ||
593 | + } | ||
594 | +} |
addons/groupon/controller/UserBank.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class UserBank extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = []; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + | ||
13 | + public function info() | ||
14 | + { | ||
15 | + $type = $this->request->get('type'); | ||
16 | + | ||
17 | + $bankInfo = \addons\groupon\model\UserBank::info($type); | ||
18 | + | ||
19 | + $this->success('提现账户', $bankInfo); | ||
20 | + } | ||
21 | + | ||
22 | + | ||
23 | + public function edit () { | ||
24 | + $params = $this->request->post(); | ||
25 | + if ($params['type'] === 'alipay') { | ||
26 | + $params['bank_name'] = '支付宝账户'; | ||
27 | + } | ||
28 | + | ||
29 | + // 表单验证 | ||
30 | + $this->grouponValidate($params, get_class(), 'edit'); | ||
31 | + | ||
32 | + $this->success('编辑成功', \addons\groupon\model\UserBank::edit($params)); | ||
33 | + } | ||
34 | + | ||
35 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | + | ||
6 | +class UserWalletApply extends Base | ||
7 | +{ | ||
8 | + | ||
9 | + protected $noNeedLogin = ['rule']; | ||
10 | + protected $noNeedRight = ['*']; | ||
11 | + | ||
12 | + | ||
13 | + public function index() | ||
14 | + { | ||
15 | + $this->success('提现记录', \addons\groupon\model\UserWalletApply::getList()); | ||
16 | + } | ||
17 | + | ||
18 | + | ||
19 | + public function apply () { | ||
20 | + repeat_filter(); // 防抖 | ||
21 | + $type = $this->request->post('type'); | ||
22 | + $money = $this->request->post('money'); | ||
23 | + | ||
24 | + $apply = \addons\groupon\model\UserWalletApply::apply($type, $money); | ||
25 | + | ||
26 | + if ($apply) { | ||
27 | + $this->success('申请成功'); | ||
28 | + } | ||
29 | + $this->error('申请失败'); | ||
30 | + } | ||
31 | + | ||
32 | + | ||
33 | + public function rule () { | ||
34 | + // 提现规则 | ||
35 | + $config = \addons\groupon\model\UserWalletApply::getWithdrawConfig(); | ||
36 | + $min = round(floatval($config['min']), 2); | ||
37 | + $max = round(floatval($config['max']), 2); | ||
38 | + $service_fee = floatval($config['service_fee']) * 100; | ||
39 | + $service_fee = round($service_fee, 1); // 1 位小数 | ||
40 | + | ||
41 | + $rule = [ | ||
42 | + 'min' => $min, | ||
43 | + 'max' => $max, | ||
44 | + 'service_fee' => $service_fee, | ||
45 | + 'methods' => $config['methods'] ?? [] | ||
46 | + ]; | ||
47 | + | ||
48 | + $this->success('提现规则', $rule); | ||
49 | + } | ||
50 | + | ||
51 | +} |
addons/groupon/controller/UserWalletLog.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | + | ||
7 | +class UserWalletLog extends Base | ||
8 | +{ | ||
9 | + | ||
10 | + protected $noNeedLogin = ['*']; | ||
11 | + protected $noNeedRight = ['*']; | ||
12 | + | ||
13 | + | ||
14 | + public function index() | ||
15 | + { | ||
16 | + $params = $this->request->get(); | ||
17 | + $wallet_type = $params['wallet_type'] ?? 'money'; | ||
18 | + | ||
19 | + if (!in_array($wallet_type, ['money', 'score'])) { | ||
20 | + $this->error('参数错误'); | ||
21 | + } | ||
22 | + | ||
23 | + $this->success(($wallet_type == 'money' ? '钱包记录' : '积分记录'), \addons\groupon\model\UserWalletLog::getList($params)); | ||
24 | + } | ||
25 | + | ||
26 | +} |
addons/groupon/controller/Wechat.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller; | ||
4 | + | ||
5 | +use addons\groupon\library\Wechat as WechatLibrary; | ||
6 | +use addons\groupon\model\Wechat as WechatModel; | ||
7 | +use addons\groupon\model\Config; | ||
8 | + | ||
9 | +/** | ||
10 | + * 微信接口 | ||
11 | + */ | ||
12 | +class Wechat extends Base | ||
13 | +{ | ||
14 | + protected $noNeedLogin = ['*']; | ||
15 | + protected $noNeedRight = ['*']; | ||
16 | + protected $app = null; | ||
17 | + protected $userOpenId = ''; | ||
18 | + /** | ||
19 | + * 微信公众号服务端API对接、处理消息回复 | ||
20 | + */ | ||
21 | + public function index() | ||
22 | + { | ||
23 | + $wechat = new WechatLibrary('wxOfficialAccount'); | ||
24 | + $this->app = $wechat->getApp(); | ||
25 | + $this->app->server->push(function ($message) { | ||
26 | + //初始化信息 | ||
27 | + $this->userOpenId = $message['FromUserName']; | ||
28 | + // return json_encode($message, JSON_UNESCAPED_UNICODE); //调试使用 | ||
29 | + | ||
30 | + switch ($message['MsgType']) { | ||
31 | + case 'event': //收到事件消息 | ||
32 | + switch ($message['Event']) { | ||
33 | + case 'subscribe': //订阅(关注)事件 | ||
34 | + //获取粉丝信息并保存 | ||
35 | + $subscribe = WechatModel::get(['type' => 'subscribe']); | ||
36 | + if ($subscribe) { | ||
37 | + return $this->response($subscribe); | ||
38 | + } | ||
39 | + break; | ||
40 | + case 'unsubscribe': //取消订阅(关注)事件 | ||
41 | + //获取粉丝信息并保存 | ||
42 | + break; | ||
43 | + case 'CLICK': //自定义菜单事件 | ||
44 | + return $this->response($message, 'CLICK'); | ||
45 | + break; | ||
46 | + case 'SCAN': //扫码事件 | ||
47 | + return ''; | ||
48 | + break; | ||
49 | + } | ||
50 | + break; | ||
51 | + case 'text': //收到文本消息 | ||
52 | + //检测关键字回复 | ||
53 | + $content = $message['Content']; | ||
54 | + $auto_reply = WechatModel::where('type', 'auto_reply')->where('find_in_set(:keywords,rules)', ['keywords' => $content])->find(); | ||
55 | + if ($auto_reply) { | ||
56 | + return $this->response($auto_reply); | ||
57 | + } | ||
58 | + case 'image': //收到图片消息 | ||
59 | + case 'voice': //收到语音消息 | ||
60 | + case 'video': //收到视频消息 | ||
61 | + case 'location': //收到坐标消息 | ||
62 | + case 'link': //收到链接消息 | ||
63 | + case 'file': //收到文件消息 | ||
64 | + default: // ... 默认回复消息 | ||
65 | + $default_reply = WechatModel::where('type', 'default_reply')->find(); | ||
66 | + if ($default_reply) { | ||
67 | + return $this->response($default_reply); | ||
68 | + } | ||
69 | + } | ||
70 | + }); | ||
71 | + $response = $this->app->server->serve(); | ||
72 | + // 将响应输出 | ||
73 | + $response->send(); | ||
74 | + } | ||
75 | + | ||
76 | + public function jssdk() | ||
77 | + { | ||
78 | + $params = $this->request->post(); | ||
79 | + $apis = [ | ||
80 | + 'checkJsApi', | ||
81 | + 'onMenuShareTimeline', | ||
82 | + 'onMenuShareAppMessage', | ||
83 | + 'getLocation', //获取位置 | ||
84 | + 'openLocation', //打开位置 | ||
85 | + 'scanQRCode', //扫一扫接口 | ||
86 | + 'chooseWXPay', //微信支付 | ||
87 | + 'chooseImage', //拍照或从手机相册中选图接口 | ||
88 | + 'previewImage', //预览图片接口 | ||
89 | + 'uploadImage', //上传图片 | ||
90 | + 'openAddress', // 获取微信地址 | ||
91 | + ]; | ||
92 | + $uri = urldecode($params['uri']); | ||
93 | + | ||
94 | + $wechat = new WechatLibrary('wxOfficialAccount'); | ||
95 | + $res = $wechat->getApp()->jssdk->setUrl($uri)->buildConfig($apis, $debug = false, $beta = false, $json = false); | ||
96 | + $this->success('sdk', $res); | ||
97 | + } | ||
98 | + | ||
99 | + /** | ||
100 | + * 微信公众号服务端API对接 | ||
101 | + */ | ||
102 | + public function wxacode() | ||
103 | + { | ||
104 | + $scene = $this->request->get('scene', ''); | ||
105 | + $path = $this->request->get('path', ''); | ||
106 | + | ||
107 | + if (empty($path)) { | ||
108 | + $path = 'pages/index/index'; | ||
109 | + } | ||
110 | + | ||
111 | + $wechat = new WechatLibrary('wxMiniProgram'); | ||
112 | + $content = $wechat->getApp()->app_code->getUnlimit($scene, [ | ||
113 | + 'page' => $path, | ||
114 | + 'is_hyaline' => true, | ||
115 | + ]); | ||
116 | + | ||
117 | + if ($content instanceof \EasyWeChat\Kernel\Http\StreamResponse) { | ||
118 | + return response($content->getBody(), 200, ['Content-Length' => strlen($content)])->contentType('image/png'); | ||
119 | + } else { | ||
120 | + // 小程序码获取失败 | ||
121 | + $msg = isset($content['errcode']) ? $content['errcode'] : '-'; | ||
122 | + $msg .= isset($content['errmsg']) ? $content['errmsg'] : ''; | ||
123 | + \think\Log::write('wxacode-error' . $msg); | ||
124 | + | ||
125 | + $this->error('获取失败', $msg); | ||
126 | + } | ||
127 | + } | ||
128 | + | ||
129 | + /** | ||
130 | + * 回复消息 | ||
131 | + */ | ||
132 | + private function response($replyInfo, $event = 'text') | ||
133 | + { | ||
134 | + switch ($event) { | ||
135 | + case 'SCAN': //解析扫码事件EventKey | ||
136 | + break; | ||
137 | + case 'CLICK': //解析菜单点击事件EventKey | ||
138 | + $key = explode('|', $replyInfo['EventKey']); | ||
139 | + if ($key) { | ||
140 | + $message['type'] = $key[0]; | ||
141 | + if ($key[0] === 'text') { | ||
142 | + $message['content'] = json_decode(WechatModel::get($key[1])->content, true); | ||
143 | + } elseif($key[0] === 'link') { | ||
144 | + $link = WechatModel::get($key[1]); | ||
145 | + $message = array_merge($message, json_decode($link->content, true)); | ||
146 | + $message['title'] = $link->name; | ||
147 | + // return json_encode($message); | ||
148 | + }else { | ||
149 | + $message['media_id'] = $key[1]; | ||
150 | + } | ||
151 | + } | ||
152 | + break; | ||
153 | + default: | ||
154 | + $message = json_decode($replyInfo['content'], true); | ||
155 | + break; | ||
156 | + } | ||
157 | + | ||
158 | + switch ($message['type']) { | ||
159 | + case 'text': //回复文本 | ||
160 | + $content = new \EasyWeChat\Kernel\Messages\Text($message['content']); | ||
161 | + break; | ||
162 | + case 'image': //回复图片 | ||
163 | + $content = new \EasyWeChat\Kernel\Messages\Image($message['media_id']); | ||
164 | + break; | ||
165 | + case 'news': //回复图文 | ||
166 | + $message = new \EasyWeChat\Kernel\Messages\Media($message['media_id'], 'mpnews'); | ||
167 | + $this->app->customer_service->message($message)->to($this->userOpenId)->send(); //素材消息使用客服接口回复 | ||
168 | + break; | ||
169 | + case 'voice': //回复语音 | ||
170 | + $content = new \EasyWeChat\Kernel\Messages\Voice($message['media_id']); | ||
171 | + break; | ||
172 | + case 'video': //回复视频 | ||
173 | + $content = new \EasyWeChat\Kernel\Messages\Video($message['media_id']); | ||
174 | + break; | ||
175 | + case 'link': //回复链接 | ||
176 | + $items = new \EasyWeChat\Kernel\Messages\NewsItem([ | ||
177 | + 'title' => $message['title'], | ||
178 | + 'description' => $message['description'], | ||
179 | + 'url' => $message['url'], | ||
180 | + 'image' => cdnurl($message['image'], true), | ||
181 | + // ... | ||
182 | + ]); | ||
183 | + $content = new \EasyWeChat\Kernel\Messages\News([$items]); | ||
184 | + break; | ||
185 | + } | ||
186 | + return $content; | ||
187 | + } | ||
188 | +} |
addons/groupon/controller/store/Apply.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller\store; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\controller\Base as GrouponBase; | ||
7 | + | ||
8 | +/** | ||
9 | + * 不继承门店的 base | ||
10 | + */ | ||
11 | +class Apply extends GrouponBase | ||
12 | +{ | ||
13 | + | ||
14 | + protected $noNeedLogin = []; | ||
15 | + protected $noNeedRight = ['*']; | ||
16 | + | ||
17 | + | ||
18 | + public function info() { | ||
19 | + $config = new \addons\groupon\model\Config; | ||
20 | + | ||
21 | + $storeConfig = json_decode($config->where(['name' => 'store'])->value('value'), true); | ||
22 | + $storeConfig['intro_image'] = (isset($storeConfig['intro_image']) && $storeConfig['intro_image']) ? cdnurl($storeConfig['intro_image'], true) : ''; | ||
23 | + | ||
24 | + $this->success('自提点申请', [ | ||
25 | + 'apply' => \addons\groupon\model\store\Apply::info(), | ||
26 | + 'config' => $storeConfig | ||
27 | + ]); | ||
28 | + } | ||
29 | + | ||
30 | + | ||
31 | + public function apply() { | ||
32 | + $params = $this->request->post(); | ||
33 | + | ||
34 | + // 表单验证 | ||
35 | + $this->grouponValidate($params, get_class(), 'apply'); | ||
36 | + | ||
37 | + $order = \addons\groupon\model\store\Apply::apply($params); | ||
38 | + | ||
39 | + $this->success('自提点申请提交成功', $order); | ||
40 | + } | ||
41 | + | ||
42 | +} |
addons/groupon/controller/store/Base.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller\store; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\controller\Base as AddonsBase; | ||
7 | +use addons\groupon\model\Store; | ||
8 | +use addons\groupon\model\User; | ||
9 | +use addons\groupon\model\UserStore; | ||
10 | + | ||
11 | +class Base extends AddonsBase | ||
12 | +{ | ||
13 | + public function _initialize() | ||
14 | + { | ||
15 | + parent::_initialize(); | ||
16 | + | ||
17 | + // 验证登录用户是否可以访问门店接口 | ||
18 | + $this->checkUserStore(); | ||
19 | + } | ||
20 | + | ||
21 | + | ||
22 | + /** | ||
23 | + * 检测用户管理的是否有门店 | ||
24 | + */ | ||
25 | + private function checkUserStore() { | ||
26 | + // 获取当前用户的门店 | ||
27 | + $user = User::info(); | ||
28 | + $store_id = $this->request->param('store_id'); | ||
29 | + | ||
30 | + if (!$store_id) { | ||
31 | + $this->error('请选择自提点'); | ||
32 | + } | ||
33 | + | ||
34 | + $userStore = UserStore::with('store')->where('user_id', $user->id)->where('store_id', $store_id)->find(); | ||
35 | + if (!$userStore || !$userStore->store) { | ||
36 | + $this->error('权限不足'); | ||
37 | + } | ||
38 | + | ||
39 | + $store = $userStore->store->toArray(); | ||
40 | + | ||
41 | + if (!$store['status']) { | ||
42 | + $this->error('自提点已被禁用'); | ||
43 | + } | ||
44 | + | ||
45 | + // 存 session 本次请求有效 | ||
46 | + session('current_oper_store', $store); | ||
47 | + } | ||
48 | +} |
addons/groupon/controller/store/Order.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller\store; | ||
4 | + | ||
5 | +class Order extends Base | ||
6 | +{ | ||
7 | + | ||
8 | + protected $noNeedLogin = []; | ||
9 | + protected $noNeedRight = ['*']; | ||
10 | + | ||
11 | + | ||
12 | + public function index() | ||
13 | + { | ||
14 | + $params = $this->request->get(); | ||
15 | + | ||
16 | + $this->success('订单列表', \addons\groupon\model\store\Order::getList($params)); | ||
17 | + } | ||
18 | + | ||
19 | + | ||
20 | + | ||
21 | + public function detail() | ||
22 | + { | ||
23 | + $params = $this->request->get(); | ||
24 | + $this->success('订单详情', \addons\groupon\model\store\Order::detail($params)); | ||
25 | + } | ||
26 | + | ||
27 | + | ||
28 | + | ||
29 | + public function confirm() | ||
30 | + { | ||
31 | + repeat_filter(); // 防抖 | ||
32 | + $params = $this->request->post(); | ||
33 | + $this->success('核销成功', \addons\groupon\model\store\Order::operConfirm($params)); | ||
34 | + } | ||
35 | +} |
addons/groupon/controller/store/Store.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller\store; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\model\Store as ModelStore; | ||
7 | + | ||
8 | +class Store extends Base | ||
9 | +{ | ||
10 | + | ||
11 | + protected $noNeedLogin = []; | ||
12 | + protected $noNeedRight = ['*']; | ||
13 | + | ||
14 | + | ||
15 | + public function index() | ||
16 | + { | ||
17 | + $params = $this->request->get(); | ||
18 | + $store = ModelStore::info(); | ||
19 | + if (!$store) { | ||
20 | + $this->error('门店不存在'); | ||
21 | + } | ||
22 | + | ||
23 | + $this->success('获取成功', $store); | ||
24 | + } | ||
25 | + | ||
26 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\controller\store; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use addons\groupon\library\traits\export\ExportOrder; | ||
7 | +/** | ||
8 | + * 门店包裹 | ||
9 | + */ | ||
10 | +class StoreExpress extends Base | ||
11 | +{ | ||
12 | + use ExportOrder; | ||
13 | + | ||
14 | + protected $noNeedLogin = []; | ||
15 | + protected $noNeedRight = ['*']; | ||
16 | + | ||
17 | + | ||
18 | + public function index() { | ||
19 | + $params = $this->request->get(); | ||
20 | + | ||
21 | + $this->success('包裹列表', \addons\groupon\model\store\StoreExpress::getList($params)); | ||
22 | + } | ||
23 | + | ||
24 | + | ||
25 | + public function detail() { | ||
26 | + $params = $this->request->get(); | ||
27 | + | ||
28 | + $this->success('包裹详情', \addons\groupon\model\store\StoreExpress::getDetail($params)); | ||
29 | + } | ||
30 | + | ||
31 | + | ||
32 | + /** | ||
33 | + * 包裹到货 | ||
34 | + * | ||
35 | + * @return void | ||
36 | + */ | ||
37 | + public function arrive() | ||
38 | + { | ||
39 | + $params = $this->request->post(); | ||
40 | + $this->success('到货成功', \addons\groupon\model\store\StoreExpress::operArrive($params)); | ||
41 | + } | ||
42 | + | ||
43 | + | ||
44 | + public function export() { | ||
45 | + $params = $this->request->get(); | ||
46 | + $id = $params['id'] ?? 0; | ||
47 | + | ||
48 | + $orderStoreExpress = \app\admin\model\groupon\order\OrderStoreExpress::with(['store'])->where('id', $id)->find(); | ||
49 | + | ||
50 | + if (!$orderStoreExpress) { | ||
51 | + $this->error('包裹未找到'); | ||
52 | + } | ||
53 | + | ||
54 | + $this->exportOutput($orderStoreExpress); | ||
55 | + } | ||
56 | +} |
addons/groupon/exception/Exception.php
0 → 100644
1 | +<?php | ||
2 | +namespace addons\groupon\exception; | ||
3 | + | ||
4 | +use think\Response; | ||
5 | + | ||
6 | +class Exception | ||
7 | +{ | ||
8 | + protected $msg = '错误消息'; | ||
9 | + protected $code = 0; //TOAST自动弹出消息 | ||
10 | + const NOT_LOGIN = 401; //未登录自动弹框提醒 | ||
11 | + const NOT_AUTHORIZE = 403;// | ||
12 | + const IGNORE = -1; | ||
13 | + public function __construct($msg, $code = 0, $status_code = 200) | ||
14 | + { | ||
15 | + $this->msg = $msg; | ||
16 | + $this->code = $code; | ||
17 | + $this->send($status_code); | ||
18 | + } | ||
19 | + protected function send($code = 200) | ||
20 | + { | ||
21 | + $data = [ | ||
22 | + 'code' => $this->code, | ||
23 | + 'msg' => $this->msg, | ||
24 | + 'data' => null, | ||
25 | + 'time' => time() | ||
26 | + ]; | ||
27 | + $response = Response::create($data, 'json', $code); | ||
28 | + throw new \think\exception\HttpResponseException($response); | ||
29 | + } | ||
30 | +} |
addons/groupon/helper.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +if (!function_exists('matchLatLng')) { | ||
4 | + function matchLatLng($latlng) { | ||
5 | + $match = "/^\d{1,3}\.\d{1,30}$/"; | ||
6 | + return preg_match($match, $latlng) ? $latlng : 0; | ||
7 | + } | ||
8 | +} | ||
9 | + | ||
10 | + | ||
11 | +if (!function_exists('getDistanceBuilder')) { | ||
12 | + function getDistanceBuilder($lat, $lng) { | ||
13 | + return "ROUND(6378.138 * 2 * ASIN(SQRT(POW(SIN((". matchLatLng($lat) . " * PI() / 180 - latitude * PI() / 180) / 2), 2) + COS(". matchLatLng($lat). " * PI() / 180) * COS(latitude * PI() / 180) * POW(SIN((". matchLatLng($lng). " * PI() / 180 - longitude * PI() / 180) / 2), 2))) * 1000) AS distance"; | ||
14 | + } | ||
15 | +} | ||
16 | + | ||
17 | + | ||
18 | +/** | ||
19 | + * 下划线转驼峰 | ||
20 | + * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符 | ||
21 | + * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符. | ||
22 | + */ | ||
23 | +if (!function_exists('camelize')) { | ||
24 | + function camelize($uncamelized_words, $separator = '_') { | ||
25 | + $uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words)); | ||
26 | + return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator); | ||
27 | + } | ||
28 | +} | ||
29 | + | ||
30 | +/** | ||
31 | + * 驼峰命名转下划线命名 | ||
32 | + * 思路: | ||
33 | + * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写 | ||
34 | + */ | ||
35 | +if (!function_exists('uncamelize')) { | ||
36 | + function uncamelize($camelCaps, $separator='_') | ||
37 | + { | ||
38 | + return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps)); | ||
39 | + } | ||
40 | +} | ||
41 | + | ||
42 | + | ||
43 | +/** | ||
44 | + * 检测系统必要环境 | ||
45 | + */ | ||
46 | +if (!function_exists('checkEnv')) { | ||
47 | + function checkEnv($need = [], $is_throw = true) | ||
48 | + { | ||
49 | + $need = is_string($need) ? [$need] : $need; | ||
50 | + | ||
51 | + // 检测是否安装浮点数运算扩展 | ||
52 | + if (in_array('bcmath', $need)) { | ||
53 | + if (!extension_loaded('bcmath')) { | ||
54 | + if ($is_throw) { | ||
55 | + new \addons\groupon\exception\Exception('请安装浮点数扩展 bcmath'); | ||
56 | + } else { | ||
57 | + return false; | ||
58 | + } | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + // 检测是否安装了队列 | ||
63 | + if (in_array('queue', $need)) { | ||
64 | + if (!class_exists(\think\Queue::class)) { | ||
65 | + if ($is_throw) { | ||
66 | + new \addons\groupon\exception\Exception('请安装 topthink/think-queue:v1.1.6 队列扩展'); | ||
67 | + } else { | ||
68 | + return false; | ||
69 | + } | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + if (in_array('yansongda', $need)) { | ||
74 | + if (!class_exists(\Yansongda\Pay\Pay::class)) { | ||
75 | + if ($is_throw) { | ||
76 | + new \addons\groupon\exception\Exception('请查看文档,配置支付'); | ||
77 | + } else { | ||
78 | + return false; | ||
79 | + } | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | + return true; | ||
84 | + } | ||
85 | +} | ||
86 | + | ||
87 | + | ||
88 | +/** | ||
89 | + * 后端防抖 | ||
90 | + */ | ||
91 | +if (!function_exists('repeat_filter')) { | ||
92 | + function repeat_filter($key = null, $expire = 5) | ||
93 | + { | ||
94 | + if (!$key) { | ||
95 | + $url = request()->baseUrl(); | ||
96 | + $ip = request()->ip(); | ||
97 | + | ||
98 | + $key = md5($url . ':' . $ip); | ||
99 | + } | ||
100 | + | ||
101 | + $hasRedis = config('redis'); | ||
102 | + if ($hasRedis) { | ||
103 | + $redis = (new \addons\groupon\library\Redis())->getRedis(); | ||
104 | + if ($redis->exists($key)) { | ||
105 | + throw new \addons\groupon\exception\Exception('请不要重复提交'); | ||
106 | + } | ||
107 | + $redis->setex($key, $expire, time()); // 缓存 五秒 | ||
108 | + } else { | ||
109 | + if (cache('?' . $key)) { | ||
110 | + throw new \addons\groupon\exception\Exception('请不要重复提交'); | ||
111 | + } | ||
112 | + cache($key, time(), $expire); | ||
113 | + } | ||
114 | + } | ||
115 | +} | ||
116 | + | ||
117 | +/** | ||
118 | + * 返回配置的微信支付版本 | ||
119 | + */ | ||
120 | +if (!function_exists('pay_version')) { | ||
121 | + function pay_version() | ||
122 | + { | ||
123 | + $version = config('pay_version'); | ||
124 | + | ||
125 | + $version = $version ? strtolower($version) : 'v2'; | ||
126 | + | ||
127 | + return $version; | ||
128 | + } | ||
129 | +} | ||
130 | + | ||
131 | + | ||
132 | + | ||
133 | +/** | ||
134 | + * 过滤掉字符串中的 sql 关键字 | ||
135 | + */ | ||
136 | +if (!function_exists('filter_sql')) { | ||
137 | + function filter_sql($str) | ||
138 | + { | ||
139 | + $str = strtolower($str); // 转小写 | ||
140 | + $str = str_replace("and", "", $str); | ||
141 | + $str = str_replace("execute", "", $str); | ||
142 | + $str = str_replace("update", "", $str); | ||
143 | + $str = str_replace("count", "", $str); | ||
144 | + $str = str_replace("chr", "", $str); | ||
145 | + $str = str_replace("mid", "", $str); | ||
146 | + $str = str_replace("master", "", $str); | ||
147 | + $str = str_replace("truncate", "", $str); | ||
148 | + $str = str_replace("char", "", $str); | ||
149 | + $str = str_replace("declare", "", $str); | ||
150 | + $str = str_replace("select", "", $str); | ||
151 | + $str = str_replace("create", "", $str); | ||
152 | + $str = str_replace("delete", "", $str); | ||
153 | + $str = str_replace("insert", "", $str); | ||
154 | + $str = str_replace("union", "", $str); | ||
155 | + $str = str_replace("alter", "", $str); | ||
156 | + $str = str_replace("into", "", $str); | ||
157 | + $str = str_replace("'", "", $str); | ||
158 | + $str = str_replace("or", "", $str); | ||
159 | + $str = str_replace("=", "", $str); | ||
160 | + | ||
161 | + return $str; | ||
162 | + } | ||
163 | +} |
addons/groupon/hooks.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +$defaultHooks = [ | ||
4 | + // 订单创建 | ||
5 | + 'groupon_order_create_before' => [ // 订单创建前 | ||
6 | + 'addons\\groupon\\listener\\order\\Create' | ||
7 | + ], | ||
8 | + 'groupon_order_create_after' => [ // 订单创建后 | ||
9 | + 'addons\\groupon\\listener\\order\\Create' | ||
10 | + ], | ||
11 | + 'groupon_order_payed_after' => [ // 订单支付成功 | ||
12 | + 'addons\\groupon\\listener\\order\\Payed', | ||
13 | + 'addons\\groupon\\listener\\store\\Take', | ||
14 | + 'addons\\groupon\\listener\\order\\Coupon', | ||
15 | + ], | ||
16 | + | ||
17 | + // 订单关闭 | ||
18 | + 'groupon_order_close_before' => [ // 订单关闭前 | ||
19 | + ], | ||
20 | + 'groupon_order_close_after' => [ // 订单关闭后 | ||
21 | + 'addons\\groupon\\listener\\order\\Invalid' | ||
22 | + ], | ||
23 | + | ||
24 | + // 订单取消 | ||
25 | + 'groupon_order_cancel_before' => [ // 订单取消前 | ||
26 | + ], | ||
27 | + 'groupon_order_cancel_after' => [ // 订单取消后 | ||
28 | + 'addons\\groupon\\listener\\order\\Invalid' | ||
29 | + ], | ||
30 | + | ||
31 | + // 订单备货 | ||
32 | + 'groupon_order_send_before' => [ | ||
33 | + ], | ||
34 | + // 订单备货 | ||
35 | + 'groupon_order_send_after' => [ | ||
36 | + 'addons\\groupon\\listener\\order\\Send' | ||
37 | + ], | ||
38 | + | ||
39 | + // 订单到货 | ||
40 | + 'groupon_order_arrive_before' => [], | ||
41 | + // 订单备货 | ||
42 | + 'groupon_order_arrive_after' => [ | ||
43 | + 'addons\\groupon\\listener\\order\\Send' | ||
44 | + ], | ||
45 | + | ||
46 | + // 订单确认收货 | ||
47 | + 'groupon_order_confirm_before' => [ // 订单确认收货前 | ||
48 | + ], | ||
49 | + 'groupon_order_confirm_after' => [ // 订单确认收货后 | ||
50 | + 'addons\\groupon\\listener\\order\\Confirm', | ||
51 | + 'addons\\groupon\\listener\\store\\Take' | ||
52 | + ], | ||
53 | + 'groupon_order_confirm_finish' => [ // 订单确认收货完成 | ||
54 | + 'addons\\groupon\\listener\\order\\Coupon', | ||
55 | + ], | ||
56 | + | ||
57 | + // 订单完成事件 | ||
58 | + 'groupon_order_finish' => [ | ||
59 | + 'addons\\groupon\\listener\\store\\Take', | ||
60 | + 'addons\\groupon\\listener\\order\\Coupon', | ||
61 | + ], | ||
62 | + | ||
63 | + // 订单评价 | ||
64 | + 'groupon_order_comment_before' => [ // 订单评价前 | ||
65 | + ], | ||
66 | + 'groupon_order_comment_after' => [ // 订单评价后 | ||
67 | + 'addons\\groupon\\listener\\order\\Comment' | ||
68 | + ], | ||
69 | + | ||
70 | + // 订单退款 | ||
71 | + 'groupon_order_refund_before' => [ // 订单退款前 | ||
72 | + 'addons\\groupon\\listener\\order\\Refund' | ||
73 | + ], | ||
74 | + 'groupon_order_refund_after' => [ // 订单退款后 | ||
75 | + 'addons\\groupon\\listener\\order\\Refund', | ||
76 | + 'addons\\groupon\\listener\\store\\Take' | ||
77 | + ], | ||
78 | + | ||
79 | + // 活动更新 | ||
80 | + 'groupon_activity_update_after' => [ // 活动更新后 | ||
81 | + 'addons\\groupon\\listener\\activity\\Update' | ||
82 | + ], | ||
83 | + 'groupon_activity_delete_after' => [ // 活动删除之后 | ||
84 | + 'addons\\groupon\\listener\\activity\\Update' | ||
85 | + ], | ||
86 | + | ||
87 | +]; | ||
88 | + | ||
89 | +return $defaultHooks; |
addons/groupon/info.ini
0 → 100644
addons/groupon/install.sql
0 → 100644
此 diff 太大无法显示。
addons/groupon/job/ActivityAutoOper.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\job; | ||
4 | + | ||
5 | +use addons\groupon\library\traits\ActivityCache; | ||
6 | +use addons\groupon\model\Activity; | ||
7 | +use think\queue\Job; | ||
8 | + | ||
9 | + | ||
10 | +/** | ||
11 | + * 订单自动操作 | ||
12 | + */ | ||
13 | +class ActivityAutoOper extends BaseJob | ||
14 | +{ | ||
15 | + use ActivityCache; | ||
16 | + | ||
17 | + /** | ||
18 | + * 活动自动删除 | ||
19 | + */ | ||
20 | + public function autoClose(Job $job, $data){ | ||
21 | + try { | ||
22 | + $activity = $data['activity']; | ||
23 | + | ||
24 | + $activity = Activity::get($activity['id']); | ||
25 | + | ||
26 | + // 一个活动会存在多个队列,要排重 | ||
27 | + if ($activity) { | ||
28 | + // 如果活动还没被删除 | ||
29 | + | ||
30 | + // 规则 | ||
31 | + $rules = $activity['rules']; | ||
32 | + | ||
33 | + // 当前配置应该自动结束的时间 | ||
34 | + $laterTime = $activity['endtime']; | ||
35 | + if (isset($rules['activity_auto_close']) && $rules['activity_auto_close'] > 0) { | ||
36 | + $laterTime += ($rules['activity_auto_close'] * 60); | ||
37 | + } | ||
38 | + | ||
39 | + // 如果当前时间大于 laterTime,可以执行删除 | ||
40 | + if (time() >= $laterTime) { | ||
41 | + // 删除活动 【软删】 | ||
42 | + $activity->delete(); | ||
43 | + | ||
44 | + // 删除活动缓存 | ||
45 | + $this->delActivity($activity); | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | + // 删除 job | ||
50 | + $job->delete(); | ||
51 | + } catch (\Exception $e) { | ||
52 | + // 队列执行失败 | ||
53 | + \think\Log::write('queue-' . get_class() . '-autoClose' . ':执行失败,错误信息:' . $e->getMessage()); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
57 | +} |
addons/groupon/job/BaseJob.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\job; | ||
4 | + | ||
5 | +use addons\groupon\model\Order; | ||
6 | +use addons\groupon\model\OrderAction; | ||
7 | +use think\queue\Job; | ||
8 | + | ||
9 | + | ||
10 | +/** | ||
11 | + * BaseJob 基类 | ||
12 | + */ | ||
13 | +class BaseJob | ||
14 | +{ | ||
15 | + | ||
16 | + public function failed($data){ | ||
17 | + // 记录日志 | ||
18 | + \think\Db::name('groupon_failed_job')->insert([ | ||
19 | + 'data' => json_encode($data), | ||
20 | + 'createtime' => time(), | ||
21 | + 'updatetime' => time() | ||
22 | + ]); | ||
23 | + } | ||
24 | + | ||
25 | +} |
addons/groupon/job/Notification.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\job; | ||
4 | + | ||
5 | +use think\queue\Job; | ||
6 | + | ||
7 | +/** | ||
8 | + * 队列消息通知 | ||
9 | + */ | ||
10 | +class Notification extends BaseJob | ||
11 | +{ | ||
12 | + /** | ||
13 | + * 发送通知 | ||
14 | + */ | ||
15 | + public function send(Job $job, $data){ | ||
16 | + try { | ||
17 | + // 这里获取到的 $notifiables 和 notification 两个都是数组,不是类,尴尬, 更可恨的 notification 只是 {"delay":0,"event":"changemobile"} | ||
18 | + $notifiables = $data['notifiables']; | ||
19 | + $notification = $data['notification']; | ||
20 | + // 因为 notification 只有参数,需要把对应的类传过来,在这里重新初始化 | ||
21 | + $notification_name = $data['notification_name']; | ||
22 | + | ||
23 | + // 重新实例化 notification 实例 | ||
24 | + $notification = new $notification_name($notification['data']); | ||
25 | + | ||
26 | + // 发送消息 | ||
27 | + \addons\groupon\library\notify\Notify::sendNow($notifiables, $notification); | ||
28 | + | ||
29 | + // 删除 job | ||
30 | + $job->delete(); | ||
31 | + } catch (\Exception $e) { | ||
32 | + // 队列执行失败 | ||
33 | + \think\Log::write('queue-' . get_class() | ||
34 | + . (isset($notification->event) ? ('-' . $notification->event) : '') | ||
35 | + . ':执行失败,错误信息:' . $e->getMessage()); | ||
36 | + } | ||
37 | + } | ||
38 | +} |
addons/groupon/job/OrderAutoOper.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\job; | ||
4 | + | ||
5 | +use addons\groupon\model\GoodsComment; | ||
6 | +use addons\groupon\model\Order; | ||
7 | +use addons\groupon\model\OrderAction; | ||
8 | +use addons\groupon\model\OrderItem; | ||
9 | +use addons\groupon\model\Config; | ||
10 | +use addons\groupon\model\Verify; | ||
11 | +use think\queue\Job; | ||
12 | + | ||
13 | + | ||
14 | +/** | ||
15 | + * 订单自动操作 | ||
16 | + */ | ||
17 | +class OrderAutoOper extends BaseJob | ||
18 | +{ | ||
19 | + | ||
20 | + /** | ||
21 | + * 订单自动关闭 | ||
22 | + */ | ||
23 | + public function autoClose(Job $job, $data){ | ||
24 | + try { | ||
25 | + $order = $data['order']; | ||
26 | + | ||
27 | + $order = Order::get($order['id']); | ||
28 | + | ||
29 | + if ($order && $order['status'] == 0) { | ||
30 | + \think\Db::transaction(function () use ($order, $data) { | ||
31 | + // 订单关闭前 | ||
32 | + \think\Hook::listen('groupon_order_close_before', $data); | ||
33 | + // 执行关闭 | ||
34 | + $order->status = Order::STATUS_INVALID; | ||
35 | + $order->ext = json_encode($order->setExt($order, ['invalid_time' => time()])); // 取消时间 | ||
36 | + $order->save(); | ||
37 | + | ||
38 | + OrderAction::operAdd($order, null, null, 'system', '系统自动失效订单'); | ||
39 | + | ||
40 | + // 订单自动关闭之后 行为 返还用户优惠券,积分 | ||
41 | + $data = ['order' => $order]; | ||
42 | + \think\Hook::listen('groupon_order_close_after', $data); | ||
43 | + }); | ||
44 | + } | ||
45 | + | ||
46 | + // 删除 job | ||
47 | + $job->delete(); | ||
48 | + } catch (\Exception $e) { | ||
49 | + // 队列执行失败 | ||
50 | + \think\Log::write('queue-' . get_class() . '-autoClose' . ':执行失败,错误信息:' . $e->getMessage()); | ||
51 | + } | ||
52 | + } | ||
53 | + | ||
54 | + | ||
55 | + /** | ||
56 | + * 订单自动确认 | ||
57 | + */ | ||
58 | + public function autoConfirm(Job $job, $data) { | ||
59 | + try { | ||
60 | + $order = $data['order']; | ||
61 | + $item = $data['item']; | ||
62 | + | ||
63 | + // 只要没有退款成功,所有队列正常执行 | ||
64 | + $item = OrderItem::where('id', $item['id']) | ||
65 | + ->where('dispatch_status', 'in', [OrderItem::DISPATCH_STATUS_READY, OrderItem::DISPATCH_STATUS_ARRIVE]) | ||
66 | + ->where('refund_status', 'not in', [OrderItem::REFUND_STATUS_OK, OrderItem::REFUND_STATUS_FINISH]) | ||
67 | + ->find(); | ||
68 | + | ||
69 | + if ($item) { | ||
70 | + \think\Db::transaction(function () use ($order, $item, $data) { | ||
71 | + // 查询核销券,并且将核销券设置为已使用 | ||
72 | + Verify::canUse()->where('order_item_id', $item['id'])->where('type', 'verify')->update([ | ||
73 | + 'usetime' => time(), | ||
74 | + 'oper_type' => 'system', | ||
75 | + 'oper_id' => 0, | ||
76 | + ]); | ||
77 | + | ||
78 | + (new Order())->getedItem($order, $item, ['oper_type' => 'system']); | ||
79 | + }); | ||
80 | + } | ||
81 | + | ||
82 | + // 删除 job | ||
83 | + $job->delete(); | ||
84 | + } catch (\Exception $e) { | ||
85 | + // 队列执行失败 | ||
86 | + \think\Log::write('queue-' . get_class() . '-autoConfirm' . ':执行失败,错误信息:' . $e->getMessage()); | ||
87 | + } | ||
88 | + } | ||
89 | + | ||
90 | + | ||
91 | + | ||
92 | + public function autoComment(Job $job, $data) { | ||
93 | + try { | ||
94 | + $order = $data['order']; | ||
95 | + $item = $data['item']; | ||
96 | + | ||
97 | + // 只要没有退款成功,所有队列正常执行 | ||
98 | + $item = OrderItem::where('id', $item['id']) | ||
99 | + ->where('dispatch_status', OrderItem::DISPATCH_STATUS_GETED) | ||
100 | + ->where('comment_status', OrderItem::COMMENT_STATUS_NO) | ||
101 | + ->where('refund_status', 'not in', [OrderItem::REFUND_STATUS_OK, OrderItem::REFUND_STATUS_FINISH]) | ||
102 | + ->find(); | ||
103 | + | ||
104 | + if ($item) { | ||
105 | + \think\Db::transaction(function () use ($order, $item, $data) { | ||
106 | + // 订单评价前 | ||
107 | + \think\Hook::listen('groupon_order_comment_before', $data); | ||
108 | + | ||
109 | + // 获取自动好评内容 | ||
110 | + $config = Config::where('name', 'order')->cache(300)->find(); // 读取配置自动缓存 5 分钟 | ||
111 | + $config = isset($config) ? json_decode($config['value'], true) : []; | ||
112 | + $comment_content = (isset($config['order_comment_content']) && $config['order_comment_content']) | ||
113 | + ? $config['order_comment_content'] : '用户默认好评'; // 单位天 | ||
114 | + | ||
115 | + GoodsComment::create([ | ||
116 | + 'goods_id' => $item['goods_id'], | ||
117 | + 'order_id' => $order['id'], | ||
118 | + 'user_id' => $order['user_id'], | ||
119 | + 'level' => 5, // 自动好评 | ||
120 | + 'content' => $comment_content, | ||
121 | + 'images' => '', | ||
122 | + 'status' => 'show' | ||
123 | + ]); | ||
124 | + | ||
125 | + $item->comment_status = OrderItem::COMMENT_STATUS_OK; // 评价成功 | ||
126 | + $item->save(); | ||
127 | + | ||
128 | + OrderAction::operAdd($order, $item, null, 'system', '系统自动评价成功'); | ||
129 | + | ||
130 | + // 订单评价后 | ||
131 | + $data = ['order' => $order, 'item' => $item]; | ||
132 | + \think\Hook::listen('groupon_order_comment_after', $data); | ||
133 | + }); | ||
134 | + } | ||
135 | + | ||
136 | + // 删除 job | ||
137 | + $job->delete(); | ||
138 | + } catch (\Exception $e) { | ||
139 | + // 队列执行失败 | ||
140 | + \think\Log::write('queue-' . get_class() . '-autoComment' . $e->getMessage()); | ||
141 | + } | ||
142 | + } | ||
143 | +} |
addons/groupon/job/OrderPayed.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\job; | ||
4 | + | ||
5 | +use addons\groupon\library\traits\Groupon; | ||
6 | +use addons\groupon\library\traits\StockSale; | ||
7 | +use addons\groupon\model\GoodsComment; | ||
8 | +use addons\groupon\model\Order; | ||
9 | +use addons\groupon\model\OrderAction; | ||
10 | +use addons\groupon\model\OrderItem; | ||
11 | +use think\queue\Job; | ||
12 | + | ||
13 | +/** | ||
14 | + * 订单支付完成 | ||
15 | + */ | ||
16 | +class OrderPayed extends BaseJob | ||
17 | +{ | ||
18 | + use StockSale; | ||
19 | + | ||
20 | + /** | ||
21 | + * 订单支付完成 | ||
22 | + */ | ||
23 | + public function payed(Job $job, $data){ | ||
24 | + try { | ||
25 | + $order = $data['order']; | ||
26 | + $user = $data['user']; | ||
27 | + | ||
28 | + $order = Order::with('item')->where('id', $order['id'])->find(); | ||
29 | + | ||
30 | + // 数据库删订单的问题常见,这里被删的订单直接把队列移除 | ||
31 | + if ($order) { | ||
32 | + \think\Db::transaction(function () use ($order, $user, $data) { | ||
33 | + // 触发订单支付完成事件 | ||
34 | + $data = ['order' => $order]; | ||
35 | + \think\Hook::listen('groupon_order_payed_after', $data); | ||
36 | + }); | ||
37 | + } | ||
38 | + | ||
39 | + // 删除 job | ||
40 | + $job->delete(); | ||
41 | + } catch (\Exception $e) { | ||
42 | + // 队列执行失败 | ||
43 | + $error = json_encode([ | ||
44 | + 'a' => $e->getLine(), | ||
45 | + 'b' => $e->getFile(), | ||
46 | + 'c' =>$e->getTrace(), | ||
47 | + 'd' => $e->getMessage() | ||
48 | + ], JSON_UNESCAPED_UNICODE); | ||
49 | + | ||
50 | + | ||
51 | + \think\Log::error('queue-' . get_class() . '-payed' . ':执行失败,错误信息:' . $error); | ||
52 | + } | ||
53 | + } | ||
54 | +} |
addons/groupon/lang/zh-cn.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + 'Keep login' => '保持会话', | ||
5 | + 'Username' => '用户名', | ||
6 | + 'User id' => '会员ID', | ||
7 | + 'Nickname' => '昵称', | ||
8 | + 'Password' => '密码', | ||
9 | + 'Sign up' => '注 册', | ||
10 | + 'Sign in' => '登 录', | ||
11 | + 'Sign out' => '注 销', | ||
12 | + 'Guest' => '游客', | ||
13 | + 'Welcome' => '%s,你好!', | ||
14 | + 'Add' => '添加', | ||
15 | + 'Edit' => '编辑', | ||
16 | + 'Delete' => '删除', | ||
17 | + 'Move' => '移动', | ||
18 | + 'Name' => '名称', | ||
19 | + 'Status' => '状态', | ||
20 | + 'Weigh' => '权重', | ||
21 | + 'Operate' => '操作', | ||
22 | + 'Warning' => '温馨提示', | ||
23 | + 'Default' => '默认', | ||
24 | + 'Article' => '文章', | ||
25 | + 'Page' => '单页', | ||
26 | + 'OK' => '确定', | ||
27 | + 'Cancel' => '取消', | ||
28 | + 'Loading' => '加载中', | ||
29 | + 'More' => '更多', | ||
30 | + 'Normal' => '正常', | ||
31 | + 'Hidden' => '隐藏', | ||
32 | + 'Submit' => '提交', | ||
33 | + 'Reset' => '重置', | ||
34 | + 'Execute' => '执行', | ||
35 | + 'Close' => '关闭', | ||
36 | + 'Search' => '搜索', | ||
37 | + 'Refresh' => '刷新', | ||
38 | + 'First' => '首页', | ||
39 | + 'Previous' => '上一页', | ||
40 | + 'Next' => '下一页', | ||
41 | + 'Last' => '末页', | ||
42 | + 'None' => '无', | ||
43 | + 'Home' => '主页', | ||
44 | + 'Online' => '在线', | ||
45 | + 'Logout' => '注销', | ||
46 | + 'Profile' => '个人资料', | ||
47 | + 'Index' => '首页', | ||
48 | + 'Hot' => '热门', | ||
49 | + 'Recommend' => '推荐', | ||
50 | + 'Dashboard' => '控制台', | ||
51 | + 'Code' => '编号', | ||
52 | + 'Message' => '内容', | ||
53 | + 'Line' => '行号', | ||
54 | + 'File' => '文件', | ||
55 | + 'Menu' => '菜单', | ||
56 | + 'Type' => '类型', | ||
57 | + 'Title' => '标题', | ||
58 | + 'Content' => '内容', | ||
59 | + 'Append' => '追加', | ||
60 | + 'Memo' => '备注', | ||
61 | + 'Parent' => '父级', | ||
62 | + 'Params' => '参数', | ||
63 | + 'Permission' => '权限', | ||
64 | + 'Advance search' => '高级搜索', | ||
65 | + 'Check all' => '选中全部', | ||
66 | + 'Expand all' => '展开全部', | ||
67 | + 'Begin time' => '开始时间', | ||
68 | + 'End time' => '结束时间', | ||
69 | + 'Create time' => '创建时间', | ||
70 | + 'Flag' => '标志', | ||
71 | + 'Please login first' => '请登录后操作', | ||
72 | + 'Redirect now' => '立即跳转', | ||
73 | + 'Operation completed' => '操作成功!', | ||
74 | + 'Operation failed' => '操作失败!', | ||
75 | + 'Unknown data format' => '未知的数据格式!', | ||
76 | + 'Network error' => '网络错误!', | ||
77 | + 'Advanced search' => '高级搜索', | ||
78 | + 'Invalid parameters' => '未知参数', | ||
79 | + 'No results were found' => '记录未找到', | ||
80 | + 'Parameter %s can not be empty' => '参数%s不能为空', | ||
81 | + 'You have no permission' => '你没有权限访问', | ||
82 | + 'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中', | ||
83 | + 'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转', | ||
84 | +]; |
addons/groupon/lang/zh-cn/common.php
0 → 100644
addons/groupon/lang/zh-cn/user.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +return [ | ||
4 | + 'User center' => '会员中心', | ||
5 | + 'Register' => '注册', | ||
6 | + 'Login' => '登录', | ||
7 | + 'Sign up successful' => '注册成功', | ||
8 | + 'Username can not be empty' => '用户名不能为空', | ||
9 | + 'Username must be 6 to 30 characters' => '用户名必须6-30个字符', | ||
10 | + 'Password can not be empty' => '密码不能为空', | ||
11 | + 'Password must be 6 to 30 characters' => '密码必须6-30个字符', | ||
12 | + 'Mobile is incorrect' => '手机格式不正确', | ||
13 | + 'Username already exist' => '用户名已经存在', | ||
14 | + 'Email already exist' => '邮箱已经存在', | ||
15 | + 'Mobile already exist' => '手机号已经存在', | ||
16 | + 'Username is incorrect' => '用户名不正确', | ||
17 | + 'Email is incorrect' => '邮箱不正确', | ||
18 | + 'Account is locked' => '账户已经被锁定', | ||
19 | + 'Password is incorrect' => '密码不正确', | ||
20 | + 'Account is incorrect' => '账户不正确', | ||
21 | + 'Account not exist' => '账户不存在', | ||
22 | + 'Account can not be empty' => '账户不能为空', | ||
23 | + 'Username or password is incorrect' => '用户名或密码不正确', | ||
24 | + 'You are not logged in' => '你当前还未登录', | ||
25 | + 'You\'ve logged in, do not login again' => '你已经存在,请不要重复登录', | ||
26 | + 'Profile' => '个人资料', | ||
27 | + 'Verify email' => '邮箱验证', | ||
28 | + 'Change password' => '修改密码', | ||
29 | + 'Captcha is incorrect' => '验证码不正确', | ||
30 | + 'Logged in successful' => '登录成功', | ||
31 | + 'Logout successful' => '注销成功', | ||
32 | + 'Operation failed' => '操作失败', | ||
33 | + 'Invalid parameters' => '参数不正确', | ||
34 | + 'Change password failure' => '修改密码失败', | ||
35 | + 'Change password successful' => '修改密码成功', | ||
36 | + 'Reset password successful' => '重置密码成功', | ||
37 | +]; |
addons/groupon/library/Export.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use EasyWeChat\Factory; | ||
6 | +use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
7 | +use PhpOffice\PhpSpreadsheet\Writer\Xlsx; | ||
8 | +use League\Flysystem\Adapter\Local; | ||
9 | +use League\Flysystem\Filesystem; | ||
10 | +use Cache\Adapter\Filesystem\FilesystemCachePool; | ||
11 | +use addons\groupon\library\Redis; | ||
12 | + | ||
13 | +/** | ||
14 | + * | ||
15 | + */ | ||
16 | +class Export | ||
17 | +{ | ||
18 | + | ||
19 | + | ||
20 | + public function __construct() | ||
21 | + { | ||
22 | + } | ||
23 | + | ||
24 | + public function exportExcel($expTitle, $expCellName, $expTableData, &$spreadsheet = null, &$sheet = null, $pages = []) | ||
25 | + { | ||
26 | + $page = $pages['page'] ?? 1; | ||
27 | + $page_size = $pages['page_size'] ?? 1000; | ||
28 | + $is_last_page = $pages['is_last_page'] ?? 1; | ||
29 | + $current_total = $pages['current_total'] ?? 0; | ||
30 | + | ||
31 | + if ($current_total) { | ||
32 | + // 每次传来的 expTableData 数据条数不等,比如订单导出 | ||
33 | + $base_cell = $current_total - count($expTableData) + 2; | ||
34 | + } else { | ||
35 | + $base_cell = ($page - 1) * $page_size + 2; | ||
36 | + } | ||
37 | + | ||
38 | + $fileName = $expTitle; | ||
39 | + $cellNum = count($expCellName); | ||
40 | + $dataNum = count($expTableData); | ||
41 | + $cellName = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'); | ||
42 | + | ||
43 | + if ($page == 1) { | ||
44 | + // 不限时 | ||
45 | + set_time_limit(0); | ||
46 | + // 根据需要调大内存限制 | ||
47 | + ini_set('memory_limit', '512M'); | ||
48 | + | ||
49 | + $cache_type = 'redis'; | ||
50 | + // 设置缓存 | ||
51 | + if ($cache_type == 'redis' && class_exists(\Cache\Adapter\Redis\RedisCachePool::class)) { | ||
52 | + // 将表格数据暂存 redis,可以降低 php 进程内存占用,需要安装扩展包 composer require cache/simple-cache-bridge cache/redis-adapter | ||
53 | + $options = [ | ||
54 | + // 'select' => 0 // 注释解开,并且换成一个空的 select 库,redis 库默认是 0-15 共 16 个库 | ||
55 | + ]; | ||
56 | + | ||
57 | + $redis = (new Redis($options))->getRedis(); | ||
58 | + $pool = new \Cache\Adapter\Redis\RedisCachePool($redis); | ||
59 | + $simpleCache = new \Cache\Bridge\SimpleCache\SimpleCacheBridge($pool); | ||
60 | + | ||
61 | + \PhpOffice\PhpSpreadsheet\Settings::setCache($simpleCache); | ||
62 | + } else if ($cache_type == 'file' && class_exists(FilesystemCachePool::class)) { | ||
63 | + // 将数据暂存磁盘,可以降低内存,但是导出速度会大幅下降 需要安装扩展包 composer require cache/filesystem-adapter | ||
64 | + $path = ROOT_PATH . 'runtime' . DS . 'export/'; | ||
65 | + @mkdir($path); | ||
66 | + $filesystemAdapter = new Local($path); | ||
67 | + $filesystem = new Filesystem($filesystemAdapter); | ||
68 | + $pool = new FilesystemCachePool($filesystem); | ||
69 | + | ||
70 | + \PhpOffice\PhpSpreadsheet\Settings::setCache($pool); | ||
71 | + } | ||
72 | + | ||
73 | + // 实例化excel | ||
74 | + $spreadsheet = new Spreadsheet(); | ||
75 | + // 初始化工作簿 | ||
76 | + $sheet = $spreadsheet->getActiveSheet(0); | ||
77 | + // 给表头设置边框 | ||
78 | + $sheet->getStyle('A1:' . $cellName[$cellNum - 1] . '1')->getFont()->setBold(true); | ||
79 | + | ||
80 | + // 表头 | ||
81 | + $i = 0; | ||
82 | + foreach ($expCellName as $key => $cell) { | ||
83 | + $sheet->setCellValue($cellName[$i] . '1', $cell); | ||
84 | + $i++; | ||
85 | + } | ||
86 | + } | ||
87 | + | ||
88 | + // for ($i = 0; $i < $cellNum; $i++) { | ||
89 | + // $sheet->getColumnDimension($cellName[$i])->setWidth(30); | ||
90 | + // } | ||
91 | + | ||
92 | + // 写入数据 | ||
93 | + for ($i = 0; $i < $dataNum; $i++) { | ||
94 | + if ($is_last_page && $i == ($dataNum - 1)) { | ||
95 | + $sheet->mergeCells('A' . ($i + $base_cell) . ':' . $cellName[$cellNum - 1] . ($i + $base_cell)); | ||
96 | + $sheet->setCellValue('A' . ($i + $base_cell), $expTableData[$i][key($expCellName)]); | ||
97 | + } else { | ||
98 | + $j = 0; | ||
99 | + foreach ($expCellName as $key => $cell) { | ||
100 | + $sheet->setCellValue($cellName[$j] . ($i + $base_cell), $expTableData[$i][$key]); | ||
101 | + $j++; | ||
102 | + } | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + if ($is_last_page) { | ||
107 | + // ini_set('memory_limit', '256M'); | ||
108 | + | ||
109 | + ob_end_clean(); | ||
110 | + header('pragma:public'); | ||
111 | + header('Content-type:application/vnd.ms-excel;charset=utf-8;name="' . $fileName . '.xlsx"'); | ||
112 | + header("Content-Disposition:attachment;filename=$fileName.xlsx"); //attachment新窗口打印inline本窗口打印 | ||
113 | + $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx'); | ||
114 | + $writer->save('php://output'); | ||
115 | + } | ||
116 | + } | ||
117 | +} |
addons/groupon/library/Express.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use fast\Http; | ||
6 | + | ||
7 | +class Express | ||
8 | +{ | ||
9 | + // 查询接口 | ||
10 | + const REQURL = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx"; | ||
11 | + // 订阅接口 | ||
12 | + const SUBURL = "https://api.kdniao.com/api/dist"; | ||
13 | + | ||
14 | + protected $config = []; | ||
15 | + | ||
16 | + /** | ||
17 | + * 构造函数 | ||
18 | + */ | ||
19 | + public function __construct() | ||
20 | + { | ||
21 | + $config = \addons\groupon\model\Config::get(['name' => 'services']); | ||
22 | + $config = ($config && $config->value) ? json_decode($config->value, true) : []; | ||
23 | + | ||
24 | + $expressConfig = $config['express'] ?? []; | ||
25 | + if (!$expressConfig || !$expressConfig['ebusiness_id'] || !$expressConfig['appkey']) { | ||
26 | + throw new \Exception('请配置快递接口'); | ||
27 | + } | ||
28 | + | ||
29 | + $this->config = $expressConfig; | ||
30 | + } | ||
31 | + | ||
32 | + | ||
33 | + /** | ||
34 | + * Json方式 物流信息订阅 | ||
35 | + */ | ||
36 | + public function subscribe($data = [], $orderExpress = null, $order = null) | ||
37 | + { | ||
38 | + $requestData = $this->getRequestData($data, $orderExpress, $order); | ||
39 | + | ||
40 | + $datas = [ | ||
41 | + 'EBusinessID' => $this->config['ebusiness_id'], | ||
42 | + 'RequestType' => $this->config['type'] == 'free' ? '1008' : '8008', | ||
43 | + 'RequestData' => urlencode($requestData), | ||
44 | + 'DataType' => '2', | ||
45 | + ]; | ||
46 | + $datas['DataSign'] = $this->encrypt($requestData, $this->config['appkey']); | ||
47 | + | ||
48 | + $result = Http::sendRequest(self::SUBURL, $datas, 'POST', []); | ||
49 | + | ||
50 | + if ($result['ret'] == 1) { | ||
51 | + $exResult = json_decode($result['msg'], true); | ||
52 | + | ||
53 | + if (!$exResult['Success']) { | ||
54 | + throw new \Exception($exResult['Reason']); | ||
55 | + } | ||
56 | + | ||
57 | + return $exResult; | ||
58 | + } else { | ||
59 | + throw new \Exception($result['msg']); | ||
60 | + } | ||
61 | + } | ||
62 | + | ||
63 | + | ||
64 | + // 查询快递信息 | ||
65 | + public function search($data = [], $orderExpress = null, $order = null) | ||
66 | + { | ||
67 | + $requestData = $this->getRequestData($data, $orderExpress, $order); | ||
68 | + | ||
69 | + $datas = [ | ||
70 | + 'EBusinessID' => $this->config['ebusiness_id'], | ||
71 | + 'RequestType' => $this->config['type'] == 'free' ? '1002' : '8001', | ||
72 | + 'RequestData' => urlencode($requestData), | ||
73 | + 'DataType' => '2', | ||
74 | + ]; | ||
75 | + $datas['DataSign'] = $this->encrypt($requestData, $this->config['appkey']); | ||
76 | + $result = Http::sendRequest(self::REQURL, $datas, 'POST', []); | ||
77 | + | ||
78 | + if ($result['ret'] == 1) { | ||
79 | + $exResult = json_decode($result['msg'], true); | ||
80 | + | ||
81 | + if (!$exResult['Success']) { | ||
82 | + throw new \Exception($exResult['Reason']); | ||
83 | + } | ||
84 | + | ||
85 | + return $exResult; | ||
86 | + } else { | ||
87 | + throw new \Exception($result['msg']); | ||
88 | + } | ||
89 | + } | ||
90 | + | ||
91 | + | ||
92 | + // 组装请求数据 | ||
93 | + private function getRequestData($data = [], $orderExpress = null, $order = null) { | ||
94 | + $requestData = [ | ||
95 | + 'OrderCode' => $order ? $order->order_sn : ($data['order_code'] ?? ''), | ||
96 | + 'ShipperCode' => $data['express_code'], | ||
97 | + 'LogisticCode' => $data['express_no'], | ||
98 | + ]; | ||
99 | + | ||
100 | + if ($data['express_code'] == 'JD') { | ||
101 | + // 京东青龙配送单号 | ||
102 | + $requestData['CustomerName'] = $this->config['jd_code']; | ||
103 | + } else if ($data['express_code'] == 'SF') { | ||
104 | + // 收件人手机号后四位 | ||
105 | + $requestData['CustomerName'] = substr($order->phone, 7); | ||
106 | + } | ||
107 | + | ||
108 | + $requestData = json_encode($requestData); | ||
109 | + | ||
110 | + return $requestData; | ||
111 | + } | ||
112 | + | ||
113 | + | ||
114 | + | ||
115 | + // 差异更新物流信息 | ||
116 | + public function checkAndAddTraces ($orderExpress, $express) { | ||
117 | + $traces = $express['Traces']; | ||
118 | + | ||
119 | + // 查询现有轨迹记录 | ||
120 | + $orderExpressLog = \addons\groupon\model\OrderExpressLog::where('order_express_id', $orderExpress->id)->where('store_id', $orderExpress['store_id'])->select(); | ||
121 | + | ||
122 | + $log_count = count($orderExpressLog); | ||
123 | + if ($log_count > 0) { | ||
124 | + // 移除已经存在的记录 | ||
125 | + array_splice($traces, 0, $log_count); | ||
126 | + } | ||
127 | + | ||
128 | + // 增加包裹记录 | ||
129 | + foreach ($traces as $k => $trace) { | ||
130 | + $orderExpressLog = new \addons\groupon\model\OrderExpressLog(); | ||
131 | + | ||
132 | + $orderExpressLog->user_id = $orderExpress['user_id'] ?? 0; | ||
133 | + $orderExpressLog->order_id = $orderExpress['order_id'] ?? 0; | ||
134 | + $orderExpressLog->store_id = $orderExpress['store_id'] ?? 0; | ||
135 | + $orderExpressLog->order_express_id = $orderExpress['id']; | ||
136 | + $orderExpressLog->status = $trace['Action'] ?? $express['State']; | ||
137 | + $orderExpressLog->content = $trace['AcceptStation']; | ||
138 | + $orderExpressLog->changedate = substr($trace['AcceptTime'], 0, 19); // 快递鸟测试数据 返回的是个 2020-08-03 16:58:272 格式 | ||
139 | + $orderExpressLog->location = $trace['Location'] ?? ($express['Location'] ?? null); | ||
140 | + $orderExpressLog->save(); | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + | ||
145 | + // 组装返回结果 | ||
146 | + public function setPushResult($success = false, $reason = '') { | ||
147 | + $result = [ | ||
148 | + "EBusinessID" => $this->config['ebusiness_id'], | ||
149 | + "UpdateTime" => date('Y-m-d H:i:s'), | ||
150 | + "Success" => $success, | ||
151 | + "Reason" => $reason | ||
152 | + ]; | ||
153 | + | ||
154 | + return $result; | ||
155 | + } | ||
156 | + | ||
157 | + | ||
158 | + // 加签 | ||
159 | + function encrypt($data, $appkey) | ||
160 | + { | ||
161 | + return urlencode(base64_encode(md5($data . $appkey))); | ||
162 | + } | ||
163 | +} |
addons/groupon/library/Hook.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use EasyWeChat\Factory; | ||
6 | +use addons\groupon\model\Config; | ||
7 | +use think\Model; | ||
8 | + | ||
9 | +/** | ||
10 | + * | ||
11 | + */ | ||
12 | +class Hook | ||
13 | +{ | ||
14 | + | ||
15 | + public function __construct() | ||
16 | + { | ||
17 | + | ||
18 | + } | ||
19 | + | ||
20 | + public static function register ($behaviors = []) { | ||
21 | + $default = require ROOT_PATH . 'addons/groupon/hooks.php'; | ||
22 | + | ||
23 | + $behaviors = array_merge($default, $behaviors); | ||
24 | + foreach ($behaviors as $tag => $behavior) { | ||
25 | + // 数组反转 保证最上面的行为优先级最高 | ||
26 | + $behavior = array_reverse($behavior); | ||
27 | + foreach ($behavior as $be) { | ||
28 | + \think\Hook::add($tag, $be, true); // 所有行为都插入最前面 | ||
29 | + } | ||
30 | + } | ||
31 | + } | ||
32 | +} |
addons/groupon/library/Oper.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use app\admin\library\Auth as AdminAuth; | ||
6 | +use addons\groupon\model\Store; | ||
7 | +use addons\groupon\model\User; | ||
8 | + | ||
9 | +class Oper | ||
10 | +{ | ||
11 | + public static function set($operType = '', $operId = 0) | ||
12 | + { | ||
13 | + if ($operType === '') { | ||
14 | + // 自动获取操作人 | ||
15 | + $admin = AdminAuth::instance(); // 没有登录返回的还是这个类实例 | ||
16 | + if ($admin->isLogin()) { | ||
17 | + // 后台管理员 | ||
18 | + $operType = 'admin'; | ||
19 | + $operId = $admin->id; | ||
20 | + } else if (strpos(request()->url(), 'store.store') !== false) { | ||
21 | + // 门店 | ||
22 | + $store = Store::info(); | ||
23 | + if ($store) { | ||
24 | + $operType = 'store'; | ||
25 | + $operId = $store['id']; | ||
26 | + } | ||
27 | + } else if (strpos(request()->url(), 'addons/groupon') !== false) { | ||
28 | + // 用户 | ||
29 | + $user = User::info(); | ||
30 | + if ($user) { | ||
31 | + $operType = 'user'; | ||
32 | + $operId = $user->id; | ||
33 | + } | ||
34 | + } | ||
35 | + } | ||
36 | + if ($operType === '') { | ||
37 | + $operType = 'system'; | ||
38 | + } | ||
39 | + return [ | ||
40 | + 'oper_type' => $operType, | ||
41 | + 'oper_id' => $operId | ||
42 | + ]; | ||
43 | + } | ||
44 | + | ||
45 | + public static function get($operType, $operId) | ||
46 | + { | ||
47 | + $operator = null; | ||
48 | + if ($operType === 'admin') { | ||
49 | + $operator = \app\admin\model\Admin::where('id', $operId)->field('nickname as name, avatar')->find(); | ||
50 | + $operator['type'] = '管理员'; | ||
51 | + } elseif ($operType === 'user') { | ||
52 | + $operator = \addons\groupon\model\User::where('id', $operId)->field('nickname as name, avatar')->find(); | ||
53 | + $operator['type'] = '用户'; | ||
54 | + } elseif ($operType === 'store') { | ||
55 | + $operator = \addons\groupon\model\Store::where('id', $operId)->field('name')->find(); | ||
56 | + $operator['type'] = '用户'; | ||
57 | + $operator['avatar'] = ''; | ||
58 | + } else { | ||
59 | + $operator = [ | ||
60 | + 'name' => '系统', | ||
61 | + 'avatar' => '', | ||
62 | + 'type' => '系统' | ||
63 | + ]; | ||
64 | + } | ||
65 | + if(!isset($operator['name'])) { | ||
66 | + $operator['name'] = '已删除'; | ||
67 | + $operator['avatar'] = ''; | ||
68 | + } | ||
69 | + return $operator; | ||
70 | + } | ||
71 | +} |
addons/groupon/library/PayService.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use Yansongda\Pay\Pay; | ||
6 | +use Yansongda\Pay\Log; | ||
7 | +use addons\groupon\exception\Exception; | ||
8 | + | ||
9 | +class PayService | ||
10 | +{ | ||
11 | + protected $config; | ||
12 | + protected $platform; | ||
13 | + protected $payment; | ||
14 | + protected $notify_url; | ||
15 | + public $method; | ||
16 | + | ||
17 | + | ||
18 | + public function __construct($payment, $platform = '', $notify_url = '', $type = 'pay') | ||
19 | + { | ||
20 | + $this->platform = $platform; | ||
21 | + $this->payment = $payment; | ||
22 | + $this->notify_url = $notify_url; | ||
23 | + $this->type = $type; | ||
24 | + | ||
25 | + $this->setPaymentConfig(); | ||
26 | + } | ||
27 | + | ||
28 | + private function setPaymentConfig() | ||
29 | + { | ||
30 | + $paymentConfig = json_decode(\addons\groupon\model\Config::get(['name' => $this->payment])->value, true); | ||
31 | + | ||
32 | + // 如果是支付,并且不是 复制地址的支付宝支付 | ||
33 | + if ($this->type == 'pay' && $this->platform != 'url' && !in_array($this->platform, $paymentConfig['platform'])) { | ||
34 | + throw new Exception('暂不支持该方式付款'); | ||
35 | + } | ||
36 | + | ||
37 | + $this->config = $paymentConfig; | ||
38 | + $this->config['notify_url'] = $this->notify_url; | ||
39 | + | ||
40 | + $this->config['http'] = [ | ||
41 | + 'timeout' => 10, | ||
42 | + 'connect_timeout' => 10, | ||
43 | + ]; | ||
44 | + | ||
45 | + if ($this->payment === 'wechat') { | ||
46 | + // 根据不同平台设置相应的 appid | ||
47 | + $this->setWechatAppId(); | ||
48 | + } | ||
49 | + | ||
50 | + // 设置支付证书路径 | ||
51 | + $this->setCert(); | ||
52 | + } | ||
53 | + | ||
54 | + private function setWechatAppId() | ||
55 | + { | ||
56 | + switch ($this->platform) { | ||
57 | + case 'wxOfficialAccount': | ||
58 | + $platformConfig = json_decode(\addons\groupon\model\Config::get(['name' => $this->platform])->value, true); | ||
59 | + if (isset($this->config['mode']) && $this->config['mode'] === 'service') { | ||
60 | + $this->config['sub_app_id'] = $platformConfig['app_id']; | ||
61 | + $this->config['app_id'] = $this->config['app_id']; // 主商户号,关联的 app_id | ||
62 | + } else { | ||
63 | + $this->config['app_id'] = $platformConfig['app_id']; | ||
64 | + } | ||
65 | + break; | ||
66 | + case 'wxMiniProgram': | ||
67 | + $platformConfig = json_decode(\addons\groupon\model\Config::get(['name' => $this->platform])->value, true); | ||
68 | + if (isset($this->config['mode']) && $this->config['mode'] === 'service') { | ||
69 | + $this->config['sub_miniapp_id'] = $platformConfig['app_id']; | ||
70 | + // $this->config['sub_app_id'] = $platformConfig['app_id']; | ||
71 | + $this->config['miniapp_id'] = $this->config['app_id']; // 主商户号,关联的 app_id | ||
72 | + } else { | ||
73 | + $this->config['miniapp_id'] = $platformConfig['app_id']; | ||
74 | + $this->config['app_id'] = $platformConfig['app_id']; // 小程序微信企业付款 | ||
75 | + } | ||
76 | + break; | ||
77 | + case 'H5': | ||
78 | + $platformConfig = json_decode(\addons\groupon\model\Config::get(['name' => $this->platform])->value, true); | ||
79 | + if (isset($this->config['mode']) && $this->config['mode'] === 'service') { | ||
80 | + $this->config['sub_app_id'] = $platformConfig['app_id']; | ||
81 | + $this->config['appid'] = $this->config['app_id']; // 主商户号,关联的 app_id | ||
82 | + } else { | ||
83 | + $this->config['app_id'] = $platformConfig['app_id']; | ||
84 | + } | ||
85 | + break; | ||
86 | + case 'App': | ||
87 | + $platformConfig = json_decode(\addons\groupon\model\Config::get(['name' => 'App'])->value, true); | ||
88 | + if (isset($this->config['mode']) && $this->config['mode'] === 'service') { | ||
89 | + $this->config['sub_appid'] = $platformConfig['app_id']; | ||
90 | + $this->config['sub_app_id'] = $platformConfig['app_id']; | ||
91 | + $this->config['appid'] = $this->config['app_id']; // 主商户号,关联的 app_id | ||
92 | + } else { | ||
93 | + $this->config['appid'] = $platformConfig['app_id']; // 微信 App 支付使用这个 | ||
94 | + $this->config['app_id'] = $platformConfig['app_id']; // 微信 App 支付退款使用的是这个 | ||
95 | + } | ||
96 | + | ||
97 | + break; | ||
98 | + } | ||
99 | + } | ||
100 | + | ||
101 | + | ||
102 | + // 处理证书路径 | ||
103 | + private function setCert() | ||
104 | + { | ||
105 | + // 处理证书路径 | ||
106 | + if ($this->payment == 'wechat') { | ||
107 | + // 微信支付证书 | ||
108 | + $this->config['cert_client'] = ROOT_PATH . 'public' . $this->config['cert_client']; | ||
109 | + $this->config['cert_key'] = ROOT_PATH . 'public' . $this->config['cert_key']; | ||
110 | + } else { | ||
111 | + // 支付宝证书路径 | ||
112 | + $end = substr($this->config['ali_public_key'], -4); | ||
113 | + if ($end == '.crt') { | ||
114 | + $this->config['ali_public_key'] = ROOT_PATH . 'public' . $this->config['ali_public_key']; | ||
115 | + } | ||
116 | + $this->config['app_cert_public_key'] = ROOT_PATH . 'public' . $this->config['app_cert_public_key']; | ||
117 | + $this->config['alipay_root_cert'] = ROOT_PATH . 'public' . $this->config['alipay_root_cert']; | ||
118 | + } | ||
119 | + } | ||
120 | + | ||
121 | + private function setPaymentMethod() | ||
122 | + { | ||
123 | + $method = [ | ||
124 | + 'wechat' => [ | ||
125 | + 'wxOfficialAccount' => 'mp', //公众号支付 Collection | ||
126 | + 'wxMiniProgram' => 'miniapp', //小程序支付 | ||
127 | + 'H5' => 'wap', //手机网站支付 Response | ||
128 | + 'App' => 'app' //APP 支付 JsonResponse | ||
129 | + ], | ||
130 | + 'alipay' => [ | ||
131 | + 'wxOfficialAccount' => 'wap', //手机网站支付 Response | ||
132 | + 'wxMiniProgram' => 'wap', //小程序支付 | ||
133 | + 'H5' => 'wap', //手机网站支付 Response | ||
134 | + 'url' => 'wap', //手机网站支付 Response | ||
135 | + 'App' => 'app' //APP 支付 JsonResponse | ||
136 | + ], | ||
137 | + ]; | ||
138 | + | ||
139 | + $this->method = $method[$this->payment][$this->platform]; | ||
140 | + } | ||
141 | + | ||
142 | + public function create($order) | ||
143 | + { | ||
144 | + // $order = [ | ||
145 | + // 'out_trade_no' => time(), | ||
146 | + // 'total_fee' => '1', // **单位:分** | ||
147 | + // 'body' => 'test body - 测试', | ||
148 | + // 'openid' => 'onkVf1FjWS5SBIixxxxxxx', //微信需要带openid过来 | ||
149 | + // ]; | ||
150 | + // 设置支付方式 | ||
151 | + $this->setPaymentMethod(); | ||
152 | + | ||
153 | + $method = $this->method; | ||
154 | + switch ($this->payment) { | ||
155 | + case 'wechat': | ||
156 | + if (isset($this->config['mode']) && $this->config['mode'] === 'service') { | ||
157 | + $order['sub_openid'] = $order['openid'] ?? ''; | ||
158 | + unset($order['openid']); | ||
159 | + } | ||
160 | + | ||
161 | + $order['total_fee'] = $order['total_fee'] * 100; | ||
162 | + $pay = Pay::wechat($this->config)->$method($order); | ||
163 | + | ||
164 | + break; | ||
165 | + case 'alipay': | ||
166 | + if (in_array($this->platform, ['wxOfficialAccount', 'wxMiniProgram', 'H5'])) { | ||
167 | + // 返回支付宝支付链接 | ||
168 | + $pay = request()->domain() . '/addons/groupon/pay/alipay?order_sn=' . $order['out_trade_no']; | ||
169 | + } else { | ||
170 | + if ($this->method == 'wap') { | ||
171 | + // 支付宝 wap 支付,增加 return_url | ||
172 | + // 获取 h5 域名 | ||
173 | + $platformConfig = json_decode(\addons\groupon\model\Config::get(['name' => 'groupon'])->value, true); | ||
174 | + // 如果域名存在,增加 return_url | ||
175 | + if ($platformConfig && isset($platformConfig['domain'])) { | ||
176 | + $start = substr($platformConfig['domain'], -1) == '/' ? "" : "/"; | ||
177 | + $this->config['return_url'] = $platformConfig['domain'] . $start . "pages/order/payment/result?orderSn=" . $order['out_trade_no'] . "&type=alipay&pay=1"; | ||
178 | + } | ||
179 | + } | ||
180 | + | ||
181 | + $pay = Pay::alipay($this->config)->$method($order); | ||
182 | + } | ||
183 | + | ||
184 | + break; | ||
185 | + } | ||
186 | + | ||
187 | + return $pay; | ||
188 | + } | ||
189 | + | ||
190 | + | ||
191 | + // 企业付款 | ||
192 | + public function transfer($payload) | ||
193 | + { | ||
194 | + // 服务商模式企业付款使用子商户证书 | ||
195 | + if ($this->payment == 'wechat' && isset($this->config['mode']) && $this->config['mode'] === 'service') { | ||
196 | + $this->config['cert_client'] = ROOT_PATH . 'public' . $this->config['sub_cert_client']; | ||
197 | + $this->config['cert_key'] = ROOT_PATH . 'public' . $this->config['sub_cert_key']; | ||
198 | + $this->config['key'] = $this->config['sub_key']; | ||
199 | + $this->config['mch_id'] = $this->config['sub_mch_id']; | ||
200 | + $this->config['mode'] = 'normal'; // 临时改为普通商户 | ||
201 | + } | ||
202 | + | ||
203 | + $code = 0; | ||
204 | + $response = []; | ||
205 | + // 支付宝返回结果 | ||
206 | + // [code] => 10000 | ||
207 | + // [msg] => Success | ||
208 | + // [order_id] => 20210309110070000006730051669626 | ||
209 | + // [out_biz_no] => W202107231625700647008000 | ||
210 | + // [pay_fund_order_id] => 20210309110070001506730065959451 | ||
211 | + // [status] => SUCCESS | ||
212 | + // [trans_date] => 2021-03-09 10:42:23 | ||
213 | + | ||
214 | + // 微信返回结果 | ||
215 | + // [return_code] => SUCCESS | ||
216 | + // [return_msg] => Array | ||
217 | + // ( | ||
218 | + // ) | ||
219 | + // [mch_appid] => wx38939920ace0d244 | ||
220 | + // [mchid] => 1481069012 | ||
221 | + // [nonce_str] => O9fwzb6HDGO2zU6H | ||
222 | + // [result_code] => SUCCESS | ||
223 | + // [partner_trade_no] => W202106361960501154008000 | ||
224 | + // [payment_no] => 10100294905592102257932685920233 | ||
225 | + // [payment_time] => 2021-02-25 18:36:30 | ||
226 | + switch ($this->payment) { | ||
227 | + case 'wechat': | ||
228 | + $payload['amount'] = $payload['amount'] * 100; | ||
229 | + $response = Pay::wechat($this->config)->transfer($payload); | ||
230 | + if ($response['return_code'] === 'SUCCESS' && $response['result_code'] === 'SUCCESS') { | ||
231 | + $code = 1; | ||
232 | + } | ||
233 | + break; | ||
234 | + case 'alipay': | ||
235 | + $response = Pay::alipay($this->config)->transfer($payload); | ||
236 | + if ($response['code'] === '10000' && $response['status'] === 'SUCCESS') { | ||
237 | + $code = 1; | ||
238 | + } | ||
239 | + break; | ||
240 | + } | ||
241 | + | ||
242 | + return [$code, $response]; | ||
243 | + } | ||
244 | + | ||
245 | + | ||
246 | + public function notify($callback) | ||
247 | + { | ||
248 | + $pay = $this->getPay(); | ||
249 | + | ||
250 | + try { | ||
251 | + $data = $pay->verify(); // 是的,验签就这么简单! | ||
252 | + | ||
253 | + $result = $callback($data, $pay); | ||
254 | + | ||
255 | + // Log::debug('Wechat notify', $data->all()); | ||
256 | + } catch (\Exception $e) { | ||
257 | + \think\Log::error('notify-error:' . $e->getMessage()); | ||
258 | + // $e->getMessage(); | ||
259 | + } | ||
260 | + | ||
261 | + return $result; | ||
262 | + } | ||
263 | + | ||
264 | + | ||
265 | + public function refund($order_data) | ||
266 | + { | ||
267 | + $pay = $this->getPay(); | ||
268 | + | ||
269 | + $order_data['type'] = $this->platform == 'wxMiniProgram' ? 'miniapp' : ''; | ||
270 | + | ||
271 | + $result = $pay->refund($order_data); | ||
272 | + | ||
273 | + \think\Log::write('refund-result' . json_encode($result)); | ||
274 | + | ||
275 | + if ($this->payment == 'wechat') { | ||
276 | + // 微信通知回调 pay->notifyr | ||
277 | + if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') { | ||
278 | + return $result; | ||
279 | + } else { | ||
280 | + throw new \Exception($result['return_msg']); | ||
281 | + } | ||
282 | + } else { | ||
283 | + // 支付宝通知回调 pay->notifyx | ||
284 | + if ($result['code'] == "10000") { | ||
285 | + return $result; | ||
286 | + } else { | ||
287 | + throw new \Exception($result['msg']); | ||
288 | + } | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | + | ||
293 | + public function notifyRefund($callback) | ||
294 | + { | ||
295 | + $pay = $this->getPay(); | ||
296 | + | ||
297 | + try { | ||
298 | + $data = $pay->verify(null, true); // 是的,验签就这么简单! | ||
299 | + \think\Log::write('notifyr-result:' . json_encode($data)); | ||
300 | + | ||
301 | + $result = $callback($data, $pay); | ||
302 | + | ||
303 | + // Log::debug('Wechat notify', $data->all()); | ||
304 | + } catch (\Exception $e) { | ||
305 | + \think\Log::write('notifyr-verify-error:' . $e->getMessage()); // $e->getMessage(); | ||
306 | + | ||
307 | + return false; | ||
308 | + } | ||
309 | + | ||
310 | + return $result; | ||
311 | + } | ||
312 | + | ||
313 | + | ||
314 | + private function getPay() | ||
315 | + { | ||
316 | + switch ($this->payment) { | ||
317 | + case 'wechat': | ||
318 | + $pay = Pay::wechat($this->config); | ||
319 | + break; | ||
320 | + case 'alipay': | ||
321 | + $pay = Pay::alipay($this->config); | ||
322 | + break; | ||
323 | + default: | ||
324 | + throw new Exception('支付方式不支持'); | ||
325 | + } | ||
326 | + | ||
327 | + return $pay; | ||
328 | + } | ||
329 | +} |
addons/groupon/library/Redis.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | + | ||
7 | +class Redis | ||
8 | +{ | ||
9 | + protected $handler = null; | ||
10 | + | ||
11 | + protected $options = [ | ||
12 | + 'host' => '127.0.0.1', | ||
13 | + 'port' => 6379, | ||
14 | + 'password' => '', | ||
15 | + 'select' => 0, | ||
16 | + 'timeout' => 0, | ||
17 | + 'expire' => 0, | ||
18 | + 'persistent' => false, | ||
19 | + 'prefix' => '', | ||
20 | + ]; | ||
21 | + | ||
22 | + /** | ||
23 | + * 构造函数 | ||
24 | + * @param array $options 缓存参数 | ||
25 | + * @access public | ||
26 | + */ | ||
27 | + public function __construct($options = []) | ||
28 | + { | ||
29 | + if (!extension_loaded('redis')) { | ||
30 | + throw new \BadFunctionCallException('not support: redis'); | ||
31 | + } | ||
32 | + | ||
33 | + // 获取 redis 配置 | ||
34 | + $config = \think\Config::get('redis'); | ||
35 | + if (empty($config) && empty($options)) { | ||
36 | + throw new \Exception('redis connection fail: no redis config'); | ||
37 | + } | ||
38 | + | ||
39 | + if (!empty($config)) { | ||
40 | + $this->options = array_merge($this->options, $config); | ||
41 | + } | ||
42 | + | ||
43 | + if (!empty($options)) { | ||
44 | + $this->options = array_merge($this->options, $options); | ||
45 | + } | ||
46 | + $this->handler = new \Redis(); | ||
47 | + if ($this->options['persistent']) { | ||
48 | + $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']); | ||
49 | + } else { | ||
50 | + $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']); | ||
51 | + } | ||
52 | + | ||
53 | + if ('' != $this->options['password']) { | ||
54 | + $this->handler->auth($this->options['password']); | ||
55 | + } | ||
56 | + | ||
57 | + if (0 != $this->options['select']) { | ||
58 | + $this->handler->select($this->options['select']); | ||
59 | + } | ||
60 | + | ||
61 | + // 赋值全局,避免多次实例化 | ||
62 | + $GLOBALS['SPREDIS'] = $this->handler; | ||
63 | + } | ||
64 | + | ||
65 | + public function getRedis() { | ||
66 | + return $this->handler; | ||
67 | + } | ||
68 | +} |
addons/groupon/library/Wechat.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library; | ||
4 | + | ||
5 | +use EasyWeChat\Factory; | ||
6 | +use addons\groupon\model\Config; | ||
7 | +use think\Model; | ||
8 | +use fast\Http; | ||
9 | + | ||
10 | +/** | ||
11 | + * | ||
12 | + */ | ||
13 | +class Wechat extends Model | ||
14 | +{ | ||
15 | + protected $config; | ||
16 | + protected $app; | ||
17 | + | ||
18 | + | ||
19 | + public function __construct($platform) | ||
20 | + { | ||
21 | + $this->config = Config::getEasyWechatConfig($platform); | ||
22 | + switch ($platform) { | ||
23 | + case 'wxOfficialAccount': | ||
24 | + $this->app = Factory::officialAccount($this->config); | ||
25 | + break; | ||
26 | + case 'wxMiniProgram': | ||
27 | + $this->app = Factory::miniProgram($this->config); | ||
28 | + break; | ||
29 | + } | ||
30 | + | ||
31 | + } | ||
32 | + | ||
33 | + // 返回实例 | ||
34 | + public function getApp() { | ||
35 | + return $this->app; | ||
36 | + } | ||
37 | + | ||
38 | + //小程序:获取openid&session_key | ||
39 | + public function code($code) | ||
40 | + { | ||
41 | + return $this->app->auth->session($code); | ||
42 | + } | ||
43 | + | ||
44 | + public function oauth() | ||
45 | + { | ||
46 | + $oauth = $this->app->oauth; | ||
47 | + return $oauth; | ||
48 | + } | ||
49 | + | ||
50 | + //解密信息 | ||
51 | + public function decryptData($session, $iv, $encryptData) | ||
52 | + { | ||
53 | + $data = $this->app->encryptor->decryptData($session, $iv, $encryptData); | ||
54 | + | ||
55 | + return $data; | ||
56 | + } | ||
57 | + | ||
58 | + public function unify($orderBody) | ||
59 | + { | ||
60 | + $result = $this->app->order->unify($orderBody); | ||
61 | + return $result; | ||
62 | + } | ||
63 | + | ||
64 | + public function bridgeConfig($prepayId) | ||
65 | + { | ||
66 | + $jssdk = $this->app->jssdk; | ||
67 | + $config = $jssdk->bridgeConfig($prepayId, false); | ||
68 | + return $config; | ||
69 | + } | ||
70 | + | ||
71 | + public function notify() | ||
72 | + { | ||
73 | + $result = $this->app; | ||
74 | + return $result; | ||
75 | + } | ||
76 | + | ||
77 | + //获取accessToken | ||
78 | + public function getAccessToken() | ||
79 | + { | ||
80 | + $accessToken = $this->app->access_token; | ||
81 | + $token = $accessToken->getToken(); // token 数组 token['access_token'] 字符串 | ||
82 | + //$token = $accessToken->getToken(true); // 强制重新从微信服务器获取 token. | ||
83 | + return $token; | ||
84 | + } | ||
85 | + | ||
86 | + public function sendTemplateMessage($attributes) | ||
87 | + { | ||
88 | + extract($attributes); | ||
89 | + $this->app->template_message->send([ | ||
90 | + 'touser' => $openId, | ||
91 | + 'template_id' => $templateId, | ||
92 | + 'page' => $page, | ||
93 | + 'form_id' => $formId, | ||
94 | + 'data' => $data, | ||
95 | + 'emphasis_keyword' => $emphasis_keyword | ||
96 | + ]); | ||
97 | + } | ||
98 | + | ||
99 | + | ||
100 | + // 同步小程序直播 | ||
101 | + public function live(Array $params = []) | ||
102 | + { | ||
103 | + $default = [ | ||
104 | + 'start' => 0, | ||
105 | + 'limit' => 10 | ||
106 | + ]; | ||
107 | + $params = array_merge($default, $params); | ||
108 | + $default = json_encode($params); | ||
109 | + | ||
110 | + | ||
111 | + $access_token = $this->app->access_token->getToken(); | ||
112 | + $getRoomsListUrl = "https://api.weixin.qq.com/wxa/business/getliveinfo?access_token={$access_token['access_token']}"; | ||
113 | + $headers = ['Content-type: application/json']; | ||
114 | + $options = [ | ||
115 | + CURLOPT_HTTPHEADER => $headers | ||
116 | + ]; | ||
117 | + $result = Http::sendRequest($getRoomsListUrl, $default, 'POST', $options); | ||
118 | + if (isset($result['ret']) && $result['ret']) { | ||
119 | + $msg = json_decode($result['msg'], true); | ||
120 | + $result = $msg; | ||
121 | + } | ||
122 | + | ||
123 | +// $result = $this->app->live->getRooms(...array_values($params)); | ||
124 | + | ||
125 | + $rooms = []; | ||
126 | + if ($result && $result['errcode'] == 0 && $result['errmsg'] === 'ok') { | ||
127 | + $rooms = $result['room_info']; | ||
128 | + } | ||
129 | + | ||
130 | + return $rooms; | ||
131 | + } | ||
132 | + | ||
133 | + // 小程序直播回放 | ||
134 | + public function liveReplay(array $params = []) | ||
135 | + { | ||
136 | + $default = [ | ||
137 | + 'room_id' => 0, | ||
138 | + 'start' => 0, | ||
139 | + 'limit' => 20 | ||
140 | + ]; | ||
141 | + | ||
142 | + $params = array_merge($default, $params); | ||
143 | + $default = json_encode($params); | ||
144 | + $access_token = $this->app->access_token->getToken(); | ||
145 | + $getPlayBackListUrl = "https://api.weixin.qq.com/wxa/business/getliveinfo?access_token={$access_token['access_token']}"; | ||
146 | + $headers = ['Content-type: application/json']; | ||
147 | + $options = [ | ||
148 | + CURLOPT_HTTPHEADER => $headers | ||
149 | + ]; | ||
150 | + $result = Http::sendRequest($getPlayBackListUrl, $default, 'POST', $options); | ||
151 | + if (isset($result['ret']) && $result['ret']) { | ||
152 | + $msg = json_decode($result['msg'], true); | ||
153 | + $result = $msg; | ||
154 | + } | ||
155 | +// $result = $this->app->live->getPlaybacks(...array_values($params)); | ||
156 | + | ||
157 | + $liveReplay = []; | ||
158 | + if ($result && $result['errcode'] == 0 && $result['errmsg'] === 'ok') { | ||
159 | + $liveReplay = $result['live_replay']; | ||
160 | + } | ||
161 | + | ||
162 | + return $liveReplay; | ||
163 | + } | ||
164 | + | ||
165 | + public function menu($act = 'create', $buttons = '') | ||
166 | + { | ||
167 | + $result = $this->app->menu->$act($buttons); | ||
168 | + return $result; | ||
169 | + | ||
170 | + } | ||
171 | + | ||
172 | + // 公众号 获取所有粉丝 | ||
173 | + public function asyncFans($nextOpenId = null, $currentPage = 1, $totalPage = 1) | ||
174 | + { | ||
175 | + $fans = $this->app->user->list($nextOpenId); | ||
176 | + $openIdsArray = $fans['data']['openid']; | ||
177 | + //放入最大10000条openid队列去执行 | ||
178 | + \think\Queue::push('\addons\groupon\job\Wechat@createQueueByOpenIdsArray', $openIdsArray, 'groupon'); | ||
179 | + //第一次计算总页数 | ||
180 | + if ($currentPage === 1) { | ||
181 | + $totalPage = intval($fans['total'] % $fans['count'] === 0 ? $fans['total'] / $fans['count'] : ceil($fans['total'] / $fans['count'])); | ||
182 | + } | ||
183 | + //有分页 递归下一页 | ||
184 | + if ($currentPage < $totalPage) { | ||
185 | + $openIdsArray = array_merge($openIdsArray, $this->asyncFans($fans['next_openid'], $currentPage++, $totalPage)); | ||
186 | + } | ||
187 | + if ($currentPage == $totalPage) { | ||
188 | + if ($totalPage == 1) { | ||
189 | + $code = 1; | ||
190 | + $msg = '同步成功'; | ||
191 | + }else{ | ||
192 | + $code = 1; | ||
193 | + $msg = '数据较大,请稍后再查看...'; | ||
194 | + } | ||
195 | + return [ | ||
196 | + 'code' => $code, | ||
197 | + 'msg' => $msg | ||
198 | + ]; | ||
199 | + } | ||
200 | + return $openIdsArray; | ||
201 | + } | ||
202 | + | ||
203 | + //通过openid获取已经关注的用户信息 | ||
204 | + public function getSubscribeUserInfoByOpenId(array $openIdsArray) | ||
205 | + { | ||
206 | + $result = $this->app->user->select($openIdsArray); | ||
207 | + return $result; | ||
208 | + } | ||
209 | + | ||
210 | + | ||
211 | + | ||
212 | + | ||
213 | +} |
addons/groupon/library/notify/Notifiable.php
0 → 100644
1 | +<?php | ||
2 | + | ||
3 | +namespace addons\groupon\library\notify; | ||
4 | + | ||
5 | +use addons\groupon\exception\Exception; | ||
6 | +use think\queue\ShouldQueue; | ||
7 | +/** | ||
8 | + * 消息通知 trait | ||
9 | + */ | ||
10 | + | ||
11 | +trait Notifiable | ||
12 | +{ | ||
13 | + public function notify ($notification) { | ||
14 | + return \addons\groupon\library\notify\Notify::send([$this], $notification); | ||
15 | + } | ||
16 | + | ||
17 | +} |
-
请 注册 或 登录 后发表评论