diff --git a/app/Builders/ConsultList.php b/app/Builders/ConsultList.php
index 44aa3f7e..55f27c0f 100644
--- a/app/Builders/ConsultList.php
+++ b/app/Builders/ConsultList.php
@@ -26,6 +26,7 @@ class ConsultList extends Builder
foreach ($consults as $key => $consult) {
$consults[$key]['owner'] = $users[$consult['owner_id']] ?? new \stdClass();
+ $consults[$key]['replier'] = $users[$consult['replier_id']] ?? new \stdClass();
}
return $consults;
@@ -67,7 +68,9 @@ class ConsultList extends Builder
public function getUsers(array $consults)
{
- $ids = kg_array_column($consults, 'owner_id');
+ $ownerIds = kg_array_column($consults, 'owner_id');
+ $replierIds = kg_array_column($consults, 'replier_id');
+ $ids = array_merge($ownerIds, $replierIds);
$userRepo = new UserRepo();
diff --git a/app/Console/Tasks/CleanLogTask.php b/app/Console/Tasks/CleanLogTask.php
index b4dd7ee9..d4d532c7 100644
--- a/app/Console/Tasks/CleanLogTask.php
+++ b/app/Console/Tasks/CleanLogTask.php
@@ -13,6 +13,7 @@ class CleanLogTask extends Task
$this->cleanSqlLog();
$this->cleanListenLog();
$this->cleanCaptchaLog();
+ $this->cleanWechatLog();
$this->cleanMailLog();
$this->cleanSmsLog();
$this->cleanVodLog();
@@ -22,6 +23,7 @@ class CleanLogTask extends Task
$this->cleanWxpayLog();
$this->cleanOrderLog();
$this->cleanRefundLog();
+ $this->cleanNoticeLog();
}
/**
@@ -112,6 +114,14 @@ class CleanLogTask extends Task
$this->cleanLog('mail', 7);
}
+ /**
+ * 清理微信服务日志
+ */
+ protected function cleanWechatLog()
+ {
+ $this->cleanLog('wechat', 7);
+ }
+
/**
* 清理阿里支付服务日志
*/
@@ -144,6 +154,14 @@ class CleanLogTask extends Task
$this->cleanLog('refund', 30);
}
+ /**
+ * 清理通知日志
+ */
+ protected function cleanNoticeLog()
+ {
+ $this->cleanLog('notice', 7);
+ }
+
/**
* 清理日志文件
*
diff --git a/app/Console/Tasks/DeliverTask.php b/app/Console/Tasks/DeliverTask.php
index 1895ce26..560c8449 100644
--- a/app/Console/Tasks/DeliverTask.php
+++ b/app/Console/Tasks/DeliverTask.php
@@ -12,7 +12,7 @@ use App\Repos\ImGroup as ImGroupRepo;
use App\Repos\ImGroupUser as ImGroupUserRepo;
use App\Repos\Order as OrderRepo;
use App\Repos\User as UserRepo;
-use App\Services\Sms\Order as OrderSms;
+use App\Services\Logic\Notice\OrderFinish as OrderFinishNotice;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
@@ -84,7 +84,7 @@ class DeliverTask extends Task
}
if ($task->status == TaskModel::STATUS_FINISHED) {
- $this->handleOrderNotice($order);
+ $this->handleOrderFinishNotice($order);
} elseif ($task->status == TaskModel::STATUS_FAILED) {
$this->handleOrderRefund($order);
}
@@ -199,11 +199,11 @@ class DeliverTask extends Task
}
}
- protected function handleOrderNotice(OrderModel $order)
+ protected function handleOrderFinishNotice(OrderModel $order)
{
- $sms = new OrderSms();
+ $notice = new OrderFinishNotice();
- $sms->handle($order);
+ $notice->createTask($order);
}
protected function handleOrderRefund(OrderModel $order)
diff --git a/app/Console/Tasks/LiveNotifyTask.php b/app/Console/Tasks/LiveNotifyTask.php
deleted file mode 100644
index ab6e2241..00000000
--- a/app/Console/Tasks/LiveNotifyTask.php
+++ /dev/null
@@ -1,81 +0,0 @@
-getRedis();
-
- $service = new LiveNotifyService();
-
- $key = $service->getNotifyKey();
-
- $chapterIds = $redis->sMembers($key);
-
- if (!$chapterIds) return;
-
- $sentKey = $service->getSentNotifyKey();
-
- $sentChapterIds = $redis->sMembers($sentKey);
-
- foreach ($chapterIds as $chapterId) {
- if (!in_array($chapterId, $sentChapterIds)) {
- $this->sendNotification($chapterId);
- } else {
- $redis->sAdd($sentKey, $chapterId);
- }
- }
-
- if ($redis->sCard($sentKey) == 1) {
- $redis->expire($sentKey, 86400);
- }
- }
-
- protected function sendNotification($chapterId)
- {
- $chapterRepo = new ChapterRepo();
-
- $chapterLive = $chapterRepo->findChapterLive($chapterId);
-
- if (!$chapterLive) return;
-
- $targetUserIds = $this->findTargetUserIds($chapterLive->course_id);
-
- if (!$targetUserIds) return;
-
- $sms = new LiveSms();
-
- foreach ($targetUserIds as $userId) {
- $sms->handle($chapterId, $userId, $chapterLive->start_time);
- }
- }
-
- protected function findTargetUserIds($courseId)
- {
- $sourceTypes = [
- CourseUserModel::SOURCE_CHARGE,
- CourseUserModel::SOURCE_VIP,
- ];
-
- $rows = CourseUserModel::query()
- ->where('course_id = :course_id:', ['course_id' => $courseId])
- ->andWhere('role_type = :role_type:', ['role_type' => CourseUserModel::ROLE_STUDENT])
- ->inWhere('source_type', $sourceTypes)
- ->execute();
-
- if ($rows->count() == 0) {
- return [];
- }
-
- return kg_array_column($rows->toArray(), 'user_id');
- }
-
-}
diff --git a/app/Console/Tasks/MaintainTask.php b/app/Console/Tasks/MaintainTask.php
index 9ac60365..7f6d5898 100644
--- a/app/Console/Tasks/MaintainTask.php
+++ b/app/Console/Tasks/MaintainTask.php
@@ -19,7 +19,7 @@ class MaintainTask extends Task
* 重建首页课程缓存
*
* @param array $params
- * @command: php console.php maintain reset_index_course_cache
+ * @command: php console.php maintain rebuild_index_course_cache
*/
public function rebuildIndexCourseCacheAction($params)
{
diff --git a/app/Console/Tasks/NoticeTask.php b/app/Console/Tasks/NoticeTask.php
new file mode 100644
index 00000000..4c69fcf6
--- /dev/null
+++ b/app/Console/Tasks/NoticeTask.php
@@ -0,0 +1,137 @@
+getLogger('notice');
+
+ $tasks = $this->findTasks(500);
+
+ if ($tasks->count() == 0) {
+ return;
+ }
+
+ foreach ($tasks as $task) {
+
+ try {
+
+ switch ($task->item_type) {
+ case TaskModel::TYPE_NOTICE_ACCOUNT_LOGIN:
+ $this->handleAccountLoginNotice($task);
+ break;
+ case TaskModel::TYPE_NOTICE_LIVE_BEGIN:
+ $this->handleLiveBeginNotice($task);
+ break;
+ case TaskModel::TYPE_NOTICE_ORDER_FINISH:
+ $this->handleOrderFinishNotice($task);
+ break;
+ case TaskModel::TYPE_NOTICE_REFUND_FINISH:
+ $this->handleRefundFinishNotice($task);
+ break;
+ case TaskModel::TYPE_NOTICE_CONSULT_REPLY:
+ $this->handleConsultReplyNotice($task);
+ break;
+ }
+
+ $task->status = TaskModel::STATUS_FINISHED;
+
+ $task->update();
+
+ } catch (\Exception $e) {
+
+ $task->try_count += 1;
+ $task->priority += 1;
+
+ if ($task->try_count > self::TRY_COUNT) {
+ $task->status = TaskModel::STATUS_FAILED;
+ }
+
+ $task->update();
+
+ $logger->info('Notice Process Exception ' . kg_json_encode([
+ 'code' => $e->getCode(),
+ 'message' => $e->getMessage(),
+ 'task' => $task->toArray(),
+ ]));
+ }
+ }
+ }
+
+ protected function handleAccountLoginNotice(TaskModel $task)
+ {
+ $notice = new AccountLoginNotice();
+
+ return $notice->handleTask($task);
+ }
+
+ protected function handleLiveBeginNotice(TaskModel $task)
+ {
+ $notice = new LiveBeginNotice();
+
+ return $notice->handleTask($task);
+ }
+
+ protected function handleOrderFinishNotice(TaskModel $task)
+ {
+ $notice = new OrderFinishNotice();
+
+ return $notice->handleTask($task);
+ }
+
+ protected function handleRefundFinishNotice(TaskModel $task)
+ {
+ $notice = new RefundFinishNotice();
+
+ return $notice->handleTask($task);
+ }
+
+ protected function handleConsultReplyNotice(TaskModel $task)
+ {
+ $notice = new ConsultReplyNotice();
+
+ return $notice->handleTask($task);
+ }
+
+ /**
+ * @param int $limit
+ * @return ResultsetInterface|Resultset|TaskModel[]
+ */
+ protected function findTasks($limit = 100)
+ {
+ $itemTypes = [
+ TaskModel::TYPE_NOTICE_ACCOUNT_LOGIN,
+ TaskModel::TYPE_NOTICE_LIVE_BEGIN,
+ TaskModel::TYPE_NOTICE_ORDER_FINISH,
+ TaskModel::TYPE_NOTICE_REFUND_FINISH,
+ TaskModel::TYPE_NOTICE_CONSULT_REPLY,
+ ];
+
+ $status = TaskModel::STATUS_PENDING;
+
+ $tryCount = self::TRY_COUNT;
+
+ return TaskModel::query()
+ ->inWhere('item_type', $itemTypes)
+ ->andWhere('status = :status:', ['status' => $status])
+ ->andWhere('try_count < :try_count:', ['try_count' => $tryCount + 1])
+ ->orderBy('priority ASC')
+ ->limit($limit)
+ ->execute();
+ }
+
+}
diff --git a/app/Console/Tasks/RefundTask.php b/app/Console/Tasks/RefundTask.php
index 0edf1a67..ad69ec3c 100644
--- a/app/Console/Tasks/RefundTask.php
+++ b/app/Console/Tasks/RefundTask.php
@@ -11,9 +11,9 @@ use App\Repos\Order as OrderRepo;
use App\Repos\Refund as RefundRepo;
use App\Repos\Trade as TradeRepo;
use App\Repos\User as UserRepo;
+use App\Services\Logic\Notice\RefundFinish as RefundFinishNotice;
use App\Services\Pay\Alipay as AlipayService;
use App\Services\Pay\Wxpay as WxpayService;
-use App\Services\Sms\Refund as RefundSms;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
@@ -95,7 +95,7 @@ class RefundTask extends Task
$this->db->commit();
- $this->handleRefundNotice($refund);
+ $this->handleRefundFinishNotice($refund);
} catch (\Exception $e) {
@@ -281,11 +281,11 @@ class RefundTask extends Task
/**
* @param RefundModel $refund
*/
- protected function handleRefundNotice(RefundModel $refund)
+ protected function handleRefundFinishNotice(RefundModel $refund)
{
- $sms = new RefundSms();
+ $notice = new RefundFinishNotice();
- $sms->handle($refund);
+ $notice->createTask($refund);
}
/**
diff --git a/app/Console/Tasks/Task.php b/app/Console/Tasks/Task.php
index 350cb5ec..75944d41 100644
--- a/app/Console/Tasks/Task.php
+++ b/app/Console/Tasks/Task.php
@@ -30,7 +30,7 @@ class Task extends \Phalcon\Cli\Task
return $appService->getRedis();
}
- public function getLogger($channel = null)
+ public function getLogger($channel = 'console')
{
$appService = new AppService();
diff --git a/app/Http/Admin/Controllers/SettingController.php b/app/Http/Admin/Controllers/SettingController.php
index 7452c717..309d6bd8 100644
--- a/app/Http/Admin/Controllers/SettingController.php
+++ b/app/Http/Admin/Controllers/SettingController.php
@@ -340,13 +340,13 @@ class SettingController extends Controller
$data = $this->request->getPost();
- $settingService->updateSettings($section, $data);
+ $settingService->updateWechatSettings($section, $data);
return $this->jsonSuccess(['msg' => '更新配置成功']);
} else {
- $oa = $settingService->getWeChatOASettings();
+ $oa = $settingService->getWechatOASettings();
$this->view->setVar('oa', $oa);
}
diff --git a/app/Http/Admin/Services/Consult.php b/app/Http/Admin/Services/Consult.php
index 8625cf86..667b99a7 100644
--- a/app/Http/Admin/Services/Consult.php
+++ b/app/Http/Admin/Services/Consult.php
@@ -4,8 +4,10 @@ namespace App\Http\Admin\Services;
use App\Builders\ConsultList as ConsultListBuilder;
use App\Library\Paginator\Query as PagerQuery;
+use App\Models\Consult as ConsultModel;
use App\Repos\Consult as ConsultRepo;
use App\Repos\Course as CourseRepo;
+use App\Services\Logic\Notice\ConsultReply as ConsultReplyNotice;
use App\Validators\Consult as ConsultValidator;
class Consult extends Service
@@ -52,12 +54,18 @@ class Consult extends Service
$data = [];
+ $firstReply = false;
+
if (!empty($post['question'])) {
$data['question'] = $validator->checkQuestion($post['question']);
}
if (!empty($post['answer'])) {
$data['answer'] = $validator->checkAnswer($post['answer']);
+ $data['reply_time'] = time();
+ if ($consult->reply_time == 0) {
+ $firstReply = true;
+ }
}
if (isset($post['private'])) {
@@ -70,6 +78,10 @@ class Consult extends Service
$consult->update($data);
+ if ($firstReply) {
+ $this->handleReplyNotice($consult);
+ }
+
return $consult;
}
@@ -107,6 +119,13 @@ class Consult extends Service
$course->update();
}
+ protected function handleReplyNotice(ConsultModel $consult)
+ {
+ $notice = new ConsultReplyNotice();
+
+ $notice->createTask($consult);
+ }
+
protected function findOrFail($id)
{
$validator = new ConsultValidator();
diff --git a/app/Http/Admin/Services/Session.php b/app/Http/Admin/Services/Session.php
index 2bff96d1..fae5222b 100644
--- a/app/Http/Admin/Services/Session.php
+++ b/app/Http/Admin/Services/Session.php
@@ -2,7 +2,9 @@
namespace App\Http\Admin\Services;
+use App\Models\User as UserModel;
use App\Services\Auth\Admin as AdminAuth;
+use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
use App\Validators\Account as AccountValidator;
use App\Validators\Captcha as CaptchaValidator;
@@ -45,6 +47,8 @@ class Session extends Service
$captchaValidator->checkCode($post['ticket'], $post['rand']);
}
+ $this->handleLoginNotice($user);
+
$this->auth->saveAuthInfo($user);
}
@@ -53,4 +57,11 @@ class Session extends Service
$this->auth->clearAuthInfo();
}
+ protected function handleLoginNotice(UserModel $user)
+ {
+ $service = new AccountLoginNoticeService();
+
+ $service->createTask($user);
+ }
+
}
diff --git a/app/Http/Admin/Services/Setting.php b/app/Http/Admin/Services/Setting.php
index 3b744ad8..3f2abe3e 100644
--- a/app/Http/Admin/Services/Setting.php
+++ b/app/Http/Admin/Services/Setting.php
@@ -57,7 +57,7 @@ class Setting extends Service
return $wxpay;
}
- public function getWeChatOASettings()
+ public function getWechatOASettings()
{
$oa = $this->getSettings('wechat.oa');
@@ -154,7 +154,9 @@ class Setting extends Service
public function updateSmsSettings($section, $settings)
{
- $settings['template'] = kg_json_encode($settings['template']);
+ if (isset($settings['template'])) {
+ $settings['template'] = kg_json_encode($settings['template']);
+ }
$this->updateSettings($section, $settings);
}
@@ -170,4 +172,15 @@ class Setting extends Service
}
}
+ public function updateWechatSettings($section, $settings)
+ {
+ if ($section == 'wechat.oa') {
+ if (isset($settings['notice_template'])) {
+ $settings['notice_template'] = kg_json_encode($settings['notice_template']);
+ }
+ }
+
+ $this->updateSettings($section, $settings);
+ }
+
}
diff --git a/app/Http/Admin/Views/order/list.volt b/app/Http/Admin/Views/order/list.volt
index fb154b05..8b6a39b3 100644
--- a/app/Http/Admin/Views/order/list.volt
+++ b/app/Http/Admin/Views/order/list.volt
@@ -36,7 +36,7 @@
{% set show_url = url({'for':'admin.order.show','id':item.id}) %}
- 商品:{{ item.subject }} {{ item_type(item.item_type) }}
+ 商品:{{ item.subject }}
单号:{{ item.sn }}
|
diff --git a/app/Http/Admin/Views/setting/sms.volt b/app/Http/Admin/Views/setting/sms.volt
index dbddfc49..8601b0a2 100644
--- a/app/Http/Admin/Views/setting/sms.volt
+++ b/app/Http/Admin/Views/setting/sms.volt
@@ -53,21 +53,27 @@
|
订单通知 |
- |
- |
- 复制 |
+ |
+ |
+ 复制 |
退款通知 |
- |
- |
- 复制 |
+ |
+ |
+ 复制 |
- 直播通知 |
- |
- |
- 复制 |
+ 直播提醒 |
+ |
+ |
+ 复制 |
+
+
+ 回复通知 |
+ |
+ |
+ 复制 |
diff --git a/app/Http/Admin/Views/setting/wechat_oa.volt b/app/Http/Admin/Views/setting/wechat_oa.volt
index c430775b..efc70be5 100644
--- a/app/Http/Admin/Views/setting/wechat_oa.volt
+++ b/app/Http/Admin/Views/setting/wechat_oa.volt
@@ -1,6 +1,8 @@
+{% set notice_template = oa.notice_template|json_decode %}
+
+
+
\ No newline at end of file
diff --git a/app/Http/Api/Services/Account.php b/app/Http/Api/Services/Account.php
index baf537f8..9ce43137 100644
--- a/app/Http/Api/Services/Account.php
+++ b/app/Http/Api/Services/Account.php
@@ -2,9 +2,11 @@
namespace App\Http\Api\Services;
+use App\Models\User as UserModel;
use App\Repos\User as UserRepo;
use App\Services\Auth\Api as AuthService;
use App\Services\Logic\Account\Register as RegisterService;
+use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
use App\Validators\Account as AccountValidator;
class Account extends Service
@@ -50,6 +52,8 @@ class Account extends Service
$user = $validator->checkUserLogin($post['account'], $post['password']);
+ $this->handleLoginNotice($user);
+
return $this->auth->saveAuthInfo($user);
}
@@ -70,6 +74,8 @@ class Account extends Service
$user = $validator->checkVerifyLogin($post['account'], $post['verify_code']);
+ $this->handleLoginNotice($user);
+
return $this->auth->saveAuthInfo($user);
}
@@ -78,4 +84,11 @@ class Account extends Service
$this->auth->clearAuthInfo();
}
+ protected function handleLoginNotice(UserModel $user)
+ {
+ $service = new AccountLoginNoticeService();
+
+ $service->createTask($user);
+ }
+
}
diff --git a/app/Http/Home/Controllers/UserConsoleController.php b/app/Http/Home/Controllers/UserConsoleController.php
index 2b56c475..12ed2de5 100644
--- a/app/Http/Home/Controllers/UserConsoleController.php
+++ b/app/Http/Home/Controllers/UserConsoleController.php
@@ -2,6 +2,7 @@
namespace App\Http\Home\Controllers;
+use App\Repos\WechatSubscribe as WechatSubscribeRepo;
use App\Services\Logic\Account\OAuthProvider as OAuthProviderService;
use App\Services\Logic\User\Console\AccountInfo as AccountInfoService;
use App\Services\Logic\User\Console\ConnectDelete as ConnectDeleteService;
@@ -36,6 +37,15 @@ class UserConsoleController extends Controller
return true;
}
+ public function initialize()
+ {
+ parent::initialize();
+
+ $wechatOA = $this->getSettings('wechat.oa');
+
+ $this->view->setVar('wechat_oa', $wechatOA);
+ }
+
/**
* @Get("/", name="home.uc.index")
*/
@@ -201,6 +211,25 @@ class UserConsoleController extends Controller
$this->view->setVar('pager', $pager);
}
+ /**
+ * @Get("/subscribe", name="home.uc.subscribe")
+ */
+ public function subscribeAction()
+ {
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($this->authUser->id);
+
+ $subscribed = 0;
+
+ if ($subscribe) {
+ $subscribed = $subscribe->deleted == 0 ? 1 : 0;
+ }
+
+ $this->view->pick('user/console/subscribe');
+ $this->view->setVar('subscribed', $subscribed);
+ }
+
/**
* @Post("/profile/update", name="home.uc.update_profile")
*/
diff --git a/app/Http/Home/Controllers/WeChatOfficialAccountController.php b/app/Http/Home/Controllers/WeChatOfficialAccountController.php
deleted file mode 100644
index e62bddc9..00000000
--- a/app/Http/Home/Controllers/WeChatOfficialAccountController.php
+++ /dev/null
@@ -1,40 +0,0 @@
-getOfficialAccount();
-
- $response = $app->server->serve();
-
- $response->send();
-
- exit;
- }
-
- /**
- * @Post("/notify", name="home.wechat.oa.notify")
- */
- public function notifyAction()
- {
-
- }
-
-}
diff --git a/app/Http/Home/Controllers/WechatOfficialAccountController.php b/app/Http/Home/Controllers/WechatOfficialAccountController.php
new file mode 100644
index 00000000..223170e7
--- /dev/null
+++ b/app/Http/Home/Controllers/WechatOfficialAccountController.php
@@ -0,0 +1,76 @@
+getSubscribeStatus();
+
+ return $this->jsonSuccess(['status' => $status]);
+ }
+
+ /**
+ * @Get("/subscribe/qrcode", name="home.wechat.oa.sub_qrcode")
+ */
+ public function subscribeQrCodeAction()
+ {
+ $service = new WechatOAService();
+
+ $qrcode = $service->createSubscribeQrCode();
+
+ return $this->jsonSuccess(['qrcode' => $qrcode]);
+ }
+
+ /**
+ * @Get("/notify", name="home.wechat.oa.verify")
+ */
+ public function verifyAction()
+ {
+ $service = new WechatOAService();
+
+ $app = $service->getOfficialAccount();
+
+ $response = $app->server->serve();
+
+ $response->send();
+
+ exit;
+ }
+
+ /**
+ * @Post("/notify", name="home.wechat.oa.notify")
+ */
+ public function notifyAction()
+ {
+ $service = new WechatOAService();
+
+ $app = $service->getOfficialAccount();
+
+ $app->server->push(function ($message) use ($service) {
+ return $service->handleNotify($message);
+ });
+
+ $response = $app->server->serve();
+
+ $response->send();
+
+ exit;
+ }
+
+}
diff --git a/app/Http/Home/Services/Account.php b/app/Http/Home/Services/Account.php
index 38efb3b2..7f7fb06f 100644
--- a/app/Http/Home/Services/Account.php
+++ b/app/Http/Home/Services/Account.php
@@ -2,9 +2,11 @@
namespace App\Http\Home\Services;
+use App\Models\User as UserModel;
use App\Repos\User as UserRepo;
use App\Services\Auth\Home as AuthService;
use App\Services\Logic\Account\Register as RegisterService;
+use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
use App\Validators\Account as AccountValidator;
use App\Validators\Captcha as CaptchaValidator;
@@ -48,6 +50,8 @@ class Account extends Service
$validator->checkCode($post['ticket'], $post['rand']);
+ $this->handleLoginNotice($user);
+
$this->auth->saveAuthInfo($user);
}
@@ -59,6 +63,8 @@ class Account extends Service
$user = $validator->checkVerifyLogin($post['account'], $post['verify_code']);
+ $this->handleLoginNotice($user);
+
$this->auth->saveAuthInfo($user);
}
@@ -67,4 +73,11 @@ class Account extends Service
$this->auth->clearAuthInfo();
}
+ protected function handleLoginNotice(UserModel $user)
+ {
+ $service = new AccountLoginNoticeService();
+
+ $service->createTask($user);
+ }
+
}
diff --git a/app/Http/Home/Services/WeChatOfficialAccount.php b/app/Http/Home/Services/WeChatOfficialAccount.php
deleted file mode 100644
index a6173e16..00000000
--- a/app/Http/Home/Services/WeChatOfficialAccount.php
+++ /dev/null
@@ -1,17 +0,0 @@
-getOfficialAccount();
- }
-
-}
diff --git a/app/Http/Home/Services/WechatOfficialAccount.php b/app/Http/Home/Services/WechatOfficialAccount.php
new file mode 100644
index 00000000..b205ccee
--- /dev/null
+++ b/app/Http/Home/Services/WechatOfficialAccount.php
@@ -0,0 +1,233 @@
+getOfficialAccount();
+ }
+
+ public function createSubscribeQrCode()
+ {
+ $user = $this->getLoginUser();
+
+ $app = $this->getOfficialAccount();
+
+ $result = $app->qrcode->temporary($user->id);
+
+ return $app->qrcode->url($result['ticket']);
+ }
+
+ public function getSubscribeStatus()
+ {
+ $user = $this->getLoginUser();
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($user->id);
+
+ $status = 0;
+
+ if ($subscribe) {
+ $status = $subscribe->deleted == 0 ? 1 : 0;
+ }
+
+ return $status;
+ }
+
+ public function handleNotify($message)
+ {
+ $service = new WechatService();
+
+ $service->logger->info('Received Message:' . json_encode($message));
+
+ switch ($message['MsgType']) {
+ case 'event':
+ switch ($message['Event']) {
+ case 'subscribe':
+ return $this->handleSubscribeEvent($message);
+ break;
+ case 'unsubscribe':
+ return $this->handleUnsubscribeEvent($message);
+ break;
+ case 'SCAN':
+ return $this->handleScanEvent($message);
+ break;
+ case 'CLICK':
+ return $this->handleClickEvent($message);
+ break;
+ case 'VIEW':
+ return $this->handleViewEvent($message);
+ break;
+ case 'LOCATION':
+ return $this->handleLocationEvent($message);
+ break;
+ default:
+ return $message['Event'];
+ break;
+ }
+ break;
+ case 'text':
+ return $this->handleTextReply($message);
+ break;
+ case 'image':
+ return $this->handleImageReply($message);
+ break;
+ case 'voice':
+ return $this->handleVoiceReply($message);
+ break;
+ case 'video':
+ return $this->handleVideoReply($message);
+ break;
+ case 'shortvideo':
+ return $this->handleShortVideoReply($message);
+ break;
+ case 'location':
+ return $this->handleLocationReply($message);
+ break;
+ case 'link':
+ return $this->handleLinkReply($message);
+ break;
+ default:
+ return $this->emptyReplyMessage();
+ break;
+ }
+ }
+
+ protected function handleSubscribeEvent($message)
+ {
+ $openId = $message['FromUserName'] ?? '';
+ $eventKey = $message['EventKey'] ?? '';
+
+ if (!$eventKey) {
+ return $this->emptyReplyMessage();
+ }
+
+ $userId = str_replace('qrscene_', '', $eventKey);
+
+ $this->handleSubscribeRelation($userId, $openId);
+
+ return new TextMessage("欢迎您的光临!");
+ }
+
+ protected function handleUnsubscribeEvent($message)
+ {
+ $openId = $message['FromUserName'] ?? '';
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByOpenId($openId);
+
+ if ($subscribe) {
+ $subscribe->deleted = 1;
+ $subscribe->update();
+ }
+
+ return new TextMessage("我们又少了一个可爱的小伙伴!");
+ }
+
+ protected function handleScanEvent($message)
+ {
+ /**
+ * 注意:当已关注过用户扫码时,"EventKey"没有带"qrscene_"前缀
+ */
+ $openId = $message['FromUserName'] ?? '';
+ $eventKey = $message['EventKey'] ?? '';
+ $userId = $eventKey;
+
+ $this->handleSubscribeRelation($userId, $openId);
+ }
+
+ protected function handleClickEvent($message)
+ {
+ }
+
+ protected function handleViewEvent($message)
+ {
+ }
+
+ protected function handleLocationEvent($message)
+ {
+ }
+
+ protected function handleTextReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function handleImageReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function handleVoiceReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function handleVideoReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function handleShortVideoReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function handleLocationReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function handleLinkReply($message)
+ {
+ return $this->defaultReplyMessage();
+ }
+
+ protected function emptyReplyMessage()
+ {
+ return new TextMessage("");
+ }
+
+ protected function defaultReplyMessage()
+ {
+ return new TextMessage("没有匹配的服务,如有需要请联系客服!");
+ }
+
+ protected function handleSubscribeRelation($userId, $openId)
+ {
+ $validator = new UserValidator();
+ $validator->checkUser($userId);
+
+ $subscribeRepo = new WechatSubscribeRepo();
+ $subscribe = $subscribeRepo->findByOpenId($openId);
+
+ if ($subscribe) {
+ if ($subscribe->deleted == 1) {
+ $subscribe->deleted = 0;
+ $subscribe->update();
+ }
+ } else {
+ $subscribe = $subscribeRepo->findSubscribe($userId, $openId);
+ if (!$subscribe) {
+ $subscribe = new WechatSubscribeModel();
+ $subscribe->user_id = $userId;
+ $subscribe->open_id = $openId;
+ $subscribe->create();
+ }
+ }
+ }
+
+}
diff --git a/app/Http/Home/Views/user/console/menu.volt b/app/Http/Home/Views/user/console/menu.volt
index cc8ed6ac..e670e951 100644
--- a/app/Http/Home/Views/user/console/menu.volt
+++ b/app/Http/Home/Views/user/console/menu.volt
@@ -52,6 +52,9 @@
\ No newline at end of file
diff --git a/app/Http/Home/Views/user/console/subscribe.volt b/app/Http/Home/Views/user/console/subscribe.volt
new file mode 100644
index 00000000..1fe6a2c7
--- /dev/null
+++ b/app/Http/Home/Views/user/console/subscribe.volt
@@ -0,0 +1,33 @@
+{% extends 'templates/main.volt' %}
+
+{% block content %}
+
+
+
+
+
+
+ 关注订阅
+
+
+ {% if subscribed == 0 %}
+
+
订阅官方公众号,接收重要通知!
+ {% else %}
+
你已经订阅官方公众号
+ {% endif %}
+
+
+
+
+
+
+
+
+{% endblock %}
+
+{% block include_js %}
+
+ {{ js_include('home/js/user.console.subscribe.js') }}
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/Models/Consult.php b/app/Models/Consult.php
index a790c650..31ea904d 100644
--- a/app/Models/Consult.php
+++ b/app/Models/Consult.php
@@ -36,12 +36,19 @@ class Consult extends Model
public $chapter_id;
/**
- * 用户编号
+ * 提主编号
*
* @var int
*/
public $owner_id;
+ /**
+ * 答主编号
+ *
+ * @var int
+ */
+ public $replier_id;
+
/**
* 提问
*
diff --git a/app/Models/Task.php b/app/Models/Task.php
index 45890752..dd85bb59 100644
--- a/app/Models/Task.php
+++ b/app/Models/Task.php
@@ -11,6 +11,12 @@ class Task extends Model
const TYPE_DELIVER = 1; // 发货
const TYPE_REFUND = 2; // 退款
+ const TYPE_NOTICE_ACCOUNT_LOGIN = 11; // 帐号登录通知
+ const TYPE_NOTICE_LIVE_BEGIN = 12; // 直播开始通知
+ const TYPE_NOTICE_ORDER_FINISH = 13; // 订单完成通知
+ const TYPE_NOTICE_REFUND_FINISH = 14; // 退款完成通知
+ const TYPE_NOTICE_CONSULT_REPLY = 15; // 咨询回复通知
+
/**
* 优先级
*/
diff --git a/app/Models/WeChatSubscribe.php b/app/Models/WechatSubscribe.php
similarity index 96%
rename from app/Models/WeChatSubscribe.php
rename to app/Models/WechatSubscribe.php
index f1ce2201..e1633caa 100644
--- a/app/Models/WeChatSubscribe.php
+++ b/app/Models/WechatSubscribe.php
@@ -4,7 +4,7 @@ namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
-class WeChatSubscribe extends Model
+class WechatSubscribe extends Model
{
/**
diff --git a/app/Repos/CourseUser.php b/app/Repos/CourseUser.php
index 12704ac5..01ece420 100644
--- a/app/Repos/CourseUser.php
+++ b/app/Repos/CourseUser.php
@@ -146,4 +146,16 @@ class CourseUser extends Repository
->execute();
}
+ /**
+ * @param int $courseId
+ * @return ResultsetInterface|Resultset|CourseUserModel[]
+ */
+ public function findByCourseId($courseId)
+ {
+ return CourseUserModel::query()
+ ->where('course_id = :course_id:', ['course_id' => $courseId])
+ ->andWhere('deleted = 0')
+ ->execute();
+ }
+
}
diff --git a/app/Repos/WechatSubscribe.php b/app/Repos/WechatSubscribe.php
new file mode 100644
index 00000000..2043d889
--- /dev/null
+++ b/app/Repos/WechatSubscribe.php
@@ -0,0 +1,57 @@
+ 'user_id= ?1 AND open_id = ?2',
+ 'bind' => [1 => $userId, 2 => $openId],
+ ]);
+ }
+
+ /**
+ * @param int $id
+ * @return WechatSubscribeModel|Model|bool
+ */
+ public function findById($id)
+ {
+ return WechatSubscribeModel::findFirst($id);
+ }
+
+ /**
+ * @param int $userId
+ * @return WechatSubscribeModel|Model|bool
+ */
+ public function findByUserId($userId)
+ {
+ return WechatSubscribeModel::findFirst([
+ 'conditions' => 'user_id = :user_id:',
+ 'bind' => ['user_id' => $userId],
+ ]);
+ }
+
+ /**
+ * @param string $openId
+ * @return WechatSubscribeModel|Model|bool
+ */
+ public function findByOpenId($openId)
+ {
+ return WechatSubscribeModel::findFirst([
+ 'conditions' => 'open_id = :open_id:',
+ 'bind' => ['open_id' => $openId],
+ ]);
+ }
+
+}
diff --git a/app/Services/Auth/Mobile.php b/app/Services/Auth/Mobile.php
deleted file mode 100644
index 5f94bcb4..00000000
--- a/app/Services/Auth/Mobile.php
+++ /dev/null
@@ -1,44 +0,0 @@
-getAuthKey();
-
- $authInfo = [
- 'id' => $user->id,
- 'name' => $user->name,
- ];
-
- $this->session->set($authKey, $authInfo);
- }
-
- public function clearAuthInfo()
- {
- $authKey = $this->getAuthKey();
-
- $this->session->remove($authKey);
- }
-
- public function getAuthInfo()
- {
- $authKey = $this->getAuthKey();
-
- $authInfo = $this->session->get($authKey);
-
- return $authInfo ?: null;
- }
-
- public function getAuthKey()
- {
- return 'mobile_auth_info';
- }
-
-}
diff --git a/app/Services/LiveNotify.php b/app/Services/LiveNotify.php
index ef1fd11d..edf7982d 100644
--- a/app/Services/LiveNotify.php
+++ b/app/Services/LiveNotify.php
@@ -5,6 +5,8 @@ namespace App\Services;
use App\Models\Chapter as ChapterModel;
use App\Models\ChapterLive as ChapterLiveModel;
use App\Repos\Chapter as ChapterRepo;
+use App\Repos\CourseUser as CourseUserRepo;
+use App\Services\Logic\Notice\LiveBegin as LiveBeginNotice;
class LiveNotify extends Service
{
@@ -42,16 +44,6 @@ class LiveNotify extends Service
return $result;
}
- public function getNotifyKey()
- {
- return 'live_notify';
- }
-
- public function getSentNotifyKey()
- {
- return 'live_notify_sent';
- }
-
/**
* 推流
*/
@@ -73,7 +65,7 @@ class LiveNotify extends Service
$chapterLive->update(['status' => ChapterLiveModel::STATUS_ACTIVE]);
- $this->sendBeginNotify($chapter);
+ $this->handleStreamBeginNotice($chapter);
return true;
}
@@ -126,15 +118,21 @@ class LiveNotify extends Service
}
- protected function sendBeginNotify(ChapterModel $chapter)
+ protected function handleStreamBeginNotice(ChapterModel $chapter)
{
- $redis = $this->getRedis();
+ $courseUserRepo = new CourseUserRepo();
- $key = $this->getNotifyKey();
+ $courseUsers = $courseUserRepo->findByCourseId($chapter->course_id);
- $redis->sAdd($key, $chapter->id);
+ if ($courseUsers->count() == 0) {
+ return;
+ }
- $redis->expire($key, 86400);
+ $notice = new LiveBeginNotice();
+
+ foreach ($courseUsers as $courseUser) {
+ $notice->createTask($chapter, $courseUser);
+ }
}
protected function getChapter($streamName)
diff --git a/app/Services/Logic/Consult/ConsultInfo.php b/app/Services/Logic/Consult/ConsultInfo.php
index 52dcf335..f8b5590b 100644
--- a/app/Services/Logic/Consult/ConsultInfo.php
+++ b/app/Services/Logic/Consult/ConsultInfo.php
@@ -37,6 +37,7 @@ class ConsultInfo extends Service
$result['course'] = $this->handleCourseInfo($consult);
$result['chapter'] = $this->handleChapterInfo($consult);
$result['owner'] = $this->handleOwnerInfo($consult);
+ $result['replier'] = $this->handleReplierInfo($consult);
return $result;
}
@@ -85,4 +86,19 @@ class ConsultInfo extends Service
];
}
+ protected function handleReplierInfo(ConsultModel $consult)
+ {
+ $userRepo = new UserRepo();
+
+ $replier = $userRepo->findById($consult->replier_id);
+
+ if (!$replier) return new \stdClass();
+
+ return [
+ 'id' => $replier->id,
+ 'name' => $replier->name,
+ 'avatar' => $replier->avatar,
+ ];
+ }
+
}
diff --git a/app/Services/Logic/Consult/ConsultReply.php b/app/Services/Logic/Consult/ConsultReply.php
index 1b0e457a..25e88371 100644
--- a/app/Services/Logic/Consult/ConsultReply.php
+++ b/app/Services/Logic/Consult/ConsultReply.php
@@ -2,11 +2,13 @@
namespace App\Services\Logic\Consult;
+use App\Models\Consult as ConsultModel;
use App\Services\Logic\ConsultTrait;
-use App\Services\Logic\Service;
+use App\Services\Logic\Notice\ConsultReply as ConsultReplyNotice;
+use App\Services\Logic\Service as LogicService;
use App\Validators\Consult as ConsultValidator;
-class ConsultReply extends Service
+class ConsultReply extends LogicService
{
use ConsultTrait;
@@ -25,12 +27,29 @@ class ConsultReply extends Service
$answer = $validator->checkAnswer($post['answer']);
- $consult->update([
- 'answer' => $answer,
- 'reply_time' => time(),
- ]);
+ $firstReply = false;
+
+ if ($consult->reply_time == 0) {
+ $firstReply = true;
+ }
+
+ $consult->replier_id = $user->id;
+ $consult->reply_time = time();
+ $consult->answer = $answer;
+ $consult->update();
+
+ if ($firstReply) {
+ $this->handleReplyNotice($consult);
+ }
return $consult;
}
+ protected function handleReplyNotice(ConsultModel $consult)
+ {
+ $notice = new ConsultReplyNotice();
+
+ $notice->createTask($consult);
+ }
+
}
diff --git a/app/Services/Logic/Notice/AccountLogin.php b/app/Services/Logic/Notice/AccountLogin.php
new file mode 100644
index 00000000..6ae4b18f
--- /dev/null
+++ b/app/Services/Logic/Notice/AccountLogin.php
@@ -0,0 +1,61 @@
+item_info;
+
+ $userId = $task->item_info['user']['id'];
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($userId);
+
+ if ($subscribe && $subscribe->deleted == 0) {
+
+ $notice = new WechatAccountLoginNotice();
+
+ return $notice->handle($subscribe, $params);
+ }
+ }
+
+ public function createTask(UserModel $user)
+ {
+ $task = new TaskModel();
+
+ $loginIp = $this->getClientIp();
+ $loginRegion = kg_ip2region($loginIp);
+
+ $itemInfo = [
+ 'user' => [
+ 'id' => $user->id,
+ 'name' => $user->name,
+ ],
+ 'login_ip' => $loginIp,
+ 'login_region' => $loginRegion,
+ 'login_time' => time(),
+ ];
+
+ $task->item_id = $user->id;
+ $task->item_info = $itemInfo;
+ $task->item_type = TaskModel::TYPE_NOTICE_ACCOUNT_LOGIN;
+ $task->priority = TaskModel::PRIORITY_LOW;
+ $task->status = TaskModel::STATUS_PENDING;
+
+ $task->create();
+ }
+
+}
diff --git a/app/Services/Logic/Notice/ConsultReply.php b/app/Services/Logic/Notice/ConsultReply.php
new file mode 100644
index 00000000..cdd3c34a
--- /dev/null
+++ b/app/Services/Logic/Notice/ConsultReply.php
@@ -0,0 +1,91 @@
+item_info['consult']['id'];
+
+ $consultRepo = new ConsultRepo();
+
+ $consult = $consultRepo->findById($consultId);
+
+ $courseRepo = new CourseRepo();
+
+ $course = $courseRepo->findById($consult->course_id);
+
+ $userRepo = new UserRepo();
+
+ $user = $userRepo->findById($consult->owner_id);
+
+ $replier = $userRepo->findById($consult->replier_id);
+
+ $params = [
+ 'user' => [
+ 'id' => $user->id,
+ 'name' => $user->name,
+ ],
+ 'replier' => [
+ 'id' => $replier->id,
+ 'name' => $replier->name,
+ ],
+ 'consult' => [
+ 'id' => $consult->id,
+ 'question' => $consult->question,
+ 'answer' => $consult->answer,
+ ],
+ 'course' => [
+ 'id' => $course->id,
+ 'title' => $course->title,
+ ],
+ ];
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($consult->owner_id);
+
+ if ($subscribe && $subscribe->deleted == 0) {
+
+ $notice = new WechatConsultReplyNotice();
+
+ return $notice->handle($subscribe, $params);
+
+ } else {
+
+ $notice = new SmsConsultReplyNotice();
+
+ return $notice->handle($user, $params);
+ }
+ }
+
+ public function createTask(ConsultModel $consult)
+ {
+ $task = new TaskModel();
+
+ $itemInfo = [
+ 'consult' => ['id' => $consult->id],
+ ];
+
+ $task->item_id = $consult->id;
+ $task->item_info = $itemInfo;
+ $task->item_type = TaskModel::TYPE_NOTICE_CONSULT_REPLY;
+ $task->priority = TaskModel::PRIORITY_LOW;
+ $task->status = TaskModel::STATUS_PENDING;
+
+ $task->create();
+ }
+
+}
diff --git a/app/Services/Logic/Notice/LiveBegin.php b/app/Services/Logic/Notice/LiveBegin.php
new file mode 100644
index 00000000..f125c56c
--- /dev/null
+++ b/app/Services/Logic/Notice/LiveBegin.php
@@ -0,0 +1,99 @@
+item_info['course_user'];
+ $chapterId = $task->item_info['chapter']['id'];
+
+ $courseRepo = new CourseRepo();
+
+ $course = $courseRepo->findById($courseUser['course_id']);
+
+ $userRepo = new UserRepo();
+
+ $user = $userRepo->findById($courseUser['user_id']);
+
+ $chapterRepo = new ChapterRepo();
+
+ $chapter = $chapterRepo->findById($chapterId);
+
+ $params = [
+ 'user' => [
+ 'id' => $user->id,
+ 'name' => $user->name,
+ ],
+ 'course' => [
+ 'id' => $course->id,
+ 'title' => $course->title,
+ ],
+ 'chapter' => [
+ 'id' => $chapter->id,
+ 'title' => $chapter->title,
+ ],
+ 'live' => [
+ 'start_time' => $chapter->attrs['start_time'],
+ 'end_time' => $chapter->attrs['end_time'],
+ ],
+ 'course_user' => $courseUser,
+ ];
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($user->id);
+
+ if ($subscribe && $subscribe->deleted == 0) {
+
+ $notice = new WechatLiveBeginNotice();
+
+ return $notice->handle($subscribe, $params);
+
+ } else {
+
+ $notice = new SmsLiveBeginNotice();
+
+ return $notice->handle($user, $params);
+ }
+ }
+
+ public function createTask(ChapterModel $chapter, CourseUserModel $courseUser)
+ {
+ $task = new TaskModel();
+
+ $itemInfo = [
+ 'course_user' => [
+ 'course_id' => $courseUser->course_id,
+ 'user_id' => $courseUser->user_id,
+ 'role_type' => $courseUser->role_type,
+ 'source_type' => $courseUser->role_type,
+ ],
+ 'chapter' => [
+ 'id' => $chapter->id,
+ ],
+ ];
+
+ $task->item_id = $chapter->id;
+ $task->item_info = $itemInfo;
+ $task->item_type = TaskModel::TYPE_NOTICE_LIVE_BEGIN;
+ $task->priority = TaskModel::PRIORITY_LOW;
+ $task->status = TaskModel::STATUS_PENDING;
+
+ $task->create();
+ }
+
+}
diff --git a/app/Services/Logic/Notice/OrderFinish.php b/app/Services/Logic/Notice/OrderFinish.php
new file mode 100644
index 00000000..5b70e132
--- /dev/null
+++ b/app/Services/Logic/Notice/OrderFinish.php
@@ -0,0 +1,76 @@
+item_info['order']['id'];
+
+ $orderRepo = new OrderRepo();
+
+ $order = $orderRepo->findById($orderId);
+
+ $userRepo = new UserRepo();
+
+ $user = $userRepo->findById($order->owner_id);
+
+ $params = [
+ 'user' => [
+ 'id' => $user->id,
+ 'name' => $user->name,
+ ],
+ 'order' => [
+ 'sn' => $order->sn,
+ 'subject' => $order->subject,
+ 'amount' => $order->amount,
+ ],
+ ];
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($order->owner_id);
+
+ if ($subscribe && $subscribe->deleted == 0) {
+
+ $notice = new WechatOrderFinishNotice();
+
+ return $notice->handle($subscribe, $params);
+
+ } else {
+
+ $notice = new SmsOrderFinishNotice();
+
+ return $notice->handle($user, $params);
+ }
+ }
+
+ public function createTask(OrderModel $order)
+ {
+ $task = new TaskModel();
+
+ $itemInfo = [
+ 'order' => ['id' => $order->id],
+ ];
+
+ $task->item_id = $order->id;
+ $task->item_info = $itemInfo;
+ $task->item_type = TaskModel::TYPE_NOTICE_ORDER_FINISH;
+ $task->priority = TaskModel::PRIORITY_HIGH;
+ $task->status = TaskModel::STATUS_PENDING;
+
+ $task->create();
+ }
+
+}
diff --git a/app/Services/Logic/Notice/RefundFinish.php b/app/Services/Logic/Notice/RefundFinish.php
new file mode 100644
index 00000000..468f5539
--- /dev/null
+++ b/app/Services/Logic/Notice/RefundFinish.php
@@ -0,0 +1,76 @@
+item_info['refund']['id'];
+
+ $refundRepo = new RefundRepo();
+
+ $refund = $refundRepo->findById($refundId);
+
+ $userRepo = new UserRepo();
+
+ $user = $userRepo->findById($refund->owner_id);
+
+ $params = [
+ 'user' => [
+ 'id' => $user->id,
+ 'name' => $user->name,
+ ],
+ 'order' => [
+ 'sn' => $refund->sn,
+ 'subject' => $refund->subject,
+ 'amount' => $refund->amount,
+ ],
+ ];
+
+ $subscribeRepo = new WechatSubscribeRepo();
+
+ $subscribe = $subscribeRepo->findByUserId($refund->owner_id);
+
+ if ($subscribe && $subscribe->deleted == 0) {
+
+ $notice = new WechatRefundFinishNotice();
+
+ return $notice->handle($subscribe, $params);
+
+ } else {
+
+ $notice = new SmsRefundFinishNotice();
+
+ return $notice->handle($user, $params);
+ }
+ }
+
+ public function createTask(RefundModel $refund)
+ {
+ $task = new TaskModel();
+
+ $itemInfo = [
+ 'refund' => ['id' => $refund->id],
+ ];
+
+ $task->item_id = $refund->id;
+ $task->item_info = $itemInfo;
+ $task->item_type = TaskModel::TYPE_NOTICE_ORDER_FINISH;
+ $task->priority = TaskModel::PRIORITY_MIDDLE;
+ $task->status = TaskModel::STATUS_PENDING;
+
+ $task->create();
+ }
+
+}
diff --git a/app/Services/Sms/Live.php b/app/Services/Sms/Live.php
deleted file mode 100644
index 356f40f1..00000000
--- a/app/Services/Sms/Live.php
+++ /dev/null
@@ -1,50 +0,0 @@
-findById($userId);
-
- if (empty($account->phone)) {
- return false;
- }
-
- $chapterRepo = new ChapterRepo();
-
- $chapter = $chapterRepo->findById($chapterId);
-
- $courseRepo = new CourseRepo();
-
- $course = $courseRepo->findById($chapter->course_id);
-
- $params = [
- $course->title,
- $chapter->title,
- $startTime,
- ];
-
- $templateId = $this->getTemplateId($this->templateCode);
-
- return $this->send($account->phone, $templateId, $params);
- }
-
-}
diff --git a/app/Services/Sms/Notice/ConsultReply.php b/app/Services/Sms/Notice/ConsultReply.php
new file mode 100644
index 00000000..85d21f21
--- /dev/null
+++ b/app/Services/Sms/Notice/ConsultReply.php
@@ -0,0 +1,37 @@
+findById($user->id);
+
+ if (!$account->phone) return null;
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ $params = [
+ $params['replier']['name'],
+ $params['course']['title'],
+ ];
+
+ return $this->send($account->phone, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Sms/Notice/LiveBegin.php b/app/Services/Sms/Notice/LiveBegin.php
new file mode 100644
index 00000000..104b8f86
--- /dev/null
+++ b/app/Services/Sms/Notice/LiveBegin.php
@@ -0,0 +1,38 @@
+findById($user->id);
+
+ if (!$account->phone) return null;
+
+ $params = [
+ $params['course']['title'],
+ $params['chapter']['title'],
+ date('H:i', $params['live']['start_time']),
+ ];
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ return $this->send($account->phone, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Sms/Notice/OrderFinish.php b/app/Services/Sms/Notice/OrderFinish.php
new file mode 100644
index 00000000..e67fd2a0
--- /dev/null
+++ b/app/Services/Sms/Notice/OrderFinish.php
@@ -0,0 +1,38 @@
+findById($user->id);
+
+ if (!$account->phone) return null;
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ $params = [
+ $params['order']['subject'],
+ $params['order']['sn'],
+ $params['order']['amount'],
+ ];
+
+ return $this->send($account->phone, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Sms/Notice/RefundFinish.php b/app/Services/Sms/Notice/RefundFinish.php
new file mode 100644
index 00000000..f64d8908
--- /dev/null
+++ b/app/Services/Sms/Notice/RefundFinish.php
@@ -0,0 +1,38 @@
+findById($user->id);
+
+ if (!$account->phone) return null;
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ $params = [
+ $params['refund']['subject'],
+ $params['refund']['sn'],
+ $params['refund']['amount'],
+ ];
+
+ return $this->send($account->phone, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Sms/Order.php b/app/Services/Sms/Order.php
deleted file mode 100644
index 64e4a6df..00000000
--- a/app/Services/Sms/Order.php
+++ /dev/null
@@ -1,39 +0,0 @@
-findById($order->owner_id);
-
- if (empty($account->phone)) {
- return false;
- }
-
- $templateId = $this->getTemplateId($this->templateCode);
-
- $params = [
- $order->subject,
- $order->sn,
- $order->amount,
- ];
-
- return $this->send($account->phone, $templateId, $params);
- }
-
-}
diff --git a/app/Services/Sms/Refund.php b/app/Services/Sms/Refund.php
deleted file mode 100644
index 5796f82b..00000000
--- a/app/Services/Sms/Refund.php
+++ /dev/null
@@ -1,39 +0,0 @@
-findById($refund->owner_id);
-
- if (empty($account->phone)) {
- return false;
- }
-
- $templateId = $this->getTemplateId($this->templateCode);
-
- $params = [
- $refund->subject,
- $refund->sn,
- $refund->amount,
- ];
-
- return $this->send($account->phone, $templateId, $params);
- }
-
-}
diff --git a/app/Services/WeChat.php b/app/Services/Wechat.php
similarity index 96%
rename from app/Services/WeChat.php
rename to app/Services/Wechat.php
index 55f5ba9d..ed106111 100644
--- a/app/Services/WeChat.php
+++ b/app/Services/Wechat.php
@@ -5,13 +5,13 @@ namespace App\Services;
use EasyWeChat\Factory;
use Phalcon\Logger\Adapter\File as FileLogger;
-class WeChat extends Service
+class Wechat extends Service
{
/**
* @var FileLogger
*/
- protected $logger;
+ public $logger;
public function __construct()
{
diff --git a/app/Services/Wechat/Notice/AccountLogin.php b/app/Services/Wechat/Notice/AccountLogin.php
new file mode 100644
index 00000000..f05b9191
--- /dev/null
+++ b/app/Services/Wechat/Notice/AccountLogin.php
@@ -0,0 +1,35 @@
+ $first,
+ 'remark' => $remark,
+ 'keyword1' => $params['login_region'],
+ 'keyword2' => date('Y-m-d H:i', $params['login_time']),
+ ];
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ return $this->send($subscribe->open_id, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Wechat/Notice/ConsultReply.php b/app/Services/Wechat/Notice/ConsultReply.php
new file mode 100644
index 00000000..3fd1202a
--- /dev/null
+++ b/app/Services/Wechat/Notice/ConsultReply.php
@@ -0,0 +1,37 @@
+open_id;
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ $first = sprintf('%s 回复了你的咨询!', $params['replier']['name']);
+
+ $remark = '如果还有其它疑问,请和我们保持联系哦!';
+
+ $params = [
+ 'first' => $first,
+ 'remark' => $remark,
+ 'keyword1' => $params['course']['title'],
+ ];
+
+ return $this->send($openId, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Wechat/Notice/LiveBegin.php b/app/Services/Wechat/Notice/LiveBegin.php
new file mode 100644
index 00000000..83077f4d
--- /dev/null
+++ b/app/Services/Wechat/Notice/LiveBegin.php
@@ -0,0 +1,36 @@
+ $first,
+ 'remark' => $remark,
+ 'keyword1' => $params['course']['title'],
+ 'keyword2' => $params['chapter']['title'],
+ 'keyword3' => date('Y-m-d H:i', $params['live']['start_time']),
+ ];
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ return $this->send($subscribe->open_id, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Wechat/Notice/OrderFinish.php b/app/Services/Wechat/Notice/OrderFinish.php
new file mode 100644
index 00000000..c21ea2a9
--- /dev/null
+++ b/app/Services/Wechat/Notice/OrderFinish.php
@@ -0,0 +1,37 @@
+ $first,
+ 'remark' => $remark,
+ 'keyword1' => $params['order']['subject'],
+ 'keyword2' => $params['order']['sn'],
+ 'keyword3' => $params['order']['amount'],
+ ];
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ return $this->send($subscribe->open_id, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/Wechat/Notice/RefundFinish.php b/app/Services/Wechat/Notice/RefundFinish.php
new file mode 100644
index 00000000..6b2030fe
--- /dev/null
+++ b/app/Services/Wechat/Notice/RefundFinish.php
@@ -0,0 +1,36 @@
+ $first,
+ 'remark' => $remark,
+ 'keyword1' => $params['refund']['subject'],
+ 'keyword2' => $params['refund']['sn'],
+ 'keyword3' => $params['refund']['amount'],
+ ];
+
+ $templateId = $this->getTemplateId($this->templateCode);
+
+ return $this->send($subscribe->open_id, $templateId, $params);
+ }
+
+}
diff --git a/app/Services/WechatNotice.php b/app/Services/WechatNotice.php
new file mode 100644
index 00000000..18c85ba4
--- /dev/null
+++ b/app/Services/WechatNotice.php
@@ -0,0 +1,103 @@
+settings = $this->getSettings('wechat.oa');
+
+ $this->logger = $this->getLogger('wechat');
+ }
+
+ /**
+ * 发送模板消息
+ *
+ * @param string $openId
+ * @param string $templateId
+ * @param array $params
+ * @param string $url
+ * @param array $miniProgram
+ * @return bool
+ */
+ public function send($openId, $templateId, $params, $url = null, $miniProgram = [])
+ {
+ $service = new WechatService();
+
+ $app = $service->getOfficialAccount();
+
+ $content = [
+ 'touser' => $openId,
+ 'template_id' => $templateId,
+ 'data' => $this->formatParams($params),
+ ];
+
+ if ($url) {
+ $content['url'] = $url;
+ }
+
+ if ($miniProgram) {
+ $content['miniprogram'] = $miniProgram;
+ }
+
+ try {
+
+ $this->logger->debug('Send Template Message Request ' . kg_json_encode($content));
+
+ $response = $app->template_message->send($content);
+
+ $this->logger->debug('Send Template Message Response ' . kg_json_encode($response));
+
+ $result = $response['errcode'] == 0;
+
+ if ($result == false) {
+ $this->logger->error('Send Template Message Failed ' . kg_json_encode($response));
+ }
+
+ } catch (\Exception $e) {
+
+ $this->logger->error('Send Template Message Exception ' . kg_json_encode([
+ 'code' => $e->getCode(),
+ 'message' => $e->getMessage(),
+ ]));
+
+ $result = false;
+ }
+
+ return $result;
+ }
+
+ protected function formatParams($params)
+ {
+ if (!empty($params)) {
+ $params = array_map(function ($value) {
+ return strval($value);
+ }, $params);
+ }
+
+ return $params;
+ }
+
+ protected function getTemplateId($code)
+ {
+ $template = json_decode($this->settings['notice_template'], true);
+
+ return $template[$code] ?? null;
+ }
+
+}
diff --git a/db/migrations/20201205091213_create_connect_table.php b/db/migrations/20201205091213_create_connect_table.php
index 53041625..4e0419da 100644
--- a/db/migrations/20201205091213_create_connect_table.php
+++ b/db/migrations/20201205091213_create_connect_table.php
@@ -84,7 +84,7 @@ class CreateConnectTable extends Phinx\Migration\AbstractMigration
'after' => 'create_time',
])
->addIndex(['open_id', 'provider'], [
- 'name' => 'openid_provider',
+ 'name' => 'open_provider',
'unique' => false,
])
->create();
diff --git a/db/migrations/20201212102844_schema_202012121830.php b/db/migrations/20201212102844_schema_202012121830.php
new file mode 100644
index 00000000..90512438
--- /dev/null
+++ b/db/migrations/20201212102844_schema_202012121830.php
@@ -0,0 +1,99 @@
+table('kg_consult')
+ ->addColumn('replier_id', 'integer', [
+ 'null' => false,
+ 'default' => '0',
+ 'limit' => MysqlAdapter::INT_REGULAR,
+ 'comment' => '回复者编号',
+ 'after' => 'owner_id',
+ ])
+ ->save();
+ $this->table('kg_connect')
+ ->addColumn('union_id', 'string', [
+ 'null' => false,
+ 'default' => '',
+ 'limit' => 50,
+ 'collation' => 'utf8mb4_general_ci',
+ 'encoding' => 'utf8mb4',
+ 'comment' => 'union_id',
+ 'after' => 'user_id',
+ ])
+ ->addIndex(['union_id', 'provider'], [
+ 'name' => 'union_provider',
+ 'unique' => false,
+ ])
+ ->addIndex(['user_id'], [
+ 'name' => 'user_id',
+ 'unique' => false,
+ ])
+ ->save();
+ $this->table('kg_wechat_subscribe', [
+ 'id' => false,
+ 'primary_key' => ['id'],
+ 'engine' => 'InnoDB',
+ 'encoding' => 'utf8mb4',
+ 'collation' => 'utf8mb4_general_ci',
+ 'comment' => '',
+ 'row_format' => 'DYNAMIC',
+ ])
+ ->addColumn('id', 'integer', [
+ 'null' => false,
+ 'limit' => MysqlAdapter::INT_REGULAR,
+ 'identity' => 'enable',
+ 'comment' => '主键编号',
+ ])
+ ->addColumn('user_id', 'integer', [
+ 'null' => false,
+ 'default' => '0',
+ 'limit' => MysqlAdapter::INT_REGULAR,
+ 'comment' => '用户编号',
+ 'after' => 'id',
+ ])
+ ->addColumn('open_id', 'string', [
+ 'null' => false,
+ 'default' => '',
+ 'limit' => 50,
+ 'collation' => 'utf8mb4_general_ci',
+ 'encoding' => 'utf8mb4',
+ 'comment' => '开放ID',
+ 'after' => 'user_id',
+ ])
+ ->addColumn('deleted', 'integer', [
+ 'null' => false,
+ 'default' => '0',
+ 'limit' => MysqlAdapter::INT_REGULAR,
+ 'comment' => '删除标识',
+ 'after' => 'open_id',
+ ])
+ ->addColumn('create_time', 'integer', [
+ 'null' => false,
+ 'default' => '0',
+ 'limit' => MysqlAdapter::INT_REGULAR,
+ 'comment' => '创建时间',
+ 'after' => 'deleted',
+ ])
+ ->addColumn('update_time', 'integer', [
+ 'null' => false,
+ 'default' => '0',
+ 'limit' => MysqlAdapter::INT_REGULAR,
+ 'comment' => '更新时间',
+ 'after' => 'create_time',
+ ])
+ ->addIndex(['open_id'], [
+ 'name' => 'open_id',
+ 'unique' => false,
+ ])
+ ->addIndex(['user_id'], [
+ 'name' => 'user_id',
+ 'unique' => false,
+ ])
+ ->create();
+ }
+}
diff --git a/db/migrations/20201212112717_data_202012121830.php b/db/migrations/20201212112717_data_202012121830.php
new file mode 100644
index 00000000..88f41687
--- /dev/null
+++ b/db/migrations/20201212112717_data_202012121830.php
@@ -0,0 +1,81 @@
+ 'wechat.oa',
+ 'item_key' => 'enabled',
+ 'item_value' => '0',
+ ],
+ [
+ 'section' => 'wechat.oa',
+ 'item_key' => 'app_id',
+ 'item_value' => '',
+ ],
+ [
+ 'section' => 'wechat.oa',
+ 'item_key' => 'app_secret',
+ 'item_value' => '',
+ ],
+ [
+ 'section' => 'wechat.oa',
+ 'item_key' => 'app_token',
+ 'item_value' => '',
+ ],
+ [
+ 'section' => 'wechat.oa',
+ 'item_key' => 'aes_key',
+ 'item_value' => '',
+ ],
+ [
+ 'section' => 'wechat.oa',
+ 'item_key' => 'notify_url',
+ 'item_value' => '',
+ ],
+ [
+ 'section' => 'wechat.oa',
+ 'item_key' => 'notice_template',
+ 'item_value' => '{"account_login":"","order_finish":"","refund_finish":"","live_begin":"","consult_reply":""}',
+ ],
+ ];
+
+ $this->table('kg_setting')->insert($rows)->save();
+
+ $this->updateSmsTemplate();
+ }
+
+ public function down()
+ {
+ $this->getQueryBuilder()->delete('kg_setting')->where(['section' => 'wechat.oa'])->execute();
+ }
+
+ protected function updateSmsTemplate()
+ {
+ $table = 'kg_setting';
+
+ $where = ['section' => 'sms', 'item_key' => 'template'];
+
+ $setting = $this->getQueryBuilder()->select('*')->from($table)->where($where)->execute()->fetch('assoc');
+
+ $itemValue = json_decode($setting['item_value'], true);
+
+ $newItemValue = json_encode([
+ 'verify' => $itemValue['verify'],
+ 'order_finish' => $itemValue['order'],
+ 'refund_finish' => $itemValue['refund'],
+ 'live_begin' => $itemValue['live'],
+ 'consult_reply' => '',
+ ]);
+
+ $this->getQueryBuilder()->update($table)->where($where)->set('item_value', $newItemValue)->execute();
+ }
+
+}
\ No newline at end of file
diff --git a/public/static/home/css/common.css b/public/static/home/css/common.css
index bf8478c5..aa001338 100644
--- a/public/static/home/css/common.css
+++ b/public/static/home/css/common.css
@@ -1609,6 +1609,24 @@
margin: 0 10px;
}
+.my-subscribe {
+ margin-bottom: 15px;
+}
+
+.my-subscribe .qrcode {
+ margin: 30px auto;
+ width: 160px;
+ height: 160px;
+}
+
+.my-subscribe .tips {
+ text-align: center;
+}
+
+.my-subscribe .success {
+ color: green;
+}
+
.order-filter {
padding: 15px 20px;
}
diff --git a/public/static/home/js/user.console.subscribe.js b/public/static/home/js/user.console.subscribe.js
new file mode 100644
index 00000000..14dc9fd2
--- /dev/null
+++ b/public/static/home/js/user.console.subscribe.js
@@ -0,0 +1,29 @@
+layui.use(['jquery'], function () {
+
+ var $ = layui.jquery;
+ var subscribed = $('input[name=subscribed]').val();
+ var interval = null;
+
+ if (subscribed === '0') {
+ showQrCode();
+ interval = setInterval(function () {
+ queryStatus();
+ }, 5000);
+ }
+
+ function showQrCode() {
+ $.get('/wechat/oa/subscribe/qrcode', function (res) {
+ $('#sub-qrcode').html('
');
+ });
+ }
+
+ function queryStatus() {
+ $.get('/wechat/oa/subscribe/status', function (res) {
+ if (res.status === 1) {
+ clearInterval(interval);
+ $('#sub-tips').addClass('success').html('关注公众号成功');
+ }
+ });
+ }
+
+});
\ No newline at end of file
diff --git a/scheduler.php b/scheduler.php
index b5b27246..78fc9f8f 100644
--- a/scheduler.php
+++ b/scheduler.php
@@ -13,8 +13,8 @@ $bin = '/usr/local/bin/php';
$scheduler->php($script, $bin, ['--task' => 'deliver', '--action' => 'main'])
->at('*/3 * * * *');
-$scheduler->php($script, $bin, ['--task' => 'live_notify', '--action' => 'main'])
- ->at('*/5 * * * *');
+$scheduler->php($script, $bin, ['--task' => 'notice', '--action' => 'main'])
+ ->at('*/3 * * * *');
$scheduler->php($script, $bin, ['--task' => 'sync_learning', '--action' => 'main'])
->at('*/7 * * * *');