mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-24 20:06:09 +08:00
Merge branch 'develop'
This commit is contained in:
commit
b6808d7294
20
CHANGELOG.md
20
CHANGELOG.md
@ -1,3 +1,23 @@
|
||||
### [v1.2.2](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.2)(2020-12-24)
|
||||
|
||||
#### 增加
|
||||
|
||||
- 登录账户微信提醒
|
||||
- 购买成功微信提醒
|
||||
- 退款成功微信提醒
|
||||
- 开始直播微信提醒
|
||||
- 咨询回复微信提醒
|
||||
- 咨询回复短信提醒
|
||||
|
||||
#### 修复
|
||||
|
||||
- 创建章节,关联表数据没有生成
|
||||
- 创建群组,没有生成max_im_group_id缓存
|
||||
- 课程分类列表没有过滤掉帮助分类的内容
|
||||
- 创建角色字段routes MySQL text 类型报错
|
||||
- 低品质视频无法播放
|
||||
- 后台遗漏的权限
|
||||
|
||||
### [v1.2.1](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.1)(2020-12-10)
|
||||
- 增加QQ,微信,微博第三方登录
|
||||
- 代码优化以及问题修复
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
酷瓜云课堂,依托腾讯云基础服务架构,采用C扩展框架Phalcon开发,GPL-2.0开源协议,致力开源网课系统,开源网校系统,开源在线教育系统。
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
#### 系统功能
|
||||
@ -86,3 +86,5 @@ Tips: 测试支付请用手机号注册一个新账户,以便接收订单通
|
||||
- 系统定制
|
||||
- 企业授权
|
||||
|
||||
毫无保留的真开源不容易,如果对你有帮助,请给我们 **STAR** !!!
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理日志文件
|
||||
*
|
||||
|
@ -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;
|
||||
@ -26,7 +26,7 @@ class DeliverTask extends Task
|
||||
{
|
||||
$logger = $this->getLogger('order');
|
||||
|
||||
$tasks = $this->findTasks();
|
||||
$tasks = $this->findTasks(30);
|
||||
|
||||
if ($tasks->count() == 0) {
|
||||
return;
|
||||
@ -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)
|
||||
@ -244,7 +244,7 @@ class DeliverTask extends Task
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|TaskModel[]
|
||||
*/
|
||||
protected function findTasks($limit = 100)
|
||||
protected function findTasks($limit = 30)
|
||||
{
|
||||
$itemType = TaskModel::TYPE_DELIVER;
|
||||
$status = TaskModel::STATUS_PENDING;
|
||||
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Services\LiveNotify as LiveNotifyService;
|
||||
use App\Services\Sms\Live as LiveSms;
|
||||
|
||||
class LiveNotifyTask extends Task
|
||||
{
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$redis = $this->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');
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
137
app/Console/Tasks/NoticeTask.php
Normal file
137
app/Console/Tasks/NoticeTask.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Services\Logic\Notice\AccountLogin as AccountLoginNotice;
|
||||
use App\Services\Logic\Notice\ConsultReply as ConsultReplyNotice;
|
||||
use App\Services\Logic\Notice\LiveBegin as LiveBeginNotice;
|
||||
use App\Services\Logic\Notice\OrderFinish as OrderFinishNotice;
|
||||
use App\Services\Logic\Notice\RefundFinish as RefundFinishNotice;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class NoticeTask extends Task
|
||||
{
|
||||
|
||||
const TRY_COUNT = 3;
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$logger = $this->getLogger('notice');
|
||||
|
||||
$tasks = $this->findTasks(300);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
@ -29,7 +29,7 @@ class RefundTask extends Task
|
||||
{
|
||||
$logger = $this->getLogger('refund');
|
||||
|
||||
$tasks = $this->findTasks();
|
||||
$tasks = $this->findTasks(30);
|
||||
|
||||
if ($tasks->count() == 0) {
|
||||
return;
|
||||
@ -95,7 +95,7 @@ class RefundTask extends Task
|
||||
|
||||
$this->db->commit();
|
||||
|
||||
$this->handleRefundNotice($refund);
|
||||
$this->handleRefundFinishNotice($refund);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@ -259,7 +259,7 @@ class RefundTask extends Task
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理测试订单退款
|
||||
* 处理赞赏订单退款
|
||||
*
|
||||
* @param OrderModel $order
|
||||
*/
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
|
||||
|
@ -327,4 +327,29 @@ class SettingController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/wechat", name="admin.setting.wechat")
|
||||
*/
|
||||
public function wechatAction()
|
||||
{
|
||||
$settingService = new SettingService();
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
|
||||
$section = $this->request->getPost('section', 'string');
|
||||
|
||||
$data = $this->request->getPost();
|
||||
|
||||
$settingService->updateWechatSettings($section, $data);
|
||||
|
||||
return $this->jsonSuccess(['msg' => '更新配置成功']);
|
||||
|
||||
} else {
|
||||
|
||||
$oa = $settingService->getWechatOASettings();
|
||||
|
||||
$this->view->setVar('oa', $oa);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,14 +34,14 @@ class AuthNode extends Service
|
||||
'title' => '分类列表',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.category.list',
|
||||
'params' => ['type' => 'course'],
|
||||
'params' => ['type' => 1],
|
||||
],
|
||||
[
|
||||
'id' => '1-2-2',
|
||||
'title' => '添加分类',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.category.add',
|
||||
'params' => ['type' => 'course'],
|
||||
'params' => ['type' => 1],
|
||||
],
|
||||
[
|
||||
'id' => '1-2-3',
|
||||
@ -90,7 +90,7 @@ class AuthNode extends Service
|
||||
'id' => '1-1-5',
|
||||
'title' => '删除课程',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.course.edit',
|
||||
'route' => 'admin.course.delete',
|
||||
],
|
||||
[
|
||||
'id' => '1-1-6',
|
||||
@ -529,6 +529,12 @@ class AuthNode extends Service
|
||||
],
|
||||
[
|
||||
'id' => '3-2-3',
|
||||
'title' => '交易详情',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.trade.show',
|
||||
],
|
||||
[
|
||||
'id' => '3-2-4',
|
||||
'title' => '交易退款',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.trade.refund',
|
||||
@ -750,6 +756,12 @@ class AuthNode extends Service
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.setting.oauth',
|
||||
],
|
||||
[
|
||||
'id' => '5-1-13',
|
||||
'title' => '微信公众平台',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.setting.wechat',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -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();
|
||||
|
@ -61,8 +61,11 @@ class Role extends Service
|
||||
|
||||
$data['name'] = $validator->checkName($post['name']);
|
||||
$data['summary'] = $validator->checkSummary($post['summary']);
|
||||
$data['routes'] = $validator->checkRoutes($post['routes']);
|
||||
$data['routes'] = $this->handleRoutes($data['routes']);
|
||||
|
||||
if (isset($post['routes'])) {
|
||||
$data['routes'] = $validator->checkRoutes($post['routes']);
|
||||
$data['routes'] = $this->handleRoutes($data['routes']);
|
||||
}
|
||||
|
||||
$role->update($data);
|
||||
|
||||
@ -114,9 +117,9 @@ class Role extends Service
|
||||
* @param array $routes
|
||||
* @return array
|
||||
*/
|
||||
protected function handleRoutes($routes)
|
||||
protected function handleRoutes(array $routes)
|
||||
{
|
||||
if (empty($routes)) {
|
||||
if (count($routes) == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -140,23 +143,24 @@ class Role extends Service
|
||||
if (in_array('admin.course.list', $routes)) {
|
||||
$list[] = 'admin.course.chapters';
|
||||
$list[] = 'admin.chapter.lessons';
|
||||
$list[] = 'admin.chapter.resources';
|
||||
}
|
||||
|
||||
if (array_intersect(['admin.course.add', 'admin.course.edit'], $routes)) {
|
||||
$list[] = 'admin.chapter.add';
|
||||
$list[] = 'admin.chapter.edit';
|
||||
$list[] = 'admin.chapter.create';
|
||||
$list[] = 'admin.chapter.update';
|
||||
$list[] = 'admin.chapter.content';
|
||||
}
|
||||
|
||||
if (array_intersect(['admin.chapter.add', 'admin.chapter.edit'], $routes)) {
|
||||
$list[] = 'admin.resource.create';
|
||||
$list[] = 'admin.resource.update';
|
||||
$list[] = 'admin.resource.delete';
|
||||
}
|
||||
|
||||
if (in_array('admin.course.delete', $routes)) {
|
||||
$list[] = 'admin.chapter.delete';
|
||||
$list[] = 'admin.chapter.restore';
|
||||
$list[] = 'admin.resource.delete';
|
||||
$list[] = 'admin.resource.restore';
|
||||
}
|
||||
|
||||
if (in_array('admin.category.list', $routes)) {
|
||||
@ -172,6 +176,18 @@ class Role extends Service
|
||||
$list[] = 'admin.category.list';
|
||||
}
|
||||
|
||||
if (in_array('admin.order.show', $routes)) {
|
||||
$list[] = 'admin.order.status_history';
|
||||
}
|
||||
|
||||
if (in_array('admin.trade.show', $routes)) {
|
||||
$list[] = 'admin.trade.status_history';
|
||||
}
|
||||
|
||||
if (in_array('admin.refund.show', $routes)) {
|
||||
$list[] = 'admin.refund.status_history';
|
||||
}
|
||||
|
||||
$list = array_unique($list);
|
||||
|
||||
return array_values($list);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,6 +57,16 @@ class Setting extends Service
|
||||
return $wxpay;
|
||||
}
|
||||
|
||||
public function getWechatOASettings()
|
||||
{
|
||||
$oa = $this->getSettings('wechat.oa');
|
||||
|
||||
$oa['auth_url'] = $oa['auth_url'] ?: kg_full_url(['for' => 'home.wechat.oa.auth_callback']);
|
||||
$oa['notify_url'] = $oa['notify_url'] ?: kg_full_url(['for' => 'home.wechat.oa.notify_callback']);
|
||||
|
||||
return $oa;
|
||||
}
|
||||
|
||||
public function getVipSettings()
|
||||
{
|
||||
$vipRepo = new VipRepo();
|
||||
@ -144,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);
|
||||
}
|
||||
@ -160,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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
||||
{% set show_url = url({'for':'admin.order.show','id':item.id}) %}
|
||||
<tr>
|
||||
<td>
|
||||
<p>商品:{{ item.subject }} {{ item_type(item.item_type) }}</p>
|
||||
<p>商品:{{ item.subject }}</p>
|
||||
<p>单号:{{ item.sn }}</p>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -53,21 +53,27 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>订单通知</td>
|
||||
<td><input class="layui-input" type="text" name="template[order]" value="{{ template.order }}" lay-verify="required"></td>
|
||||
<td><input id="tc-order" class="layui-input" type="text" value="下单成功,商品名称:{1},订单序号:{2},订单金额:¥{3}" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-order">复制</span></td>
|
||||
<td><input class="layui-input" type="text" name="template[order_finish]" value="{{ template.order_finish }}" lay-verify="required"></td>
|
||||
<td><input id="tc-order-finish" class="layui-input" type="text" value="下单成功,商品名称:{1},订单序号:{2},订单金额:¥{3}" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-order-finish">复制</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>退款通知</td>
|
||||
<td><input class="layui-input" type="text" name="template[refund]" value="{{ template.refund }}" lay-verify="required"></td>
|
||||
<td><input id="tc-refund" class="layui-input" type="text" value="退款成功,商品名称:{1},订单序号:{2},退款金额:¥{3}" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-refund">复制</span></td>
|
||||
<td><input class="layui-input" type="text" name="template[refund_finish]" value="{{ template.refund_finish }}" lay-verify="required"></td>
|
||||
<td><input id="tc-refund-finish" class="layui-input" type="text" value="退款成功,商品名称:{1},退款序号:{2},退款金额:¥{3}" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-refund-finish">复制</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>直播通知</td>
|
||||
<td><input class="layui-input" type="text" name="template[live]" value="{{ template.live }}" lay-verify="required"></td>
|
||||
<td><input id="tc-live" class="layui-input" type="text" value="直播预告,课程名称:{1},章节名称:{2},开播时间:{3}" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-live">复制</span></td>
|
||||
<td>直播提醒</td>
|
||||
<td><input class="layui-input" type="text" name="template[live_begin]" value="{{ template.live_begin }}" lay-verify="required"></td>
|
||||
<td><input id="tc-live-begin" class="layui-input" type="text" value="直播预告,课程名称:{1},章节名称:{2},开播时间:{3}" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-live-begin">复制</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>回复通知</td>
|
||||
<td><input class="layui-input" type="text" name="template[consult_reply]" value="{{ template.consult_reply }}" lay-verify="required"></td>
|
||||
<td><input id="tc-consult-reply" class="layui-input" type="text" value="{1} 回复了你的咨询,课程名称:{2},请登录系统查看详情。" readonly="readonly"></td>
|
||||
<td><span class="kg-copy layui-btn" data-clipboard-target="#tc-consult-reply">复制</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
16
app/Http/Admin/Views/setting/wechat.volt
Normal file
16
app/Http/Admin/Views/setting/wechat.volt
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title kg-tab-title">
|
||||
<li class="layui-this">公众号</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
{{ partial('setting/wechat_oa') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
104
app/Http/Admin/Views/setting/wechat_oa.volt
Normal file
104
app/Http/Admin/Views/setting/wechat_oa.volt
Normal file
@ -0,0 +1,104 @@
|
||||
{% set notice_template = oa.notice_template|json_decode %}
|
||||
|
||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.wechat'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">开启</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="enabled" value="1" title="是" {% if oa.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="enabled" value="0" title="否" {% if oa.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="app_id" value="{{ oa.app_id }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App Secret</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="app_secret" value="{{ oa.app_secret }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App Token</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="app_token" value="{{ oa.app_token }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Aes Key</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="aes_key" value="{{ oa.aes_key }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Notify Url</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="notify_url" value="{{ oa.notify_url }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
<input type="hidden" name="section" value="wechat.oa">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>模板配置</legend>
|
||||
</fieldset>
|
||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.wechat'}) }}">
|
||||
<table class="layui-table kg-table layui-form">
|
||||
<colgroup>
|
||||
<col width="12%">
|
||||
<col width="30%">
|
||||
<col>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>模板编号</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>登录提醒</td>
|
||||
<td><input class="layui-input" type="text" name="notice_template[account_login]" value="{{ notice_template.account_login }}" lay-verify="required"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>订单通知</td>
|
||||
<td><input class="layui-input" type="text" name="notice_template[order_finish]" value="{{ notice_template.order_finish }}" lay-verify="required"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>退款通知</td>
|
||||
<td><input class="layui-input" type="text" name="notice_template[refund_finish]" value="{{ notice_template.refund_finish }}" lay-verify="required"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>直播提醒</td>
|
||||
<td><input class="layui-input" type="text" name="notice_template[live_begin]" value="{{ notice_template.live_begin }}" lay-verify="required"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>回复通知</td>
|
||||
<td><input class="layui-input" type="text" name="notice_template[consult_reply]" value="{{ notice_template.consult_reply }}" lay-verify="required"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
<input type="hidden" name="section" value="wechat.oa">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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")
|
||||
*/
|
||||
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Home\Controllers;
|
||||
|
||||
use App\Http\Home\Services\WechatOfficialAccount as WechatOAService;
|
||||
use App\Traits\Response as ResponseTrait;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/wechat/oa")
|
||||
*/
|
||||
class WechatOfficialAccountController extends \Phalcon\Mvc\Controller
|
||||
{
|
||||
|
||||
use ResponseTrait;
|
||||
|
||||
/**
|
||||
* @Get("/subscribe/status", name="home.wechat.oa.sub_status")
|
||||
*/
|
||||
public function subscribeStatusAction()
|
||||
{
|
||||
$service = new WechatOAService();
|
||||
|
||||
$status = $service->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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use App\Repos\Connect as ConnectRepo;
|
||||
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\Services\OAuth\QQ as QQAuth;
|
||||
use App\Services\OAuth\WeiBo as WeiBoAuth;
|
||||
use App\Services\OAuth\WeiXin as WeiXinAuth;
|
||||
@ -32,6 +33,8 @@ class Connect extends Service
|
||||
|
||||
$this->handleConnectRelation($user, $openUser);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
|
||||
$auth = $this->getAppAuth();
|
||||
|
||||
$auth->saveAuthInfo($user);
|
||||
@ -57,6 +60,8 @@ class Connect extends Service
|
||||
|
||||
$this->handleConnectRelation($user, $openUser);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
|
||||
$auth = $this->getAppAuth();
|
||||
|
||||
$auth->saveAuthInfo($user);
|
||||
@ -75,6 +80,8 @@ class Connect extends Service
|
||||
|
||||
$user = $userRepo->findById($connect->user_id);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
|
||||
$auth = $this->getAppAuth();
|
||||
|
||||
$auth->saveAuthInfo($user);
|
||||
@ -208,4 +215,11 @@ class Connect extends Service
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleLoginNotice(UserModel $user)
|
||||
{
|
||||
$service = new AccountLoginNoticeService();
|
||||
|
||||
$service->createTask($user);
|
||||
}
|
||||
|
||||
}
|
||||
|
238
app/Http/Home/Services/WechatOfficialAccount.php
Normal file
238
app/Http/Home/Services/WechatOfficialAccount.php
Normal file
@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Home\Services;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use App\Repos\WechatSubscribe as WechatSubscribeRepo;
|
||||
use App\Services\Wechat as WechatService;
|
||||
use App\Validators\User as UserValidator;
|
||||
use EasyWeChat\Kernel\Messages\Text as TextMessage;
|
||||
|
||||
class WechatOfficialAccount extends Service
|
||||
{
|
||||
|
||||
public function getOfficialAccount()
|
||||
{
|
||||
$service = new WechatService();
|
||||
|
||||
return $service->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->debug('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 $this->emptyReplyMessage();
|
||||
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)
|
||||
{
|
||||
$this->defaultReplyMessage();
|
||||
}
|
||||
|
||||
protected function handleViewEvent($message)
|
||||
{
|
||||
$this->defaultReplyMessage();
|
||||
}
|
||||
|
||||
protected function handleLocationEvent($message)
|
||||
{
|
||||
$this->defaultReplyMessage();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -52,6 +52,9 @@
|
||||
<ul class="my-menu">
|
||||
<li><a href="{{ url({'for':'home.uc.profile'}) }}">个人信息</a></li>
|
||||
<li><a href="{{ url({'for':'home.uc.account'}) }}">帐号安全</a></li>
|
||||
{% if wechat_oa.enabled == 1 %}
|
||||
<li><a href="{{ url({'for':'home.uc.subscribe'}) }}">关注订阅</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
33
app/Http/Home/Views/user/console/subscribe.volt
Normal file
33
app/Http/Home/Views/user/console/subscribe.volt
Normal file
@ -0,0 +1,33 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="layout-main clearfix">
|
||||
<div class="my-sidebar">{{ partial('user/console/menu') }}</div>
|
||||
<div class="my-content">
|
||||
<div class="wrap">
|
||||
<div class="my-nav">
|
||||
<span class="title">关注订阅</span>
|
||||
</div>
|
||||
<div class="my-subscribe">
|
||||
{% if subscribed == 0 %}
|
||||
<div id="sub-qrcode" class="qrcode"></div>
|
||||
<div id="sub-tips" class="tips">订阅官方公众号,接收重要通知!</div>
|
||||
{% else %}
|
||||
<div class="tips">你已经订阅官方公众号</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="layui-hide">
|
||||
<input type="hidden" name="subscribed" value="{{ subscribed }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('home/js/user.console.subscribe.js') }}
|
||||
|
||||
{% endblock %}
|
@ -11,7 +11,7 @@ class AppInfo
|
||||
|
||||
protected $link = 'https://gitee.com/koogua';
|
||||
|
||||
protected $version = '1.2.1';
|
||||
protected $version = '1.2.2';
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
|
@ -36,12 +36,19 @@ class Consult extends Model
|
||||
public $chapter_id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
* 提主编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $owner_id;
|
||||
|
||||
/**
|
||||
* 答主编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $replier_id;
|
||||
|
||||
/**
|
||||
* 提问
|
||||
*
|
||||
|
@ -105,6 +105,8 @@ class Role extends Model
|
||||
{
|
||||
if (is_array($this->routes) && !empty($this->routes)) {
|
||||
$this->routes = kg_json_encode($this->routes);
|
||||
} else {
|
||||
$this->routes = '';
|
||||
}
|
||||
|
||||
$this->create_time = time();
|
||||
|
@ -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; // 咨询回复通知
|
||||
|
||||
/**
|
||||
* 优先级
|
||||
*/
|
||||
|
79
app/Models/WechatSubscribe.php
Normal file
79
app/Models/WechatSubscribe.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Phalcon\Mvc\Model\Behavior\SoftDelete;
|
||||
|
||||
class WechatSubscribe extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id;
|
||||
|
||||
/**
|
||||
* 开放ID
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $open_id;
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_wechat_subscribe';
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->addBehavior(
|
||||
new SoftDelete([
|
||||
'field' => 'deleted',
|
||||
'value' => 1,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public function beforeCreate()
|
||||
{
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
public function beforeUpdate()
|
||||
{
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
57
app/Repos/WechatSubscribe.php
Normal file
57
app/Repos/WechatSubscribe.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
|
||||
class WechatSubscribe extends Repository
|
||||
{
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @param string $openId
|
||||
* @return WechatSubscribeModel|Model|bool
|
||||
*/
|
||||
public function findSubscribe($userId, $openId)
|
||||
{
|
||||
return WechatSubscribeModel::findFirst([
|
||||
'conditions' => '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],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Services\Auth as AuthService;
|
||||
|
||||
class Mobile extends AuthService
|
||||
{
|
||||
|
||||
public function saveAuthInfo(UserModel $user)
|
||||
{
|
||||
$authKey = $this->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';
|
||||
}
|
||||
|
||||
}
|
@ -41,9 +41,12 @@ class ChapterVod extends Service
|
||||
|
||||
$vodTemplates = $this->getVodTemplates();
|
||||
|
||||
/**
|
||||
* 腾讯云播放器只支持[od|hd|sd],遇到fd替换为od
|
||||
*/
|
||||
foreach ($vodTemplates as $key => $template) {
|
||||
if ($height >= $template['height']) {
|
||||
return $key;
|
||||
return $key == 'fd' ? $default : $key;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
61
app/Services/Logic/Notice/AccountLogin.php
Normal file
61
app/Services/Logic/Notice/AccountLogin.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Notice;
|
||||
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\WechatSubscribe as WechatSubscribeRepo;
|
||||
use App\Services\Logic\Service as LogicService;
|
||||
use App\Services\Wechat\Notice\AccountLogin as WechatAccountLoginNotice;
|
||||
use App\Traits\Client as ClientTrait;
|
||||
|
||||
class AccountLogin extends LogicService
|
||||
{
|
||||
|
||||
use ClientTrait;
|
||||
|
||||
public function handleTask(TaskModel $task)
|
||||
{
|
||||
$params = $task->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();
|
||||
}
|
||||
|
||||
}
|
91
app/Services/Logic/Notice/ConsultReply.php
Normal file
91
app/Services/Logic/Notice/ConsultReply.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Notice;
|
||||
|
||||
use App\Models\Consult as ConsultModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Repos\Consult as ConsultRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Repos\WechatSubscribe as WechatSubscribeRepo;
|
||||
use App\Services\Logic\Service as LogicService;
|
||||
use App\Services\Sms\Notice\ConsultReply as SmsConsultReplyNotice;
|
||||
use App\Services\Wechat\Notice\ConsultReply as WechatConsultReplyNotice;
|
||||
|
||||
class ConsultReply extends LogicService
|
||||
{
|
||||
|
||||
public function handleTask(TaskModel $task)
|
||||
{
|
||||
$consultId = $task->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();
|
||||
}
|
||||
|
||||
}
|
99
app/Services/Logic/Notice/LiveBegin.php
Normal file
99
app/Services/Logic/Notice/LiveBegin.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Notice;
|
||||
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Repos\WechatSubscribe as WechatSubscribeRepo;
|
||||
use App\Services\Logic\Service as LogicService;
|
||||
use App\Services\Sms\Notice\LiveBegin as SmsLiveBeginNotice;
|
||||
use App\Services\Wechat\Notice\LiveBegin as WechatLiveBeginNotice;
|
||||
|
||||
class LiveBegin extends LogicService
|
||||
{
|
||||
|
||||
public function handleTask(TaskModel $task)
|
||||
{
|
||||
$courseUser = $task->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();
|
||||
}
|
||||
|
||||
}
|
76
app/Services/Logic/Notice/OrderFinish.php
Normal file
76
app/Services/Logic/Notice/OrderFinish.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Notice;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Repos\WechatSubscribe as WechatSubscribeRepo;
|
||||
use App\Services\Logic\Service as LogicService;
|
||||
use App\Services\Sms\Notice\OrderFinish as SmsOrderFinishNotice;
|
||||
use App\Services\Wechat\Notice\OrderFinish as WechatOrderFinishNotice;
|
||||
|
||||
class OrderFinish extends LogicService
|
||||
{
|
||||
|
||||
public function handleTask(TaskModel $task)
|
||||
{
|
||||
$orderId = $task->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();
|
||||
}
|
||||
|
||||
}
|
76
app/Services/Logic/Notice/RefundFinish.php
Normal file
76
app/Services/Logic/Notice/RefundFinish.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Notice;
|
||||
|
||||
use App\Models\Refund as RefundModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Repos\Refund as RefundRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Repos\WechatSubscribe as WechatSubscribeRepo;
|
||||
use App\Services\Logic\Service as LogicService;
|
||||
use App\Services\Sms\Notice\RefundFinish as SmsRefundFinishNotice;
|
||||
use App\Services\Wechat\Notice\RefundFinish as WechatRefundFinishNotice;
|
||||
|
||||
class RefundFinish extends LogicService
|
||||
{
|
||||
|
||||
public function handleTask(TaskModel $task)
|
||||
{
|
||||
$refundId = $task->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();
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms;
|
||||
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class Live extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'live';
|
||||
|
||||
/**
|
||||
* @param int $chapterId
|
||||
* @param int $userId
|
||||
* @param int $startTime
|
||||
* @return bool
|
||||
*/
|
||||
public function handle($chapterId, $userId, $startTime)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
37
app/Services/Sms/Notice/ConsultReply.php
Normal file
37
app/Services/Sms/Notice/ConsultReply.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms\Notice;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class ConsultReply extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'consult_reply';
|
||||
|
||||
/**
|
||||
* @param UserModel $user
|
||||
* @param array $params
|
||||
* @return bool|null
|
||||
*/
|
||||
public function handle(UserModel $user, array $params)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
38
app/Services/Sms/Notice/LiveBegin.php
Normal file
38
app/Services/Sms/Notice/LiveBegin.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms\Notice;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class LiveBegin extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'live_begin';
|
||||
|
||||
/**
|
||||
* @param UserModel $user
|
||||
* @param array $params
|
||||
* @return bool|null
|
||||
*/
|
||||
public function handle(UserModel $user, array $params)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
38
app/Services/Sms/Notice/OrderFinish.php
Normal file
38
app/Services/Sms/Notice/OrderFinish.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms\Notice;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class OrderFinish extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'order_finish';
|
||||
|
||||
/**
|
||||
* @param UserModel $user
|
||||
* @param array $params
|
||||
* @return bool|null
|
||||
*/
|
||||
public function handle(UserModel $user, array $params)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
38
app/Services/Sms/Notice/RefundFinish.php
Normal file
38
app/Services/Sms/Notice/RefundFinish.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms\Notice;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class RefundFinish extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'refund_finish';
|
||||
|
||||
/**
|
||||
* @param UserModel $user
|
||||
* @param array $params
|
||||
* @return bool|null
|
||||
*/
|
||||
public function handle(UserModel $user, array $params)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms;
|
||||
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class Order extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'order';
|
||||
|
||||
/**
|
||||
* @param OrderModel $order
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(OrderModel $order)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Sms;
|
||||
|
||||
use App\Models\Refund as RefundModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Services\Smser;
|
||||
|
||||
class Refund extends Smser
|
||||
{
|
||||
|
||||
protected $templateCode = 'refund';
|
||||
|
||||
/**
|
||||
* @param RefundModel $refund
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(RefundModel $refund)
|
||||
{
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->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);
|
||||
}
|
||||
|
||||
}
|
59
app/Services/Wechat.php
Normal file
59
app/Services/Wechat.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use EasyWeChat\Factory;
|
||||
use Phalcon\Logger\Adapter\File as FileLogger;
|
||||
|
||||
class Wechat extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @var FileLogger
|
||||
*/
|
||||
public $logger;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logger = $this->getLogger('wechat');
|
||||
}
|
||||
|
||||
public function getOfficialAccount()
|
||||
{
|
||||
$settings = $this->getSettings('wechat.oa');
|
||||
|
||||
$config = [
|
||||
'app_id' => $settings['app_id'],
|
||||
'secret' => $settings['app_secret'],
|
||||
'token' => $settings['app_token'],
|
||||
'aes_key' => $settings['aes_key'],
|
||||
'log' => $this->getLogOptions(),
|
||||
];
|
||||
|
||||
return Factory::officialAccount($config);
|
||||
}
|
||||
|
||||
protected function getLogOptions()
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
|
||||
$default = $config->get('env') == ENV_DEV ? 'dev' : 'prod';
|
||||
|
||||
return [
|
||||
'default' => $default,
|
||||
'channels' => [
|
||||
'dev' => [
|
||||
'driver' => 'daily',
|
||||
'path' => log_path('wechat.log'),
|
||||
'level' => 'debug',
|
||||
],
|
||||
'prod' => [
|
||||
'driver' => 'daily',
|
||||
'path' => log_path('wechat.log'),
|
||||
'level' => 'info',
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
43
app/Services/Wechat/Notice/AccountLogin.php
Normal file
43
app/Services/Wechat/Notice/AccountLogin.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wechat\Notice;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use App\Services\WechatNotice;
|
||||
|
||||
class AccountLogin extends WechatNotice
|
||||
{
|
||||
|
||||
protected $templateCode = 'account_login';
|
||||
|
||||
/**
|
||||
* @param WechatSubscribeModel $subscribe
|
||||
* @param array $params
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(WechatSubscribeModel $subscribe, array $params)
|
||||
{
|
||||
$first = '你好,登录系统成功!';
|
||||
$remark = '如果非本人操作,请立即修改密码哦!';
|
||||
|
||||
$loginRegion = implode('/', [
|
||||
$params['login_region']['country'],
|
||||
$params['login_region']['province'],
|
||||
$params['login_region']['city'],
|
||||
]);
|
||||
|
||||
$loginTime = date('Y-m-d H:i:s', $params['login_time']);
|
||||
|
||||
$params = [
|
||||
'first' => $first,
|
||||
'remark' => $remark,
|
||||
'keyword1' => $loginRegion,
|
||||
'keyword2' => $loginTime,
|
||||
];
|
||||
|
||||
$templateId = $this->getTemplateId($this->templateCode);
|
||||
|
||||
return $this->send($subscribe->open_id, $templateId, $params);
|
||||
}
|
||||
|
||||
}
|
35
app/Services/Wechat/Notice/ConsultReply.php
Normal file
35
app/Services/Wechat/Notice/ConsultReply.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wechat\Notice;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use App\Services\WechatNotice;
|
||||
|
||||
class ConsultReply extends WechatNotice
|
||||
{
|
||||
|
||||
protected $templateCode = 'consult_reply';
|
||||
|
||||
/**
|
||||
* @param WechatSubscribeModel $subscribe
|
||||
* @param array $params
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(WechatSubscribeModel $subscribe, array $params)
|
||||
{
|
||||
$first = sprintf('%s 回复了你的咨询!', $params['replier']['name']);
|
||||
|
||||
$remark = '如果还有其它疑问,请和我们保持联系哦!';
|
||||
|
||||
$params = [
|
||||
'first' => $first,
|
||||
'remark' => $remark,
|
||||
'keyword1' => $params['course']['title'],
|
||||
];
|
||||
|
||||
$templateId = $this->getTemplateId($this->templateCode);
|
||||
|
||||
return $this->send($subscribe->open_id, $templateId, $params);
|
||||
}
|
||||
|
||||
}
|
36
app/Services/Wechat/Notice/LiveBegin.php
Normal file
36
app/Services/Wechat/Notice/LiveBegin.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wechat\Notice;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use App\Services\WechatNotice;
|
||||
|
||||
class LiveBegin extends WechatNotice
|
||||
{
|
||||
|
||||
protected $templateCode = 'live_begin';
|
||||
|
||||
/**
|
||||
* @param WechatSubscribeModel $subscribe
|
||||
* @param array $params
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(WechatSubscribeModel $subscribe, array $params)
|
||||
{
|
||||
$first = '你参与的课程直播就要开始了!';
|
||||
$remark = '如果没能参与直播,记得观看直播录像哦!';
|
||||
|
||||
$params = [
|
||||
'first' => $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);
|
||||
}
|
||||
|
||||
}
|
37
app/Services/Wechat/Notice/OrderFinish.php
Normal file
37
app/Services/Wechat/Notice/OrderFinish.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wechat\Notice;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use App\Services\WechatNotice;
|
||||
|
||||
class OrderFinish extends WechatNotice
|
||||
{
|
||||
|
||||
protected $templateCode = 'order_finish';
|
||||
|
||||
/**
|
||||
* @param WechatSubscribeModel $subscribe
|
||||
* @param array $params
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(WechatSubscribeModel $subscribe, $params)
|
||||
{
|
||||
|
||||
$first = '订单已处理完成!';
|
||||
$remark = '感谢您的支持,有疑问请联系客服哦!';
|
||||
|
||||
$params = [
|
||||
'first' => $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);
|
||||
}
|
||||
|
||||
}
|
36
app/Services/Wechat/Notice/RefundFinish.php
Normal file
36
app/Services/Wechat/Notice/RefundFinish.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Wechat\Notice;
|
||||
|
||||
use App\Models\WechatSubscribe as WechatSubscribeModel;
|
||||
use App\Services\WechatNotice;
|
||||
|
||||
class RefundFinish extends WechatNotice
|
||||
{
|
||||
|
||||
protected $templateCode = 'refund_finish';
|
||||
|
||||
/**
|
||||
* @param WechatSubscribeModel $subscribe
|
||||
* @param array $params
|
||||
* @return bool
|
||||
*/
|
||||
public function handle(WechatSubscribeModel $subscribe, array $params)
|
||||
{
|
||||
$first = '退款已处理完成!';
|
||||
$remark = '感谢您的支持,有疑问请联系客服哦!';
|
||||
|
||||
$params = [
|
||||
'first' => $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);
|
||||
}
|
||||
|
||||
}
|
103
app/Services/WechatNotice.php
Normal file
103
app/Services/WechatNotice.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Services\Wechat as WechatService;
|
||||
use Phalcon\Logger\Adapter\File as FileLogger;
|
||||
|
||||
Abstract class WechatNotice extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var FileLogger
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
|
||||
}
|
@ -20,7 +20,8 @@
|
||||
"aferrandini/phpqrcode": "1.0.1",
|
||||
"xiaochong0302/ip2region": "^1.0",
|
||||
"robmorgan/phinx": "^0.12",
|
||||
"lcobucci/jwt": "^3.3"
|
||||
"lcobucci/jwt": "^3.3",
|
||||
"overtrue/wechat": "^4.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"odan/phinx-migrations-generator": "^5.1",
|
||||
|
1364
composer.lock
generated
1364
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
99
db/migrations/20201212102844_schema_202012121830.php
Normal file
99
db/migrations/20201212102844_schema_202012121830.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class Schema202012121830 extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$this->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();
|
||||
}
|
||||
}
|
81
db/migrations/20201212112717_data_202012121830.php
Normal file
81
db/migrations/20201212112717_data_202012121830.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class Data202012121830 extends AbstractMigration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
$rows = [
|
||||
[
|
||||
'section' => '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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
29
public/static/home/js/user.console.subscribe.js
Normal file
29
public/static/home/js/user.console.subscribe.js
Normal file
@ -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('<img alt="扫码关注" src="' + res.qrcode + '">');
|
||||
});
|
||||
}
|
||||
|
||||
function queryStatus() {
|
||||
$.get('/wechat/oa/subscribe/status', function (res) {
|
||||
if (res.status === 1) {
|
||||
clearInterval(interval);
|
||||
$('#sub-tips').addClass('success').html('关注公众号成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
@ -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 * * * *');
|
||||
@ -49,9 +49,6 @@ $scheduler->php($script, $bin, ['--task' => 'unlock_user', '--action' => 'main']
|
||||
$scheduler->php($script, $bin, ['--task' => 'revoke_vip', '--action' => 'main'])
|
||||
->daily(3, 11);
|
||||
|
||||
$scheduler->php($script, $bin, ['--task' => 'clean_token', '--action' => 'main'])
|
||||
->daily(3, 17);
|
||||
|
||||
$scheduler->php($script, $bin, ['--task' => 'sitemap', '--action' => 'main'])
|
||||
->daily(4, 3);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user