mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-07-16 21:26:13 +08:00
阶段性提交积分机制-0204
This commit is contained in:
parent
e902c0c80f
commit
f47091991d
29
app/Caches/MaxPointGiftId.php
Normal file
29
app/Caches/MaxPointGiftId.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
|
||||
class MaxPointGiftId extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'max_point_gift_id';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$gift = PointGiftModel::findFirst(['order' => 'id DESC']);
|
||||
|
||||
return $gift->id ?? 0;
|
||||
}
|
||||
|
||||
}
|
31
app/Caches/PointGift.php
Normal file
31
app/Caches/PointGift.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Repos\PointGift as PointGiftRepo;
|
||||
|
||||
class PointGift extends Cache
|
||||
{
|
||||
|
||||
protected $lifetime = 365 * 86400;
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return "point_gift:{$id}";
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$giftRepo = new PointGiftRepo();
|
||||
|
||||
$gift = $giftRepo->findById($id);
|
||||
|
||||
return $gift ?: null;
|
||||
}
|
||||
|
||||
}
|
79
app/Caches/PointHotGiftList.php
Normal file
79
app/Caches/PointHotGiftList.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class PointHotGiftList extends Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $lifetime = 1 * 86400;
|
||||
|
||||
/**
|
||||
* 显示个数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $limit = 5;
|
||||
|
||||
public function setLimit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
public function getKey($id = null)
|
||||
{
|
||||
return 'point_hot_gift_list';
|
||||
}
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$gifts = $this->findGifts($this->limit);
|
||||
|
||||
if (count($gifts) == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($gifts as $gift) {
|
||||
$result[] = [
|
||||
'id' => $gift->id,
|
||||
'name' => $gift->name,
|
||||
'cover' => $gift->cover,
|
||||
'details' => $gift->details,
|
||||
'type' => $gift->type,
|
||||
'point' => $gift->point,
|
||||
'redeem_count' => $gift->redeem_count,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|PointGiftModel[]
|
||||
*/
|
||||
protected function findGifts($limit = 5)
|
||||
{
|
||||
return PointGiftModel::query()
|
||||
->where('published = 1')
|
||||
->orderBy('redeem_count DESC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ class CleanLogTask extends Task
|
||||
$this->cleanWxpayLog();
|
||||
$this->cleanOrderLog();
|
||||
$this->cleanRefundLog();
|
||||
$this->cleanPointLog();
|
||||
$this->cleanNoticeLog();
|
||||
$this->cleanOtherLog();
|
||||
}
|
||||
@ -221,6 +222,18 @@ class CleanLogTask extends Task
|
||||
$this->whitelist[] = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理积分日志
|
||||
*/
|
||||
protected function cleanPointLog()
|
||||
{
|
||||
$type = 'point';
|
||||
|
||||
$this->cleanLog($type, 7);
|
||||
|
||||
$this->whitelist[] = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理通知日志
|
||||
*/
|
||||
|
213
app/Console/Tasks/PointGiftAwardTask.php
Normal file
213
app/Console/Tasks/PointGiftAwardTask.php
Normal file
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\ImGroupUser as ImGroupUserModel;
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use App\Models\PointHistory as PointHistoryModel;
|
||||
use App\Models\PointRedeem as PointRedeemModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\ImGroupUser as ImGroupUserRepo;
|
||||
use App\Repos\PointGift as PointGiftRepo;
|
||||
use App\Repos\PointRedeem as PointRedeemRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class PointGiftAwardTask extends Task
|
||||
{
|
||||
|
||||
const TRY_COUNT = 3;
|
||||
|
||||
public function mainAction()
|
||||
{
|
||||
$logger = $this->getLogger('point');
|
||||
|
||||
$tasks = $this->findTasks();
|
||||
|
||||
if ($tasks->count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$redeemRepo = new PointRedeemRepo();
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
|
||||
$redeem = $redeemRepo->findById($task->item_id);
|
||||
|
||||
if (!$redeem) continue;
|
||||
|
||||
try {
|
||||
|
||||
switch ($redeem->gift_type) {
|
||||
case PointGiftModel::TYPE_COURSE:
|
||||
$this->handleCourseAward($redeem);
|
||||
break;
|
||||
case PointGiftModel::TYPE_GOODS:
|
||||
$this->handleCommodityAward($redeem);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->finishRedeem($redeem);
|
||||
|
||||
$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('Point Gift Award Exception ' . kg_json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
]));
|
||||
}
|
||||
|
||||
if ($task->status == TaskModel::STATUS_FINISHED) {
|
||||
$this->handleFinishNotice();
|
||||
} elseif ($task->status == TaskModel::STATUS_FAILED) {
|
||||
$this->handlePointRefund($redeem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function finishRedeem(PointRedeemModel $redeem)
|
||||
{
|
||||
$redeem->status = PointRedeemModel::STATUS_FINISHED;
|
||||
|
||||
if ($redeem->update() === false) {
|
||||
throw new \RuntimeException('Finish Point Redeem Failed');
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleCourseAward(PointRedeemModel $redeem)
|
||||
{
|
||||
$giftRepo = new PointGiftRepo();
|
||||
|
||||
$gift = $giftRepo->findById($redeem->gift_id);
|
||||
|
||||
$courseUser = new CourseUserModel();
|
||||
|
||||
$courseUser->user_id = $redeem->user_id;
|
||||
$courseUser->course_id = $gift->attrs['id'];
|
||||
$courseUser->expiry_time = $gift->attrs['study_expiry_time'];
|
||||
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
||||
$courseUser->source_type = CourseUserModel::SOURCE_POINT_REDEEM;
|
||||
|
||||
if ($courseUser->create() === false) {
|
||||
throw new \RuntimeException('Create Course User Failed');
|
||||
}
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$group = $courseRepo->findImGroup($gift->attrs['id']);
|
||||
|
||||
$groupUserRepo = new ImGroupUserRepo();
|
||||
|
||||
$groupUser = $groupUserRepo->findGroupUser($group->id, $redeem->user_id);
|
||||
|
||||
if ($groupUser) return;
|
||||
|
||||
$groupUser = new ImGroupUserModel();
|
||||
|
||||
$groupUser->group_id = $group->id;
|
||||
$groupUser->user_id = $redeem->user_id;
|
||||
|
||||
if ($groupUser->create() === false) {
|
||||
throw new \RuntimeException('Create Im Group User Failed');
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleCommodityAward(PointRedeemModel $redeem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function handleFinishNotice()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function handlePointRefund(PointRedeemModel $redeem)
|
||||
{
|
||||
$logger = $this->getLogger('point');
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$balance = $userRepo->findUserBalance($redeem->user_id);
|
||||
|
||||
try {
|
||||
|
||||
$this->db->begin();
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$eventInfo = [
|
||||
'gift' => [
|
||||
'id' => $redeem->gift_id,
|
||||
'name' => $redeem->gift_name,
|
||||
]
|
||||
];
|
||||
|
||||
$history->user_id = $redeem->user_id;
|
||||
$history->event_id = $redeem->id;
|
||||
$history->event_type = PointHistoryModel::EVENT_POINT_REFUND;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$result = $history->create();
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Create Point History Failed');
|
||||
}
|
||||
|
||||
$balance->point += $redeem->gift_point;
|
||||
|
||||
$result = $balance->update();
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Update User Balance Failed');
|
||||
}
|
||||
|
||||
$this->db->commit();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->db->rollback();
|
||||
|
||||
$logger->error('Point Refund Exception ' . kg_json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return ResultsetInterface|Resultset|TaskModel[]
|
||||
*/
|
||||
protected function findTasks($limit = 30)
|
||||
{
|
||||
$itemType = TaskModel::TYPE_POINT_GIFT_AWARD;
|
||||
$status = TaskModel::STATUS_PENDING;
|
||||
$createTime = strtotime('-3 days');
|
||||
|
||||
return TaskModel::query()
|
||||
->where('item_type = :item_type:', ['item_type' => $itemType])
|
||||
->andWhere('status = :status:', ['status' => $status])
|
||||
->andWhere('create_time > :create_time:', ['create_time' => $createTime])
|
||||
->orderBy('priority ASC')
|
||||
->limit($limit)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\ChapterUser as ChapterUserModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\Learning as LearningModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
@ -9,7 +10,8 @@ use App\Repos\ChapterUser as ChapterUserRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\CourseUser as CourseUserRepo;
|
||||
use App\Repos\Learning as LearningRepo;
|
||||
use App\Services\Sync\Learning as LearningSync;
|
||||
use App\Services\Logic\Point\PointHistory as PointHistoryService;
|
||||
use App\Services\Sync\Learning as LearningSyncService;
|
||||
|
||||
class SyncLearningTask extends Task
|
||||
{
|
||||
@ -18,7 +20,7 @@ class SyncLearningTask extends Task
|
||||
{
|
||||
$redis = $this->getRedis();
|
||||
|
||||
$sync = new LearningSync();
|
||||
$sync = new LearningSyncService();
|
||||
|
||||
$syncKey = $sync->getSyncKey();
|
||||
|
||||
@ -120,7 +122,10 @@ class SyncLearningTask extends Task
|
||||
$chapterUser->update();
|
||||
|
||||
if ($chapterUser->consumed == 1) {
|
||||
|
||||
$this->updateCourseUser($learning);
|
||||
|
||||
$this->handleLearningPoint($chapterUser);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,4 +179,14 @@ class SyncLearningTask extends Task
|
||||
$courseUser->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ChapterUserModel $chapterUser
|
||||
*/
|
||||
protected function handleLearningPoint(ChapterUserModel $chapterUser)
|
||||
{
|
||||
$service = new PointHistoryService();
|
||||
|
||||
$service->handleChapterLearning($chapterUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
$this->checkCsrfToken();
|
||||
}
|
||||
|
||||
$this->checkRateLimit();
|
||||
|
||||
$this->authInfo = $this->getAuthInfo();
|
||||
|
||||
if (!$this->authInfo) {
|
||||
|
128
app/Http/Admin/Controllers/PointGiftController.php
Normal file
128
app/Http/Admin/Controllers/PointGiftController.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Admin\Controllers;
|
||||
|
||||
use App\Http\Admin\Services\PointGift as PointGiftService;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/admin/point/gift")
|
||||
*/
|
||||
class PointGiftController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Get("/list", name="admin.point_gift.list")
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$giftService = new PointGiftService();
|
||||
|
||||
$pager = $giftService->getGifts();
|
||||
|
||||
$this->view->pick('point/gift/list');
|
||||
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/add", name="admin.point_gift.add")
|
||||
*/
|
||||
public function addAction()
|
||||
{
|
||||
$this->view->pick('point/gift/add');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}/edit", name="admin.point_gift.edit")
|
||||
*/
|
||||
public function editAction($id)
|
||||
{
|
||||
$giftService = new PointGiftService();
|
||||
|
||||
$gift = $giftService->getGift($id);
|
||||
|
||||
$this->view->pick('point/gift/edit');
|
||||
|
||||
$this->view->setVar('gift', $gift);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/create", name="admin.point_gift.create")
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$giftService = new PointGiftService();
|
||||
|
||||
$gift = $giftService->createGift();
|
||||
|
||||
$location = $this->url->get([
|
||||
'for' => 'admin.point_gift.edit',
|
||||
'id' => $gift->id,
|
||||
]);
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '添加礼品成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/update", name="admin.point_gift.update")
|
||||
*/
|
||||
public function updateAction($id)
|
||||
{
|
||||
$giftService = new PointGiftService();
|
||||
|
||||
$giftService->updateGift($id);
|
||||
|
||||
$location = $this->url->get(['for' => 'admin.point_gift.list']);
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '更新礼品成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/delete", name="admin.point_gift.delete")
|
||||
*/
|
||||
public function deleteAction($id)
|
||||
{
|
||||
$giftService = new PointGiftService();
|
||||
|
||||
$giftService->deleteGift($id);
|
||||
|
||||
$location = $this->request->getHTTPReferer();
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '删除礼品成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/restore", name="admin.point_gift.restore")
|
||||
*/
|
||||
public function restoreAction($id)
|
||||
{
|
||||
$giftService = new PointGiftService();
|
||||
|
||||
$giftService->restoreGift($id);
|
||||
|
||||
$location = $this->request->getHTTPReferer();
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '还原礼品成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
}
|
60
app/Http/Admin/Controllers/PointRedeemController.php
Normal file
60
app/Http/Admin/Controllers/PointRedeemController.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Admin\Controllers;
|
||||
|
||||
use App\Http\Admin\Services\PointGift as PointGiftService;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/admin/point/redeem")
|
||||
*/
|
||||
class PointRedeemController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Get("/list", name="admin.point_redeem.list")
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$groupService = new PointGiftService();
|
||||
|
||||
$pager = $groupService->getGroups();
|
||||
|
||||
$this->view->pick('point/redeem/list');
|
||||
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}/edit", name="admin.point_redeem.edit")
|
||||
*/
|
||||
public function editAction($id)
|
||||
{
|
||||
$groupService = new PointGiftService();
|
||||
|
||||
$group = $groupService->getGroup($id);
|
||||
|
||||
$this->view->pick('point/redeem/edit');
|
||||
|
||||
$this->view->setVar('group', $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/update", name="admin.point_redeem.update")
|
||||
*/
|
||||
public function updateAction($id)
|
||||
{
|
||||
$groupService = new PointGiftService();
|
||||
|
||||
$groupService->updateGroup($id);
|
||||
|
||||
$location = $this->url->get(['for' => 'admin.point_redeem.list']);
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '更新群组成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
}
|
@ -50,7 +50,7 @@ class SettingController extends Controller
|
||||
|
||||
$data = $this->request->getPost();
|
||||
|
||||
$settingService->updateStorageSettings($section, $data);
|
||||
$settingService->updateSettings($section, $data);
|
||||
|
||||
return $this->jsonSuccess(['msg' => '更新配置成功']);
|
||||
|
||||
@ -248,6 +248,31 @@ class SettingController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/point", name="admin.setting.point")
|
||||
*/
|
||||
public function pointAction()
|
||||
{
|
||||
$section = 'point';
|
||||
|
||||
$settingService = new SettingService();
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
|
||||
$data = $this->request->getPost();
|
||||
|
||||
$settingService->updatePointSettings($section, $data);
|
||||
|
||||
return $this->jsonSuccess(['msg' => '更新配置成功']);
|
||||
|
||||
} else {
|
||||
|
||||
$point = $settingService->getSettings($section);
|
||||
|
||||
$this->view->setVar('point', $point);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/vip", name="admin.setting.vip")
|
||||
*/
|
||||
|
@ -476,6 +476,43 @@ class AuthNode extends Service
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => '2-8',
|
||||
'title' => '积分商城',
|
||||
'type' => 'menu',
|
||||
'children' => [
|
||||
[
|
||||
'id' => '2-8-1',
|
||||
'title' => '兑换记录',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.point_redeem.list',
|
||||
],
|
||||
[
|
||||
'id' => '2-8-2',
|
||||
'title' => '礼品列表',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.point_gift.list',
|
||||
],
|
||||
[
|
||||
'id' => '2-8-3',
|
||||
'title' => '添加礼品',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.point_gift.add',
|
||||
],
|
||||
[
|
||||
'id' => '2-8-4',
|
||||
'title' => '编辑礼品',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.point_gift.edit',
|
||||
],
|
||||
[
|
||||
'id' => '2-8-5',
|
||||
'title' => '删除礼品',
|
||||
'type' => 'button',
|
||||
'route' => 'admin.point_gift.delete',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
@ -763,6 +800,12 @@ class AuthNode extends Service
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.setting.wechat_oa',
|
||||
],
|
||||
[
|
||||
'id' => '5-1-14',
|
||||
'title' => '积分设置',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.setting.point',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
155
app/Http/Admin/Services/PointGift.php
Normal file
155
app/Http/Admin/Services/PointGift.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Admin\Services;
|
||||
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use App\Repos\PointGift as PointGiftRepo;
|
||||
use App\Validators\PointGift as PointGiftValidator;
|
||||
|
||||
class PointGift extends Service
|
||||
{
|
||||
|
||||
public function getGifts()
|
||||
{
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
|
||||
$params['deleted'] = $params['deleted'] ?? 0;
|
||||
|
||||
$sort = $pagerQuery->getSort();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$giftRepo = new PointGiftRepo();
|
||||
|
||||
return $giftRepo->paginate($params, $sort, $page, $limit);
|
||||
}
|
||||
|
||||
public function getGift($id)
|
||||
{
|
||||
return $this->findOrFail($id);
|
||||
}
|
||||
|
||||
public function createGift()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$validator = new PointGiftValidator();
|
||||
|
||||
$post['type'] = $validator->checkType($post['type']);
|
||||
|
||||
$gift = new PointGiftModel();
|
||||
|
||||
switch ($post['type']) {
|
||||
case PointGiftModel::TYPE_COURSE:
|
||||
$gift = $this->createCourseGift($post);
|
||||
break;
|
||||
case PointGiftModel::TYPE_GOODS:
|
||||
$gift = $this->createCommodityGift($post);
|
||||
break;
|
||||
}
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
public function updateGift($id)
|
||||
{
|
||||
$gift = $this->findOrFail($id);
|
||||
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$validator = new PointGiftValidator();
|
||||
|
||||
$data = [];
|
||||
|
||||
if (isset($post['cover'])) {
|
||||
$data['cover'] = $validator->checkCover($post['cover']);
|
||||
}
|
||||
|
||||
if (isset($post['name'])) {
|
||||
$data['name'] = $validator->checkName($post['name']);
|
||||
}
|
||||
|
||||
if (isset($post['details'])) {
|
||||
$data['details'] = $validator->checkDetails($post['details']);
|
||||
}
|
||||
|
||||
if (isset($post['point'])) {
|
||||
$data['point'] = $validator->checkPoint($post['point']);
|
||||
}
|
||||
|
||||
if (isset($post['stock'])) {
|
||||
$data['stock'] = $validator->checkStock($post['stock']);
|
||||
}
|
||||
|
||||
if (isset($post['published'])) {
|
||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||
}
|
||||
|
||||
$gift->update($data);
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
public function deleteGift($id)
|
||||
{
|
||||
$gift = $this->findOrFail($id);
|
||||
|
||||
$gift->deleted = 1;
|
||||
|
||||
$gift->update();
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
public function restoreGift($id)
|
||||
{
|
||||
$gift = $this->findOrFail($id);
|
||||
|
||||
$gift->deleted = 0;
|
||||
|
||||
$gift->update();
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
protected function createCourseGift($post)
|
||||
{
|
||||
$validator = new PointGiftValidator();
|
||||
|
||||
$course = $validator->checkCourse($post['course_id']);
|
||||
|
||||
$gift = new PointGiftModel();
|
||||
|
||||
$gift->type = PointGiftModel::TYPE_COURSE;
|
||||
$gift->name = $course->title;
|
||||
|
||||
$gift->create();
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
protected function createCommodityGift($post)
|
||||
{
|
||||
$validator = new PointGiftValidator();
|
||||
|
||||
$gift = new PointGiftModel();
|
||||
|
||||
$gift->type = PointGiftModel::TYPE_GOODS;
|
||||
$gift->name = $validator->checkName($post['name']);
|
||||
|
||||
$gift->create();
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
protected function findOrFail($id)
|
||||
{
|
||||
$validator = new PointGiftValidator();
|
||||
|
||||
return $validator->checkGift($id);
|
||||
}
|
||||
|
||||
}
|
@ -4,9 +4,10 @@ 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;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
|
||||
class Session extends Service
|
||||
{
|
||||
@ -47,21 +48,38 @@ class Session extends Service
|
||||
$captchaValidator->checkCode($post['ticket'], $post['rand']);
|
||||
}
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
|
||||
$this->auth->saveAuthInfo($user);
|
||||
|
||||
$this->fireAfterLoginEvent($user);
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$this->auth->clearAuthInfo();
|
||||
|
||||
$this->fireAfterLogoutEvent($user);
|
||||
}
|
||||
|
||||
protected function handleLoginNotice(UserModel $user)
|
||||
protected function fireAfterLoginEvent(UserModel $user)
|
||||
{
|
||||
$service = new AccountLoginNoticeService();
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$service->createTask($user);
|
||||
$eventsManager->fire('account:afterLogin', $this, $user);
|
||||
}
|
||||
|
||||
protected function fireAfterLogoutEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('account:afterLogout', $this, $user);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -181,6 +181,19 @@ class Setting extends Service
|
||||
$this->updateSettings($section, $settings);
|
||||
}
|
||||
|
||||
public function updatePointSettings($section, $settings)
|
||||
{
|
||||
if (isset($settings['event_rule'])) {
|
||||
$settings['event_rule'] = kg_json_encode($settings['event_rule']);
|
||||
}
|
||||
|
||||
if (isset($settings['consume_rule'])) {
|
||||
$settings['consume_rule'] = kg_json_encode($settings['consume_rule']);
|
||||
}
|
||||
|
||||
$this->updateSettings($section, $settings);
|
||||
}
|
||||
|
||||
public function updateVipSettings($items)
|
||||
{
|
||||
$vipRepo = new VipRepo();
|
||||
|
62
app/Http/Admin/Views/point/gift/add.volt
Normal file
62
app/Http/Admin/Views/point/gift/add.volt
Normal file
@ -0,0 +1,62 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form id="form-1" class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.point_gift.create'}) }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>添加礼品</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">礼品类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="type" value="1" title="课程" lay-filter="type">
|
||||
<input type="radio" name="type" value="2" title="商品" lay-filter="type">
|
||||
</div>
|
||||
</div>
|
||||
<div id="block-1" class="block" style="display:none;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">课程编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="item_id" value="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="block-2" class="block" style="display:none;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="name" value="">
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
layui.use(['jquery', 'form'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
|
||||
form.on('radio(type)', function (data) {
|
||||
var block = $('#block-' + data.value);
|
||||
$('.block').hide();
|
||||
block.show();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
108
app/Http/Admin/Views/point/gift/edit.volt
Normal file
108
app/Http/Admin/Views/point/gift/edit.volt
Normal file
@ -0,0 +1,108 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set update_url = url({'for':'admin.point_gift.update','id':gift.id}) %}
|
||||
|
||||
{% if gift.type == 1 %}
|
||||
<form class="layui-form kg-form" method="POST" action="{{ update_url }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>编辑礼品</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">课程封面</label>
|
||||
<div class="layui-input-inline">
|
||||
<img id="img-cover" class="kg-cover" src="{{ gift.cover }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">课程名称</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{ gift.name }}</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">所需积分</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="point" value="{{ gift.point }}" lay-verify="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">库存数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="stock" value="{{ gift.stock }}" lay-verify="number">
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if gift.type == 2 %}
|
||||
<form class="layui-form kg-form" method="POST" action="{{ update_url }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>编辑礼品</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品封面</label>
|
||||
<div class="layui-input-inline">
|
||||
<img id="img-cover" class="kg-cover" src="{{ gift.cover }}">
|
||||
<input type="hidden" name="cover" value="{{ gift.cover }}">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="padding-top:35px;">
|
||||
<button id="change-cover" class="layui-btn layui-btn-sm" type="button">更换</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="name" value="{{ gift.name }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品详情</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="vditor"></div>
|
||||
<textarea name="details" class="layui-hide" id="vditor-textarea">{{ gift.details }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">所需积分</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="point" value="{{ gift.point }}" lay-verify="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">库存数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="stock" value="{{ gift.stock }}" lay-verify="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="kg-submit layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block link_css %}
|
||||
|
||||
{{ css_link('https://cdn.jsdelivr.net/npm/vditor/dist/index.css', false) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://cdn.jsdelivr.net/npm/vditor/dist/index.min.js', false) }}
|
||||
{{ js_include('admin/js/cover.upload.js') }}
|
||||
{{ js_include('admin/js/vditor.js') }}
|
||||
|
||||
{% endblock %}
|
83
app/Http/Admin/Views/point/gift/list.volt
Normal file
83
app/Http/Admin/Views/point/gift/list.volt
Normal file
@ -0,0 +1,83 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{%- macro type_info(value) %}
|
||||
{% if value == 1 %}
|
||||
<span class="layui-badge layui-bg-green">课程</span>
|
||||
{% elseif value == 2 %}
|
||||
<span class="layui-badge layui-bg-blue">商品</span>
|
||||
{% elseif value == 3 %}
|
||||
<span class="layui-badge layui-bg-cyan">现金</span>
|
||||
{% else %}
|
||||
<span class="layui-badge layui-bg-gray">未知</span>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>礼品管理</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="kg-table layui-table layui-form">
|
||||
<group>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col width="12%">
|
||||
</group>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编号</th>
|
||||
<th>礼品名称</th>
|
||||
<th>所需积分</th>
|
||||
<th>库存数量</th>
|
||||
<th>兑换人次</th>
|
||||
<th>发布</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in pager.items %}
|
||||
{% set redeem_url = url({'for':'admin.point_redeem.list'},{'gift_id':item.id}) %}
|
||||
{% set preview_url = url({'for':'home.point_gift.show','id':item.id}) %}
|
||||
{% set edit_url = url({'for':'admin.point_gift.edit','id':item.id}) %}
|
||||
{% set update_url = url({'for':'admin.point_gift.update','id':item.id}) %}
|
||||
{% set delete_url = url({'for':'admin.point_gift.delete','id':item.id}) %}
|
||||
{% set restore_url = url({'for':'admin.point_gift.restore','id':item.id}) %}
|
||||
<tr>
|
||||
<td>{{ item.id }}</td>
|
||||
<td><a href="{{ edit_url }}">{{ item.name }}</a> {{ type_info(item.type) }}</td>
|
||||
<td>{{ item.point }}</td>
|
||||
<td>{{ item.stock }}</td>
|
||||
<td><a class="layui-badge layui-bg-green" href="{{ redeem_url }}">{{ item.redeem_count }}</a></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||
<ul>
|
||||
<li><a href="{{ preview_url }}" target="_blank">前台预览</a></li>
|
||||
<li><a href="{{ redeem_url }}">兑换记录</a></li>
|
||||
<li><a href="{{ edit_url }}">编辑</a></li>
|
||||
{% if item.deleted == 0 %}
|
||||
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
|
||||
{% else %}
|
||||
<li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ partial('partials/pager') }}
|
||||
|
||||
{% endblock %}
|
64
app/Http/Admin/Views/point/gift/search.volt
Normal file
64
app/Http/Admin/Views/point/gift/search.volt
Normal file
@ -0,0 +1,64 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form class="layui-form kg-form" method="GET" action="{{ url({'for':'admin.group.list'}) }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>搜索群组</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">群组编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="id" placeholder="群组编号精确匹配">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">群组名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="name" placeholder="群组名称模糊匹配">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">群主编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="user_id" placeholder="群主编号精确匹配">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">课程编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="course_id" placeholder="课程编号精确匹配">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="type" value="1" title="课程">
|
||||
<input type="radio" name="type" value="2" title="聊天">
|
||||
<input type="radio" name="type" value="3" title="职工">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发布</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="published" value="1" title="是">
|
||||
<input type="radio" name="published" value="0" title="否">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">删除</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="deleted" value="1" title="是">
|
||||
<input type="radio" name="deleted" value="0" title="否">
|
||||
</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">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
86
app/Http/Admin/Views/point/redeem/list.volt
Normal file
86
app/Http/Admin/Views/point/redeem/list.volt
Normal file
@ -0,0 +1,86 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{%- macro type_info(value) %}
|
||||
{% if value == 1 %}
|
||||
<span class="layui-badge layui-bg-green">课</span>
|
||||
{% elseif value == 2 %}
|
||||
<span class="layui-badge layui-bg-blue">聊</span>
|
||||
{% elseif value == 3 %}
|
||||
<span class="layui-badge layui-bg-cyan">职</span>
|
||||
{% else %}
|
||||
<span class="layui-badge layui-bg-gray">未知</span>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro owner_info(owner) %}
|
||||
{% if owner.id is defined %}
|
||||
{{ owner.name }}({{ owner.id }})
|
||||
{% else %}
|
||||
未设置
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
<div class="kg-nav">
|
||||
<div class="kg-nav-left">
|
||||
<span class="layui-breadcrumb">
|
||||
<a><cite>群组管理</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="kg-table layui-table layui-form">
|
||||
<colgroup>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
<col width="12%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编号</th>
|
||||
<th>名称</th>
|
||||
<th>群主</th>
|
||||
<th>成员</th>
|
||||
<th>发布</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in pager.items %}
|
||||
{% set preview_url = url({'for':'home.group.show','id':item.id}) %}
|
||||
{% set edit_url = url({'for':'admin.group.edit','id':item.id}) %}
|
||||
{% set update_url = url({'for':'admin.group.update','id':item.id}) %}
|
||||
{% set delete_url = url({'for':'admin.group.delete','id':item.id}) %}
|
||||
{% set restore_url = url({'for':'admin.group.restore','id':item.id}) %}
|
||||
<tr>
|
||||
<td>{{ item.id }}</td>
|
||||
<td><a href="{{ edit_url }}">{{ item.name }}</a> {{ type_info(item.type) }}</td>
|
||||
<td>{{ owner_info(item.owner) }}</td>
|
||||
<td><span class="layui-badge layui-bg-gray">{{ item.user_count }}</span></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||
<ul>
|
||||
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
|
||||
<li><a href="{{ edit_url }}">编辑</a></li>
|
||||
{% if item.deleted == 0 %}
|
||||
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
|
||||
{% else %}
|
||||
<li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ partial('partials/pager') }}
|
||||
|
||||
{% endblock %}
|
112
app/Http/Admin/Views/setting/point.volt
Normal file
112
app/Http/Admin/Views/setting/point.volt
Normal file
@ -0,0 +1,112 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set consume_rule = point.consume_rule|json_decode %}
|
||||
{% set event_rule = point.event_rule|json_decode %}
|
||||
|
||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.point'}) }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>积分设置</legend>
|
||||
</fieldset>
|
||||
<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 point.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="enabled" value="0" title="否" {% if point.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>消费奖励规则</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启用规则</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="consume_rule[enabled]" value="1" title="是" {% if consume_rule.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="consume_rule[enabled]" value="0" title="否" {% if consume_rule.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">奖励倍率</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="consume_rule[rate]" value="{{ consume_rule.rate }}" lay-verify="number">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">奖励积分 = 消费金额 X 奖励倍率</div>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>行为奖励规则</legend>
|
||||
</fieldset>
|
||||
<table class="layui-table kg-table layui-form" style="width:60%;">
|
||||
<colgroup>
|
||||
<col width="15%">
|
||||
<col>
|
||||
<col>
|
||||
<col>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>行为类型</th>
|
||||
<th>奖励积分</th>
|
||||
<th>每日上限</th>
|
||||
<th>启用规则</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>帐号注册</td>
|
||||
<td><input class="layui-input" type="text" name="event_rule[account_register][point]" value="{{ event_rule.account_register.point }}" lay-verify="required"></td>
|
||||
<td>N/A</td>
|
||||
<td>
|
||||
<input type="radio" name="event_rule[account_register][enabled]" value="1" title="是" {% if event_rule.account_register.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="event_rule[account_register][enabled]" value="0" title="否" {% if event_rule.account_register.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>站点访问</td>
|
||||
<td><input class="layui-input" type="text" name="event_rule[site_visit][point]" value="{{ event_rule.site_visit.point }}" lay-verify="required"></td>
|
||||
<td>N/A</td>
|
||||
<td>
|
||||
<input type="radio" name="event_rule[site_visit][enabled]" value="1" title="是" {% if event_rule.site_visit.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="event_rule[site_visit][enabled]" value="0" title="否" {% if event_rule.site_visit.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>课程评价</td>
|
||||
<td><input class="layui-input" type="text" name="event_rule[course_review][point]" value="{{ event_rule.course_review.point }}" lay-verify="required"></td>
|
||||
<td>N/A</td>
|
||||
<td>
|
||||
<input type="radio" name="event_rule[course_review][enabled]" value="1" title="是" {% if event_rule.course_review.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="event_rule[course_review][enabled]" value="0" title="否" {% if event_rule.course_review.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>课时学习</td>
|
||||
<td><input class="layui-input" type="text" name="event_rule[lesson_learning][point]" value="{{ event_rule.lesson_learning.point }}" lay-verify="required"></td>
|
||||
<td>N/A</td>
|
||||
<td>
|
||||
<input type="radio" name="event_rule[lesson_learning][enabled]" value="1" title="是" {% if event_rule.lesson_learning.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="event_rule[lesson_learning][enabled]" value="0" title="否" {% if event_rule.lesson_learning.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>群组讨论</td>
|
||||
<td><input class="layui-input" type="text" name="event_rule[group_discuss][point]" value="{{ event_rule.group_discuss.point }}" lay-verify="required"></td>
|
||||
<td>N/A</td>
|
||||
<td>
|
||||
<input type="radio" name="event_rule[group_discuss][enabled]" value="1" title="是" {% if event_rule.group_discuss.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="event_rule[group_discuss][enabled]" value="0" title="否" {% if event_rule.group_discuss.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -2,14 +2,22 @@
|
||||
|
||||
namespace App\Http\Api\Controllers;
|
||||
|
||||
use App\Services\Auth\Api as AppAuth;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Services\Auth\Api as ApiAuth;
|
||||
use App\Traits\Response as ResponseTrait;
|
||||
use App\Traits\Security as SecurityTrait;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
use Phalcon\Mvc\Dispatcher;
|
||||
|
||||
class Controller extends \Phalcon\Mvc\Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @var UserModel
|
||||
*/
|
||||
protected $authUser;
|
||||
|
||||
use ResponseTrait;
|
||||
use SecurityTrait;
|
||||
|
||||
@ -19,21 +27,36 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
$this->setCors();
|
||||
}
|
||||
|
||||
if (!$this->request->isOptions()) {
|
||||
$this->checkRateLimit();
|
||||
}
|
||||
$this->checkRateLimit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
$this->authUser = $this->getAuthUser();
|
||||
|
||||
$this->fireSiteViewEvent($this->authUser);
|
||||
}
|
||||
|
||||
protected function getAuthUser()
|
||||
{
|
||||
/**
|
||||
* @var AppAuth $auth
|
||||
* @var ApiAuth $auth
|
||||
*/
|
||||
$auth = $this->getDI()->get('auth');
|
||||
|
||||
return $auth->getCurrentUser();
|
||||
}
|
||||
|
||||
protected function fireSiteViewEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('site:view', $this, $user);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ 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;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
|
||||
class Account extends Service
|
||||
{
|
||||
@ -32,7 +33,11 @@ class Account extends Service
|
||||
|
||||
$user = $userRepo->findById($account->id);
|
||||
|
||||
return $this->auth->saveAuthInfo($user);
|
||||
$token = $this->auth->saveAuthInfo($user);
|
||||
|
||||
$this->fireAfterRegisterEvent($user);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function loginByPassword()
|
||||
@ -52,9 +57,11 @@ class Account extends Service
|
||||
|
||||
$user = $validator->checkUserLogin($post['account'], $post['password']);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
$token = $this->auth->saveAuthInfo($user);
|
||||
|
||||
return $this->auth->saveAuthInfo($user);
|
||||
$this->fireAfterLoginEvent($user);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function loginByVerify()
|
||||
@ -74,21 +81,50 @@ class Account extends Service
|
||||
|
||||
$user = $validator->checkVerifyLogin($post['account'], $post['verify_code']);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
$token = $this->auth->saveAuthInfo($user);
|
||||
|
||||
return $this->auth->saveAuthInfo($user);
|
||||
$this->fireAfterLoginEvent($user);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$this->auth->clearAuthInfo();
|
||||
|
||||
$this->fireAfterLogoutEvent($user);
|
||||
}
|
||||
|
||||
protected function handleLoginNotice(UserModel $user)
|
||||
protected function fireAfterRegisterEvent(UserModel $user)
|
||||
{
|
||||
$service = new AccountLoginNoticeService();
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$service->createTask($user);
|
||||
$eventsManager->fire('account:afterRegister', $this, $user);
|
||||
}
|
||||
|
||||
protected function fireAfterLoginEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('account:afterLogin', $this, $user);
|
||||
}
|
||||
|
||||
protected function fireAfterLogoutEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('account:afterLogout', $this, $user);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ use App\Services\Auth\Home as HomeAuth;
|
||||
use App\Services\Service as AppService;
|
||||
use App\Traits\Response as ResponseTrait;
|
||||
use App\Traits\Security as SecurityTrait;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
use Phalcon\Mvc\Dispatcher;
|
||||
|
||||
class Controller extends \Phalcon\Mvc\Controller
|
||||
@ -66,11 +68,7 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
$this->checkCsrfToken();
|
||||
}
|
||||
|
||||
$config = $this->getConfig();
|
||||
|
||||
if ($config->path('throttle.enabled')) {
|
||||
$this->checkRateLimit();
|
||||
}
|
||||
$this->checkRateLimit();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -82,6 +80,11 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
$this->appInfo = $this->getAppInfo();
|
||||
$this->imInfo = $this->getImInfo();
|
||||
|
||||
/**
|
||||
* @todo 内部操作会改变afterFetch()
|
||||
*/
|
||||
$this->fireSiteViewEvent($this->authUser);
|
||||
|
||||
$this->seo->setTitle($this->siteInfo['title']);
|
||||
|
||||
$this->view->setVar('seo', $this->seo);
|
||||
@ -158,4 +161,14 @@ class Controller extends \Phalcon\Mvc\Controller
|
||||
return $appService->getSettings($section);
|
||||
}
|
||||
|
||||
protected function fireSiteViewEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('site:view', $this, $user);
|
||||
}
|
||||
|
||||
}
|
||||
|
80
app/Http/Home/Controllers/PointGiftController.php
Normal file
80
app/Http/Home/Controllers/PointGiftController.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Home\Controllers;
|
||||
|
||||
use App\Services\Logic\Point\GiftInfo as GiftInfoService;
|
||||
use App\Services\Logic\Point\GiftList as GiftListService;
|
||||
use App\Services\Logic\Point\HotGiftList as HotGiftListService;
|
||||
use App\Services\Logic\Point\PointRedeem as GiftRedeemService;
|
||||
use Phalcon\Mvc\View;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/point/gift")
|
||||
*/
|
||||
class PointGiftController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Get("/list", name="home.point_gift.list")
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->seo->prependTitle('积分兑换');
|
||||
|
||||
$this->view->pick('point/gift/list');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/pager", name="home.point_gift.pager")
|
||||
*/
|
||||
public function pagerAction()
|
||||
{
|
||||
$service = new GiftListService();
|
||||
|
||||
$pager = $service->handle();
|
||||
|
||||
$pager->target = 'gift-list';
|
||||
|
||||
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
|
||||
$this->view->pick('point/gift/pager');
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}", name="home.point_gift.show")
|
||||
*/
|
||||
public function showAction($id)
|
||||
{
|
||||
$service = new GiftInfoService();
|
||||
|
||||
$gift = $service->handle($id);
|
||||
|
||||
$hotGifts = $this->getHotGifts();
|
||||
|
||||
$this->seo->prependTitle(['积分兑换', $gift['name']]);
|
||||
|
||||
$this->view->pick('point/gift/show');
|
||||
$this->view->setVar('gift', $gift);
|
||||
$this->view->setVar('hot_gifts', $hotGifts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/redeem", name="home.point_gift.redeem")
|
||||
*/
|
||||
public function redeemAction()
|
||||
{
|
||||
$service = new GiftRedeemService();
|
||||
|
||||
$service->handle();
|
||||
|
||||
return $this->jsonSuccess(['msg' => '兑换成功']);
|
||||
}
|
||||
|
||||
protected function getHotGifts()
|
||||
{
|
||||
$service = new HotGiftListService();
|
||||
|
||||
return $service->handle();
|
||||
}
|
||||
|
||||
}
|
35
app/Http/Home/Controllers/PointRedeemController.php
Normal file
35
app/Http/Home/Controllers/PointRedeemController.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Home\Controllers;
|
||||
|
||||
use App\Services\Logic\Point\PointRedeem as GiftRedeemService;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/point/redeem")
|
||||
*/
|
||||
class PointRedeemController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Post("/create", name="home.point_redeem.create")
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$service = new GiftRedeemService();
|
||||
|
||||
$service->handle();
|
||||
|
||||
return $this->jsonSuccess(['msg' => '兑换成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/list", name="home.point_gift.list")
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->seo->prependTitle('积分兑换');
|
||||
|
||||
$this->view->pick('point/gift/list');
|
||||
}
|
||||
|
||||
}
|
@ -8,11 +8,14 @@ use App\Services\Logic\User\Console\AccountInfo as AccountInfoService;
|
||||
use App\Services\Logic\User\Console\ConnectDelete as ConnectDeleteService;
|
||||
use App\Services\Logic\User\Console\ConnectList as ConnectListService;
|
||||
use App\Services\Logic\User\Console\ConsultList as ConsultListService;
|
||||
use App\Services\Logic\User\Console\ContactInfo as ContactInfoService;
|
||||
use App\Services\Logic\User\Console\ContactUpdate as ContactUpdateService;
|
||||
use App\Services\Logic\User\Console\CourseList as CourseListService;
|
||||
use App\Services\Logic\User\Console\FavoriteList as FavoriteListService;
|
||||
use App\Services\Logic\User\Console\FriendList as FriendListService;
|
||||
use App\Services\Logic\User\Console\GroupList as GroupListService;
|
||||
use App\Services\Logic\User\Console\OrderList as OrderListService;
|
||||
use App\Services\Logic\User\Console\PointRedeemList as PointRedeemListService;
|
||||
use App\Services\Logic\User\Console\ProfileInfo as ProfileInfoService;
|
||||
use App\Services\Logic\User\Console\ProfileUpdate as ProfileUpdateService;
|
||||
use App\Services\Logic\User\Console\RefundList as RefundListService;
|
||||
@ -67,6 +70,19 @@ class UserConsoleController extends Controller
|
||||
$this->view->setVar('user', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/contact", name="home.uc.contact")
|
||||
*/
|
||||
public function contactAction()
|
||||
{
|
||||
$service = new ContactInfoService();
|
||||
|
||||
$contact = $service->handle();
|
||||
|
||||
$this->view->pick('user/console/contact');
|
||||
$this->view->setVar('contact', $contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/account", name="home.uc.account")
|
||||
*/
|
||||
@ -182,6 +198,19 @@ class UserConsoleController extends Controller
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/point_redeems", name="home.uc.point_redeems")
|
||||
*/
|
||||
public function pointRedeemsAction()
|
||||
{
|
||||
$service = new PointRedeemListService();
|
||||
|
||||
$pager = $service->handle();
|
||||
|
||||
$this->view->pick('user/console/point_redeems');
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/friends", name="home.uc.friends")
|
||||
*/
|
||||
@ -249,6 +278,20 @@ class UserConsoleController extends Controller
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/contact/update", name="home.uc.update_contact")
|
||||
*/
|
||||
public function updateContactAction()
|
||||
{
|
||||
$service = new ContactUpdateService();
|
||||
|
||||
$service->handle();
|
||||
|
||||
$content = ['msg' => '更新收货信息成功'];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/connect/{id:[0-9]+}/delete", name="home.uc.unconnect")
|
||||
*/
|
||||
|
@ -6,9 +6,10 @@ 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;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
|
||||
class Account extends Service
|
||||
{
|
||||
@ -35,6 +36,8 @@ class Account extends Service
|
||||
|
||||
$this->auth->saveAuthInfo($user);
|
||||
|
||||
$this->fireAfterRegisterEvent($user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
@ -50,9 +53,9 @@ class Account extends Service
|
||||
|
||||
$validator->checkCode($post['ticket'], $post['rand']);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
|
||||
$this->auth->saveAuthInfo($user);
|
||||
|
||||
$this->fireAfterLoginEvent($user);
|
||||
}
|
||||
|
||||
public function loginByVerify()
|
||||
@ -63,21 +66,48 @@ class Account extends Service
|
||||
|
||||
$user = $validator->checkVerifyLogin($post['account'], $post['verify_code']);
|
||||
|
||||
$this->handleLoginNotice($user);
|
||||
|
||||
$this->auth->saveAuthInfo($user);
|
||||
|
||||
$this->fireAfterLoginEvent($user);
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$this->auth->clearAuthInfo();
|
||||
|
||||
$this->fireAfterLogoutEvent($user);
|
||||
}
|
||||
|
||||
protected function handleLoginNotice(UserModel $user)
|
||||
protected function fireAfterRegisterEvent(UserModel $user)
|
||||
{
|
||||
$service = new AccountLoginNoticeService();
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$service->createTask($user);
|
||||
$eventsManager->fire('account:afterRegister', $this, $user);
|
||||
}
|
||||
|
||||
protected function fireAfterLoginEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('account:afterLogin', $this, $user);
|
||||
}
|
||||
|
||||
protected function fireAfterLogoutEvent(UserModel $user)
|
||||
{
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('account:afterLogout', $this, $user);
|
||||
}
|
||||
|
||||
}
|
||||
|
9
app/Http/Home/Views/macros/point.volt
Normal file
9
app/Http/Home/Views/macros/point.volt
Normal file
@ -0,0 +1,9 @@
|
||||
{%- macro gift_type_info(value) %}
|
||||
{% if value == 1 %}
|
||||
<span class="layui-badge layui-bg-green type">课程</span>
|
||||
{% elseif value == 2 %}
|
||||
<span class="layui-badge layui-bg-blue type">商品</span>
|
||||
{% elseif value == 3 %}
|
||||
<span class="layui-badge layui-bg-cyan type">现金</span>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
@ -32,6 +32,9 @@
|
||||
<li class="layui-nav-item">
|
||||
<a href="javascript:" class="nav-search" data-type="{{ s_type }}" data-query="{{ s_query }}" data-url="{{ s_url }}"><i class="layui-icon layui-icon-search"></i> 搜索</a>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a href="{{ url({'for':'home.point_gift.list'}) }}" class="nav-point-gift"><i class="layui-icon layui-icon-gift"></i> 积分</a>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a href="{{ url({'for':'home.vip.index'}) }}" class="nav-vip"><i class="layui-icon layui-icon-diamond"></i> 会员</a>
|
||||
</li>
|
||||
|
20
app/Http/Home/Views/point/gift/list.volt
Normal file
20
app/Http/Home/Views/point/gift/list.volt
Normal file
@ -0,0 +1,20 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set pager_url = url({'for':'home.point_gift.pager'}) %}
|
||||
|
||||
<div class="layui-breadcrumb breadcrumb">
|
||||
<a href="/">首页</a>
|
||||
<a><cite>积分兑换</cite></a>
|
||||
</div>
|
||||
|
||||
<div id="gift-list" data-url="{{ pager_url }}"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('home/js/point.gift.list.js') }}
|
||||
|
||||
{% endblock %}
|
31
app/Http/Home/Views/point/gift/pager.volt
Normal file
31
app/Http/Home/Views/point/gift/pager.volt
Normal file
@ -0,0 +1,31 @@
|
||||
{{ partial('macros/point') }}
|
||||
|
||||
{% if pager.total_pages > 0 %}
|
||||
<div class="course-list clearfix">
|
||||
<div class="layui-row layui-col-space20">
|
||||
{% for item in pager.items %}
|
||||
{% set gift_url = url({'for':'home.point_gift.show','id':item.id}) %}
|
||||
<div class="layui-col-md3">
|
||||
<div class="course-card">
|
||||
<div class="cover">
|
||||
<a href="{{ gift_url }}">
|
||||
<img src="{{ item.cover }}" alt="item.name">
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="title layui-elip">
|
||||
<a href="{{ gift_url }}">{{ item.name }}</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
{{ gift_type_info(item.type) }}
|
||||
<span class="price">{{ item.point }} 积分</span>
|
||||
<span>{{ item.redeem_count }} 人兑换</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{{ partial('partials/pager_ajax') }}
|
||||
{% endif %}
|
89
app/Http/Home/Views/point/gift/show.volt
Normal file
89
app/Http/Home/Views/point/gift/show.volt
Normal file
@ -0,0 +1,89 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set gift_redeem_url = url({'for':'home.point_redeem.create'}) %}
|
||||
{% set gift_list_url = url({'for':'home.point_gift.list'}) %}
|
||||
|
||||
<div class="breadcrumb">
|
||||
<span class="layui-breadcrumb">
|
||||
<a href="/">首页</a>
|
||||
<a href="{{ gift_list_url }}">积分兑换</a>
|
||||
<a><cite>{{ gift.name }}</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="layout-main clearfix">
|
||||
<div class="layout-content">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">商品信息</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="gift-meta clearfix">
|
||||
<div class="cover">
|
||||
<img src="{{ gift.cover }}!cover_270" alt="{{ gift.name }}">
|
||||
</div>
|
||||
<div class="info">
|
||||
<p class="item">{{ gift.name }}</p>
|
||||
<p class="item stats">
|
||||
<span class="key">兑换价格</span>
|
||||
<span class="price">{{ gift.point }} 积分</span>
|
||||
<span class="key">兑换人次</span>
|
||||
<span class="value">{{ gift.redeem_count }}</span>
|
||||
</p>
|
||||
<p class="item">
|
||||
<button class="layui-btn layui-bg-red btn-redeem" data-id="{{ gift.id }}" data-url="{{ gift_redeem_url }}">立即兑换</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">商品详情</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="gift-details markdown-body">{{ gift.details }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-sidebar">
|
||||
<div class="sidebar">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">热门商品</div>
|
||||
<div class="layui-card-body">
|
||||
{% for gift in hot_gifts %}
|
||||
{% set gift_url = url({'for':'home.point_gift.show','id':gift.id}) %}
|
||||
<div class="sidebar-course-card clearfix">
|
||||
<div class="cover">
|
||||
<a href="{{ gift_url }}" title="{{ gift.name }}">
|
||||
<img src="{{ gift.cover }}!cover_270" alt="{{ gift.name }}">
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="title layui-elip">
|
||||
<a href="{{ gift_url }}" title="{{ gift.name }}">{{ gift.name }}</a>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<span class="price">{{ gift.point }} 积分</span>
|
||||
<span class="count">{{ gift.redeem_count }} 人兑换</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block link_css %}
|
||||
|
||||
{{ css_link('home/css/markdown.css') }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('home/js/point.gift.show.js') }}
|
||||
|
||||
{% endblock %}
|
69
app/Http/Home/Views/user/console/contact.volt
Normal file
69
app/Http/Home/Views/user/console/contact.volt
Normal file
@ -0,0 +1,69 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% set update_url = url({'for':'home.uc.update_contact'}) %}
|
||||
|
||||
<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>
|
||||
<form class="layui-form profile-form" method="post" action="{{ update_url }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">真实姓名</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="name" value="{{ contact.name }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机号码</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="phone" value="{{ contact.phone }}" lay-verify="phone">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="area-picker" style="margin-bottom: 25px;">
|
||||
<div class="layui-form-label">所在地区</div>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<select name="address[province]" class="province-selector" data-value="{{ contact.add_province }}" lay-verify="required">
|
||||
<option value="">请选择省</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<select name="address[city]" class="city-selector" data-value="{{ contact.add_city }}" lay-verify="required">
|
||||
<option value="">请选择市</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<select name="address[county]" class="county-selector" data-value="{{ contact.add_county }}">
|
||||
<option value="">请选择区</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">详细地址</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea class="layui-textarea" name="address[other]" lay-verify="required">{{ contact.add_other }}</textarea>
|
||||
</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 class="layui-btn layui-btn-primary" type="reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('home/js/user.console.contact.js') }}
|
||||
|
||||
{% endblock %}
|
@ -51,6 +51,7 @@
|
||||
<div class="layui-card-body">
|
||||
<ul class="my-menu">
|
||||
<li><a href="{{ url({'for':'home.uc.profile'}) }}">个人信息</a></li>
|
||||
<li><a href="{{ url({'for':'home.uc.contact'}) }}">收货地址</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>
|
||||
|
42
app/Listeners/Account.php
Normal file
42
app/Listeners/Account.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
|
||||
use App\Services\Logic\Point\PointHistory as PointHistoryService;
|
||||
use Phalcon\Events\Event;
|
||||
|
||||
class Account extends Listener
|
||||
{
|
||||
|
||||
public function afterRegister(Event $event, $source, UserModel $user)
|
||||
{
|
||||
$this->handleRegisterPoint($user);
|
||||
}
|
||||
|
||||
public function afterLogin(Event $event, $source, UserModel $user)
|
||||
{
|
||||
$this->handleLoginNotice($user);
|
||||
}
|
||||
|
||||
public function afterLogout(Event $event, $source, UserModel $user)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function handleRegisterPoint(UserModel $user)
|
||||
{
|
||||
$service = new PointHistoryService();
|
||||
|
||||
$service->handleAccountRegister($user);
|
||||
}
|
||||
|
||||
protected function handleLoginNotice(UserModel $user)
|
||||
{
|
||||
$service = new AccountLoginNoticeService();
|
||||
|
||||
$service->createTask($user);
|
||||
}
|
||||
|
||||
}
|
@ -8,6 +8,28 @@ use Phalcon\Mvc\User\Plugin as UserPlugin;
|
||||
class Listener extends UserPlugin
|
||||
{
|
||||
|
||||
public function getConfig()
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getConfig();
|
||||
}
|
||||
|
||||
|
||||
public function getCache()
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getCache();
|
||||
}
|
||||
|
||||
public function getRedis()
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
||||
return $appService->getRedis();
|
||||
}
|
||||
|
||||
public function getLogger($channel = null)
|
||||
{
|
||||
$appService = new AppService();
|
||||
|
116
app/Listeners/Site.php
Normal file
116
app/Listeners/Site.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Library\Utils\Lock as LockUtil;
|
||||
use App\Models\Online as OnlineModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Online as OnlineRepo;
|
||||
use App\Services\Logic\Point\PointHistory as PointHistoryService;
|
||||
use App\Traits\Client as ClientTrait;
|
||||
use Phalcon\Events\Event;
|
||||
|
||||
class Site extends Listener
|
||||
{
|
||||
|
||||
use ClientTrait;
|
||||
|
||||
/**
|
||||
* 访问站点
|
||||
*
|
||||
* @param Event $event
|
||||
* @param $source
|
||||
* @param UserModel $user
|
||||
*/
|
||||
public function view(Event $event, $source, UserModel $user)
|
||||
{
|
||||
if ($user->id > 0) {
|
||||
$this->handleOnline($user);
|
||||
$this->handleVisitPoint($user);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleOnline(UserModel $user)
|
||||
{
|
||||
$now = time();
|
||||
|
||||
if ($now - $user->active_time < 900) {
|
||||
return;
|
||||
}
|
||||
|
||||
$itemId = "user_online:{$user->id}";
|
||||
|
||||
$clientType = $this->getClientType();
|
||||
$clientIp = $this->getClientIp();
|
||||
|
||||
$lockId = LockUtil::addLock($itemId);
|
||||
|
||||
$user->active_time = $now;
|
||||
|
||||
$user->update();
|
||||
|
||||
$onlineRepo = new OnlineRepo();
|
||||
|
||||
$records = $onlineRepo->findByUserDate($user->id, date('Y-m-d'));
|
||||
|
||||
if ($records->count() > 0) {
|
||||
$online = null;
|
||||
foreach ($records as $record) {
|
||||
$case1 = $record->client_type == $clientType;
|
||||
$case2 = $record->client_ip == $clientIp;
|
||||
if ($case1 && $case2) {
|
||||
$online = $record;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($online) {
|
||||
$online->active_time = $now;
|
||||
$online->update();
|
||||
} else {
|
||||
$this->createOnline($user->id, $clientType, $clientIp);
|
||||
}
|
||||
} else {
|
||||
$this->createOnline($user->id, $clientType, $clientIp);
|
||||
}
|
||||
|
||||
LockUtil::releaseLock($itemId, $lockId);
|
||||
}
|
||||
|
||||
protected function createOnline($userId, $clientType, $clientIp)
|
||||
{
|
||||
$online = new OnlineModel();
|
||||
|
||||
$online->user_id = $userId;
|
||||
$online->client_type = $clientType;
|
||||
$online->client_ip = $clientIp;
|
||||
$online->active_time = time();
|
||||
|
||||
$online->create();
|
||||
|
||||
return $online;
|
||||
}
|
||||
|
||||
protected function handleVisitPoint(UserModel $user)
|
||||
{
|
||||
$todayDate = date('Ymd');
|
||||
|
||||
$keyName = sprintf('site_visit:%s:%s', $user->id, $todayDate);
|
||||
|
||||
$cache = $this->getCache();
|
||||
|
||||
$content = $cache->get($keyName);
|
||||
|
||||
if ($content) return;
|
||||
|
||||
$service = new PointHistoryService();
|
||||
|
||||
$service->handleSiteVisit($user);
|
||||
|
||||
$tomorrow = strtotime($todayDate) + 86400;
|
||||
|
||||
$lifetime = $tomorrow - time();
|
||||
|
||||
$cache->save($keyName, 1, $lifetime);
|
||||
}
|
||||
|
||||
}
|
@ -2,10 +2,7 @@
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Library\Utils\Lock as LockUtil;
|
||||
use App\Models\Online as OnlineModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Online as OnlineRepo;
|
||||
use App\Traits\Client as ClientTrait;
|
||||
use Phalcon\Events\Event;
|
||||
|
||||
@ -14,64 +11,9 @@ class User extends Listener
|
||||
|
||||
use ClientTrait;
|
||||
|
||||
public function online(Event $event, $source, UserModel $user)
|
||||
public function view(Event $event, $source, UserModel $user)
|
||||
{
|
||||
$itemId = "user:{$user->id}";
|
||||
|
||||
$lockId = LockUtil::addLock($itemId);
|
||||
|
||||
$now = time();
|
||||
$clientType = $this->getClientType();
|
||||
$clientIp = $this->getClientIp();
|
||||
|
||||
if ($now - $user->active_time > 600) {
|
||||
|
||||
$user->active_time = $now;
|
||||
|
||||
$user->update();
|
||||
|
||||
$onlineRepo = new OnlineRepo();
|
||||
|
||||
$records = $onlineRepo->findByUserDate($user->id, date('Y-m-d'));
|
||||
|
||||
if ($records->count() > 0) {
|
||||
|
||||
$online = null;
|
||||
|
||||
foreach ($records as $record) {
|
||||
if ($record->client_type == $clientType && $record->client_ip == $clientIp) {
|
||||
$online = $record;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($online) {
|
||||
$online->active_time = $now;
|
||||
$online->update();
|
||||
} else {
|
||||
$this->createOnline($user->id, $clientType, $clientIp);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->createOnline($user->id, $clientType, $clientIp);
|
||||
}
|
||||
}
|
||||
|
||||
LockUtil::releaseLock($itemId, $lockId);
|
||||
}
|
||||
|
||||
protected function createOnline($userId, $clientType, $clientIp)
|
||||
{
|
||||
$online = new OnlineModel();
|
||||
|
||||
$online->user_id = $userId;
|
||||
$online->client_type = $clientType;
|
||||
$online->client_ip = $clientIp;
|
||||
$online->active_time = time();
|
||||
|
||||
$online->create();
|
||||
|
||||
return $online;
|
||||
}
|
||||
|
||||
}
|
@ -205,22 +205,18 @@ class Chapter extends Model
|
||||
$this->model = $course->model;
|
||||
|
||||
if ($this->parent_id > 0) {
|
||||
|
||||
$attrs = [];
|
||||
|
||||
switch ($course->model) {
|
||||
case Course::MODEL_VOD:
|
||||
$attrs = $this->_vod_attrs;
|
||||
break;
|
||||
case Course::MODEL_LIVE:
|
||||
$attrs = $this->_live_attrs;
|
||||
break;
|
||||
case Course::MODEL_READ:
|
||||
$attrs = $this->_read_attrs;
|
||||
break;
|
||||
if (empty($this->attrs)) {
|
||||
if ($this->model == Course::MODEL_VOD) {
|
||||
$this->attrs = $this->_vod_attrs;
|
||||
} elseif ($this->model == Course::MODEL_LIVE) {
|
||||
$this->attrs = $this->_live_attrs;
|
||||
} elseif ($this->model == Course::MODEL_READ) {
|
||||
$this->attrs = $this->_read_attrs;
|
||||
}
|
||||
}
|
||||
if (is_array($this->attrs) && !empty($this->attrs)) {
|
||||
$this->attrs = kg_json_encode($this->attrs);
|
||||
}
|
||||
|
||||
$this->attrs = kg_json_encode($attrs);
|
||||
}
|
||||
|
||||
$this->create_time = time();
|
||||
|
@ -271,18 +271,18 @@ class Course extends Model
|
||||
|
||||
public function beforeCreate()
|
||||
{
|
||||
$attrs = [];
|
||||
if (empty($this->attrs)) {
|
||||
if ($this->model == self::MODEL_VOD) {
|
||||
$this->attrs = $this->_vod_attrs;
|
||||
} elseif ($this->model == self::MODEL_LIVE) {
|
||||
$this->attrs = $this->_live_attrs;
|
||||
} elseif ($this->model == self::MODEL_READ) {
|
||||
$this->attrs = $this->_read_attrs;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->model) {
|
||||
case Course::MODEL_VOD:
|
||||
$attrs = $this->_vod_attrs;
|
||||
break;
|
||||
case Course::MODEL_LIVE:
|
||||
$attrs = $this->_live_attrs;
|
||||
break;
|
||||
case Course::MODEL_READ:
|
||||
$attrs = $this->_read_attrs;
|
||||
break;
|
||||
if (is_array($this->attrs) && !empty($this->attrs)) {
|
||||
$this->attrs = kg_json_encode($this->attrs);
|
||||
}
|
||||
|
||||
if (empty($this->cover)) {
|
||||
@ -298,10 +298,6 @@ class Course extends Model
|
||||
$this->details = '';
|
||||
}
|
||||
|
||||
if (!empty($attrs)) {
|
||||
$this->attrs = kg_json_encode($attrs);
|
||||
}
|
||||
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@ class CourseUser extends Model
|
||||
const SOURCE_CHARGE = 2; // 付费
|
||||
const SOURCE_VIP = 3; // 会员
|
||||
const SOURCE_IMPORT = 4; // 导入
|
||||
const SOURCE_POINT_REDEEM = 5; // 积分兑换
|
||||
const SOURCE_LUCKY_REDEEM = 6; // 抽奖兑换
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
|
235
app/Models/PointGift.php
Normal file
235
app/Models/PointGift.php
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Caches\MaxPointGiftId as MaxPointGiftIdCache;
|
||||
use Phalcon\Mvc\Model\Behavior\SoftDelete;
|
||||
use Phalcon\Text;
|
||||
|
||||
class PointGift extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 礼物类型
|
||||
*/
|
||||
const TYPE_COURSE = 1; // 课程
|
||||
const TYPE_GOODS = 2; // 商品
|
||||
const TYPE_CASH = 3; // 现金
|
||||
|
||||
/**
|
||||
* 课程扩展属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_course_attrs = [
|
||||
'id' => 0,
|
||||
'title' => '',
|
||||
'market_price' => 0,
|
||||
'study_expiry_time' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 商品扩展属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_goods_attrs = [
|
||||
'source' => '',
|
||||
'price' => 0,
|
||||
'url' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* 现金扩展属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_cash_attrs = ['amount' => 0];
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id = 0;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* 封面
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cover = '';
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $details = '';
|
||||
|
||||
/**
|
||||
* 属性
|
||||
*
|
||||
* @var string|array
|
||||
*/
|
||||
public $attrs = [];
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $type = 0;
|
||||
|
||||
/**
|
||||
* 库存
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $stock = 0;
|
||||
|
||||
/**
|
||||
* 所需积分
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $point = 0;
|
||||
|
||||
/**
|
||||
* 发布标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $published = 0;
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted = 0;
|
||||
|
||||
/**
|
||||
* 兑换数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $redeem_count = 0;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time = 0;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time = 0;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_point_gift';
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->addBehavior(
|
||||
new SoftDelete([
|
||||
'field' => 'deleted',
|
||||
'value' => 1,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public function beforeCreate()
|
||||
{
|
||||
if (empty($this->attrs)) {
|
||||
if ($this->type == self::TYPE_COURSE) {
|
||||
$this->attrs = $this->_course_attrs;
|
||||
} elseif ($this->type == self::TYPE_GOODS) {
|
||||
$this->attrs = $this->_goods_attrs;
|
||||
} elseif ($this->type == self::TYPE_CASH) {
|
||||
$this->attrs = $this->_cash_attrs;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($this->attrs) && !empty($this->attrs)) {
|
||||
$this->attrs = kg_json_encode($this->attrs);
|
||||
}
|
||||
|
||||
if (empty($this->cover)) {
|
||||
$this->cover = kg_default_cover_path();
|
||||
} elseif (Text::startsWith($this->cover, 'http')) {
|
||||
$this->cover = self::getCoverPath($this->cover);
|
||||
}
|
||||
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
public function beforeUpdate()
|
||||
{
|
||||
if (Text::startsWith($this->cover, 'http')) {
|
||||
$this->cover = self::getCoverPath($this->cover);
|
||||
}
|
||||
|
||||
if (is_array($this->attrs) && !empty($this->attrs)) {
|
||||
$this->attrs = kg_json_encode($this->attrs);
|
||||
}
|
||||
|
||||
if ($this->deleted == 1) {
|
||||
$this->published = 0;
|
||||
}
|
||||
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
public function afterCreate()
|
||||
{
|
||||
$cache = new MaxPointGiftIdCache();
|
||||
|
||||
$cache->rebuild();
|
||||
}
|
||||
|
||||
public function afterFetch()
|
||||
{
|
||||
if (!Text::startsWith($this->cover, 'http')) {
|
||||
$this->cover = kg_cos_cover_url($this->cover);
|
||||
}
|
||||
|
||||
if (is_string($this->attrs) && !empty($this->attrs)) {
|
||||
$this->attrs = json_decode($this->attrs, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getCoverPath($url)
|
||||
{
|
||||
if (Text::startsWith($url, 'http')) {
|
||||
return parse_url($url, PHP_URL_PATH);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public static function types()
|
||||
{
|
||||
return [
|
||||
self::TYPE_COURSE => '课程',
|
||||
self::TYPE_GOODS => '商品',
|
||||
self::TYPE_CASH => '现金',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
133
app/Models/PointHistory.php
Normal file
133
app/Models/PointHistory.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Phalcon\Mvc\Model\Behavior\SoftDelete;
|
||||
|
||||
class PointHistory extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
const EVENT_ORDER_CONSUME = 1; // 订单消费
|
||||
const EVENT_POINT_REDEEM = 2; // 积分兑换
|
||||
const EVENT_POINT_REFUND = 3; // 积分退款
|
||||
const EVENT_ACCOUNT_REGISTER = 4; // 帐号注册
|
||||
const EVENT_SITE_VISIT = 5; // 站点访问
|
||||
const EVENT_LESSON_LEARNING = 6; // 课时学习
|
||||
const EVENT_COURSE_REVIEW = 7; // 课程评价
|
||||
const EVENT_GROUP_DISCUSS = 8; // 群组讨论
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id = 0;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id = 0;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_name = '';
|
||||
|
||||
/**
|
||||
* 事件编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $event_id = 0;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $event_type = '';
|
||||
|
||||
/**
|
||||
* 事件内容
|
||||
*
|
||||
* @var string|array
|
||||
*/
|
||||
public $event_info = [];
|
||||
|
||||
/**
|
||||
* 事件积分
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $event_point = 0;
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted = 0;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time = 0;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time = 0;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_point_history';
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public static function eventTypes()
|
||||
{
|
||||
return [
|
||||
self::EVENT_ORDER_CONSUME => '订单消费',
|
||||
self::EVENT_POINT_REDEEM => '积分兑换',
|
||||
self::EVENT_POINT_REFUND => '积分退款',
|
||||
self::EVENT_ACCOUNT_REGISTER => '用户注册',
|
||||
self::EVENT_SITE_VISIT => '用户登录',
|
||||
self::EVENT_LESSON_LEARNING => '课时学习',
|
||||
self::EVENT_COURSE_REVIEW => '课程评价',
|
||||
self::EVENT_GROUP_DISCUSS => '群组讨论',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
130
app/Models/PointRedeem.php
Normal file
130
app/Models/PointRedeem.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class PointRedeem extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 状态类型
|
||||
*/
|
||||
const STATUS_PENDING = 1; // 待处理
|
||||
const STATUS_FINISHED = 2; // 已完成
|
||||
const STATUS_FAILED = 3; // 已失败
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id = 0;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id = 0;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $user_name = '';
|
||||
|
||||
/**
|
||||
* 礼品编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $gift_id = 0;
|
||||
|
||||
/**
|
||||
* 礼品名称
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $gift_name = '';
|
||||
|
||||
/**
|
||||
* 礼品类型
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $gift_type = 0;
|
||||
|
||||
/**
|
||||
* 礼品积分
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $gift_point = 0;
|
||||
|
||||
/**
|
||||
* 联系人
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $contact_name = '';
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $contact_phone = '';
|
||||
|
||||
/**
|
||||
* 联系地址
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $contact_address = '';
|
||||
|
||||
/**
|
||||
* 备注内容
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $remark = '';
|
||||
|
||||
/**
|
||||
* 兑换状态
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $status = 0;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time = 0;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time = 0;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_point_redeem';
|
||||
}
|
||||
|
||||
public function beforeCreate()
|
||||
{
|
||||
$this->status = self::STATUS_PENDING;
|
||||
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
public function beforeUpdate()
|
||||
{
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,8 @@ class Task extends Model
|
||||
*/
|
||||
const TYPE_DELIVER = 1; // 发货
|
||||
const TYPE_REFUND = 2; // 退款
|
||||
const TYPE_POINT_GIFT_AWARD = 3; // 积分礼品派发
|
||||
const TYPE_LUCKY_GIFT_AWARD = 4; // 抽奖礼品派发
|
||||
|
||||
const TYPE_NOTICE_ACCOUNT_LOGIN = 11; // 帐号登录通知
|
||||
const TYPE_NOTICE_LIVE_BEGIN = 12; // 直播开始通知
|
||||
|
78
app/Models/UserBalance.php
Normal file
78
app/Models/UserBalance.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Phalcon\Mvc\Model\Behavior\SoftDelete;
|
||||
|
||||
class UserBalance extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 用户编号(主键)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id = 0;
|
||||
|
||||
/**
|
||||
* 可用现金(元)
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $cash = 0.00;
|
||||
|
||||
/**
|
||||
* 可用积分
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $point = 0;
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted = 0;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time = 0;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time = 0;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_user_balance';
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->addBehavior(
|
||||
new SoftDelete([
|
||||
'field' => 'deleted',
|
||||
'value' => 1,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public function beforeSave()
|
||||
{
|
||||
if (empty($this->create_time)) {
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
}
|
107
app/Models/UserContact.php
Normal file
107
app/Models/UserContact.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Phalcon\Mvc\Model\Behavior\SoftDelete;
|
||||
|
||||
|
||||
class UserContact extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* 用户编号(主键)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id = 0;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* 手机
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $phone = '';
|
||||
|
||||
/**
|
||||
* 地址(省)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $add_province = '';
|
||||
|
||||
/**
|
||||
* 地址(市)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $add_city = '';
|
||||
|
||||
/**
|
||||
* 地址(区)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $add_county = '';
|
||||
|
||||
/**
|
||||
* 地址(详)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $add_other = '';
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted = 0;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time = 0;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time = 0;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_user_contact';
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->addBehavior(
|
||||
new SoftDelete([
|
||||
'field' => 'deleted',
|
||||
'value' => 1,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public function beforeSave()
|
||||
{
|
||||
if (empty($this->create_time)) {
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
}
|
87
app/Repos/PointGift.php
Normal file
87
app/Repos/PointGift.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class PointGift extends Repository
|
||||
{
|
||||
|
||||
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
|
||||
{
|
||||
$builder = $this->modelsManager->createBuilder();
|
||||
|
||||
$builder->from(PointGiftModel::class);
|
||||
|
||||
$builder->where('1 = 1');
|
||||
|
||||
if (!empty($where['id'])) {
|
||||
$builder->andWhere('id = :id:', ['id' => $where['id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['type'])) {
|
||||
$builder->andWhere('type = :type:', ['type' => $where['type']]);
|
||||
}
|
||||
|
||||
if (!empty($where['name'])) {
|
||||
$builder->andWhere('name LIKE :name:', ['name' => "%{$where['name']}%"]);
|
||||
}
|
||||
|
||||
if (isset($where['published'])) {
|
||||
$builder->andWhere('published = :published:', ['published' => $where['published']]);
|
||||
}
|
||||
|
||||
if (isset($where['deleted'])) {
|
||||
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
|
||||
}
|
||||
|
||||
switch ($sort) {
|
||||
case 'popular':
|
||||
$orderBy = 'redeem_count DESC';
|
||||
break;
|
||||
default:
|
||||
$orderBy = 'id DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
$builder->orderBy($orderBy);
|
||||
|
||||
$pager = new PagerQueryBuilder([
|
||||
'builder' => $builder,
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
return $pager->paginate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return PointGiftModel|Model|bool
|
||||
*/
|
||||
public function findById($id)
|
||||
{
|
||||
return PointGiftModel::findFirst([
|
||||
'conditions' => 'id = :id:',
|
||||
'bind' => ['id' => $id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
* @param string|array $columns
|
||||
* @return ResultsetInterface|Resultset|PointGiftModel[]
|
||||
*/
|
||||
public function findByIds($ids, $columns = '*')
|
||||
{
|
||||
return PointGiftModel::query()
|
||||
->columns($columns)
|
||||
->inWhere('id', $ids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
104
app/Repos/PointHistory.php
Normal file
104
app/Repos/PointHistory.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
|
||||
use App\Models\PointHistory as PointHistoryModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class PointHistory extends Repository
|
||||
{
|
||||
|
||||
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
|
||||
{
|
||||
$builder = $this->modelsManager->createBuilder();
|
||||
|
||||
$builder->from(PointHistoryModel::class);
|
||||
|
||||
$builder->where('1 = 1');
|
||||
|
||||
if (!empty($where['user_id'])) {
|
||||
$builder->andWhere('user_id = :user_id:', ['user_id' => $where['user_id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['event_id'])) {
|
||||
$builder->andWhere('event_id = :event_id:', ['event_id' => $where['event_id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['event_type'])) {
|
||||
$builder->andWhere('event_type = :event_type:', ['event_type' => $where['event_type']]);
|
||||
}
|
||||
|
||||
switch ($sort) {
|
||||
default:
|
||||
$orderBy = 'id DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
$builder->orderBy($orderBy);
|
||||
|
||||
$pager = new PagerQueryBuilder([
|
||||
'builder' => $builder,
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
return $pager->paginate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $eventId
|
||||
* @param int $eventType
|
||||
* @return PointHistoryModel|Model|bool
|
||||
*/
|
||||
public function findEventHistory($eventId, $eventType)
|
||||
{
|
||||
return PointHistoryModel::findFirst([
|
||||
'conditions' => 'event_id = ?1 AND event_type = ?2',
|
||||
'bind' => [1 => $eventId, 2 => $eventType],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $eventId
|
||||
* @param int $eventType
|
||||
* @return PointHistoryModel|Model|bool
|
||||
*/
|
||||
public function findDailyEventHistory($eventId, $eventType)
|
||||
{
|
||||
$createTime = strtotime(date('Y-m-d'));
|
||||
|
||||
return PointHistoryModel::findFirst([
|
||||
'conditions' => 'event_id = ?1 AND event_type = ?2 AND create_time > ?3',
|
||||
'bind' => [1 => $eventId, 2 => $eventType, 3 => $createTime],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return PointHistoryModel|Model|bool
|
||||
*/
|
||||
public function findById($id)
|
||||
{
|
||||
return PointHistoryModel::findFirst([
|
||||
'conditions' => 'id = :id:',
|
||||
'bind' => ['id' => $id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
* @param string|array $columns
|
||||
* @return ResultsetInterface|Resultset|PointHistoryModel[]
|
||||
*/
|
||||
public function findByIds($ids, $columns = '*')
|
||||
{
|
||||
return PointHistoryModel::query()
|
||||
->columns($columns)
|
||||
->inWhere('id', $ids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
76
app/Repos/PointRedeem.php
Normal file
76
app/Repos/PointRedeem.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
|
||||
use App\Models\PointRedeem as PointRedeemModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class PointRedeem extends Repository
|
||||
{
|
||||
|
||||
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
|
||||
{
|
||||
$builder = $this->modelsManager->createBuilder();
|
||||
|
||||
$builder->from(PointRedeemModel::class);
|
||||
|
||||
$builder->where('1 = 1');
|
||||
|
||||
if (!empty($where['user_id'])) {
|
||||
$builder->andWhere('user_id = :user_id:', ['user_id' => $where['user_id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['gift_id'])) {
|
||||
$builder->andWhere('gift_id = :gift_id:', ['gift_id' => $where['gift_id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['gift_type'])) {
|
||||
$builder->andWhere('gift_type = :gift_type:', ['gift_type' => $where['gift_type']]);
|
||||
}
|
||||
|
||||
switch ($sort) {
|
||||
default:
|
||||
$orderBy = 'id DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
$builder->orderBy($orderBy);
|
||||
|
||||
$pager = new PagerQueryBuilder([
|
||||
'builder' => $builder,
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
return $pager->paginate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return PointRedeemModel|Model|bool
|
||||
*/
|
||||
public function findById($id)
|
||||
{
|
||||
return PointRedeemModel::findFirst([
|
||||
'conditions' => 'id = :id:',
|
||||
'bind' => ['id' => $id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
* @param string|array $columns
|
||||
* @return ResultsetInterface|Resultset|PointRedeemModel[]
|
||||
*/
|
||||
public function findByIds($ids, $columns = '*')
|
||||
{
|
||||
return PointRedeemModel::query()
|
||||
->columns($columns)
|
||||
->inWhere('id', $ids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,8 @@ use App\Models\CourseFavorite as CourseFavoriteModel;
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\ImUser as ImUserModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Models\UserBalance as UserBalanceModel;
|
||||
use App\Models\UserContact as UserContactModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
@ -104,6 +106,30 @@ class User extends Repository
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @return UserBalanceModel|Model
|
||||
*/
|
||||
public function findUserBalance($userId)
|
||||
{
|
||||
return UserBalanceModel::findFirst([
|
||||
'conditions' => 'user_id = :user_id:',
|
||||
'bind' => ['user_id' => $userId],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @return UserContactModel|Model
|
||||
*/
|
||||
public function findUserContact($userId)
|
||||
{
|
||||
return UserContactModel::findFirst([
|
||||
'conditions' => 'user_id = :user_id:',
|
||||
'bind' => ['user_id' => $userId],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return ImUserModel|Model|bool
|
||||
|
50
app/Services/Logic/Point/GiftInfo.php
Normal file
50
app/Services/Logic/Point/GiftInfo.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Point;
|
||||
|
||||
use App\Models\PointGift;
|
||||
use App\Services\Logic\CourseTrait;
|
||||
use App\Services\Logic\PointGiftTrait;
|
||||
use App\Services\Logic\Service;
|
||||
|
||||
class GiftInfo extends Service
|
||||
{
|
||||
|
||||
use CourseTrait;
|
||||
use PointGiftTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
$gift = $this->checkGift($id);
|
||||
|
||||
if ($gift->type == PointGift::TYPE_COURSE) {
|
||||
$gift = $this->getCourseGift($gift);
|
||||
}
|
||||
|
||||
$gift->details = kg_parse_markdown($gift->details);
|
||||
|
||||
return [
|
||||
'id' => $gift->id,
|
||||
'name' => $gift->name,
|
||||
'cover' => $gift->cover,
|
||||
'details' => $gift->details,
|
||||
'type' => $gift->type,
|
||||
'point' => $gift->point,
|
||||
'redeem_count' => $gift->redeem_count,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getCourseGift(PointGift $gift)
|
||||
{
|
||||
$courseId = $gift->attrs['id'] ?? 0;
|
||||
|
||||
$course = $this->checkCourse($courseId);
|
||||
|
||||
$gift->name = $course->title;
|
||||
$gift->cover = $course->cover;
|
||||
$gift->details = $course->details;
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
}
|
61
app/Services/Logic/Point/GiftList.php
Normal file
61
app/Services/Logic/Point/GiftList.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Point;
|
||||
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Repos\PointGift as PointGiftRepo;
|
||||
use App\Services\Logic\Service;
|
||||
|
||||
class GiftList extends Service
|
||||
{
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
|
||||
$params['published'] = 1;
|
||||
|
||||
$sort = $pagerQuery->getSort();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$giftRepo = new PointGiftRepo();
|
||||
|
||||
$pager = $giftRepo->paginate($params, $sort, $page, $limit);
|
||||
|
||||
return $this->handleGifts($pager);
|
||||
}
|
||||
|
||||
protected function handleGifts($pager)
|
||||
{
|
||||
if ($pager->total_items == 0) {
|
||||
return $pager;
|
||||
}
|
||||
|
||||
$baseUrl = kg_cos_url();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($pager->items->toArray() as $gift) {
|
||||
|
||||
$gift['cover'] = $baseUrl . $gift['cover'];
|
||||
|
||||
$items[] = [
|
||||
'id' => $gift['id'],
|
||||
'name' => $gift['name'],
|
||||
'cover' => $gift['cover'],
|
||||
'details' => $gift['details'],
|
||||
'type' => $gift['type'],
|
||||
'point' => $gift['point'],
|
||||
'redeem_count' => $gift['redeem_count'],
|
||||
];
|
||||
}
|
||||
|
||||
$pager->items = $items;
|
||||
|
||||
return $pager;
|
||||
}
|
||||
|
||||
}
|
20
app/Services/Logic/Point/HotGiftList.php
Normal file
20
app/Services/Logic/Point/HotGiftList.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Point;
|
||||
|
||||
use App\Caches\PointHotGiftList;
|
||||
use App\Services\Logic\Service;
|
||||
|
||||
class HotGiftList extends Service
|
||||
{
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$cache = new PointHotGiftList();
|
||||
|
||||
$cache->setLimit(5);
|
||||
|
||||
return $cache->get() ?: [];
|
||||
}
|
||||
|
||||
}
|
438
app/Services/Logic/Point/PointHistory.php
Normal file
438
app/Services/Logic/Point/PointHistory.php
Normal file
@ -0,0 +1,438 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Point;
|
||||
|
||||
use App\Models\ChapterUser as ChapterUserModel;
|
||||
use App\Models\Order as OrderModel;
|
||||
use App\Models\PointHistory as PointHistoryModel;
|
||||
use App\Models\PointRedeem as PointRedeemModel;
|
||||
use App\Models\Review as ReviewModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Models\UserBalance as UserBalanceModel;
|
||||
use App\Repos\Chapter as ChapterRepo;
|
||||
use App\Repos\Course as CourseRepo;
|
||||
use App\Repos\PointHistory as PointHistoryRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Logic\Service;
|
||||
|
||||
class PointHistory extends Service
|
||||
{
|
||||
|
||||
public function handleOrderConsume(OrderModel $order)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$ruleEnabled = $setting['consume_rule']['enabled'] ?? 0;
|
||||
|
||||
if ($ruleEnabled == 0) return;
|
||||
|
||||
$ruleRate = $setting['consume_rule']['rate'] ?? 0;
|
||||
|
||||
if ($ruleRate <= 0) return;
|
||||
|
||||
$eventId = $order->id;
|
||||
$eventType = PointHistoryModel::EVENT_ORDER_CONSUME;
|
||||
$eventPoint = $ruleRate * $order->amount;
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($order->owner_id);
|
||||
|
||||
$eventInfo = [
|
||||
'order' => [
|
||||
'sn' => $order->sn,
|
||||
'subject' => $order->subject,
|
||||
'amount' => $order->amount,
|
||||
]
|
||||
];
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_point = $eventPoint;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handlePointRedeem(PointRedeemModel $redeem)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$eventId = $redeem->id;
|
||||
$eventType = PointHistoryModel::EVENT_POINT_REDEEM;
|
||||
$eventPoint = 0 - $redeem->gift_point;
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($redeem->user_id);
|
||||
|
||||
$eventInfo = [
|
||||
'point_redeem' => [
|
||||
'id' => $redeem->id,
|
||||
'gift_name' => $redeem->gift_name,
|
||||
'gift_type' => $redeem->gift_type,
|
||||
'gift_point' => $redeem->gift_point,
|
||||
]
|
||||
];
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_point = $eventPoint;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handlePointRefund(PointRedeemModel $redeem)
|
||||
{
|
||||
$eventId = $redeem->id;
|
||||
$eventType = PointHistoryModel::EVENT_POINT_REFUND;
|
||||
$eventPoint = $redeem->gift_point;
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($redeem->user_id);
|
||||
|
||||
$eventInfo = [
|
||||
'point_redeem' => [
|
||||
'id' => $redeem->id,
|
||||
'gift_name' => $redeem->gift_name,
|
||||
'gift_type' => $redeem->gift_type,
|
||||
'gift_point' => $redeem->gift_point,
|
||||
]
|
||||
];
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_point = $eventPoint;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handleSiteVisit(UserModel $user)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$eventRule = json_decode($setting['event_rule'], true);
|
||||
|
||||
$eventEnabled = $eventRule['site_visit']['enabled'] ?? 0;
|
||||
|
||||
if ($eventEnabled == 0) return;
|
||||
|
||||
$eventPoint = $eventRule['site_visit']['point'] ?? 0;
|
||||
|
||||
if ($eventPoint <= 0) return;
|
||||
|
||||
$eventId = $user->id;
|
||||
$eventType = PointHistoryModel::EVENT_SITE_VISIT;
|
||||
$eventInfo = '每日登录';
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findDailyEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_point = $eventPoint;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handleAccountRegister(UserModel $user)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$eventRule = json_decode($setting['event_rule'], true);
|
||||
|
||||
$eventEnabled = $eventRule['account_register']['enabled'] ?? 0;
|
||||
|
||||
if ($eventEnabled == 0) return;
|
||||
|
||||
$eventPoint = $eventRule['account_register']['point'] ?? 0;
|
||||
|
||||
if ($eventPoint <= 0) return;
|
||||
|
||||
$eventId = $user->id;
|
||||
$eventType = PointHistoryModel::EVENT_ACCOUNT_REGISTER;
|
||||
$eventInfo = '用户注册';
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findDailyEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $user->id;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_point = $eventPoint;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handleLessonLearning(ChapterUserModel $chapterUser)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$eventRule = json_decode($setting['event_rule'], true);
|
||||
|
||||
$eventEnabled = $eventRule['chapter_learning']['enabled'] ?? 0;
|
||||
|
||||
if ($eventEnabled == 0) return;
|
||||
|
||||
$eventPoint = $eventRule['chapter_learning']['point'] ?? 0;
|
||||
|
||||
if ($eventPoint <= 0) return;
|
||||
|
||||
$eventId = $chapterUser->id;
|
||||
$eventType = PointHistoryModel::EVENT_LESSON_LEARNING;
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($chapterUser->user_id);
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$course = $courseRepo->findById($chapterUser->course_id);
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapter = $chapterRepo->findById($chapterUser->chapter_id);
|
||||
|
||||
$eventInfo = [
|
||||
'course' => [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
],
|
||||
'chapter' => [
|
||||
'id' => $chapter->id,
|
||||
'title' => $chapter->title,
|
||||
]
|
||||
];
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_info = $eventInfo;
|
||||
$history->event_point = $eventPoint;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handleCourseReview(ReviewModel $review)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$eventRule = json_decode($setting['event_rule'], true);
|
||||
|
||||
$eventEnabled = $eventRule['course_review']['enabled'] ?? 0;
|
||||
|
||||
if ($eventEnabled == 0) return;
|
||||
|
||||
$eventPoint = $eventRule['course_review']['point'] ?? 0;
|
||||
|
||||
if ($eventPoint <= 0) return;
|
||||
|
||||
$eventId = $review->id;
|
||||
$eventType = PointHistoryModel::EVENT_COURSE_REVIEW;
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($review->owner_id);
|
||||
|
||||
$courseRepo = new CourseRepo();
|
||||
|
||||
$course = $courseRepo->findById($review->course_id);
|
||||
|
||||
$eventInfo = [
|
||||
'course' => [
|
||||
'id' => $course->id,
|
||||
'title' => $course->title,
|
||||
]
|
||||
];
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_info = $eventInfo;
|
||||
$history->event_point = $eventPoint;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
public function handleGroupDiscuss(UserModel $user)
|
||||
{
|
||||
$setting = $this->getSettings('point');
|
||||
|
||||
$pointEnabled = $setting['enabled'] ?? 0;
|
||||
|
||||
if ($pointEnabled == 0) return;
|
||||
|
||||
$eventRule = json_decode($setting['event_rule'], true);
|
||||
|
||||
$eventEnabled = $eventRule['group_discuss']['enabled'] ?? 0;
|
||||
|
||||
if ($eventEnabled == 0) return;
|
||||
|
||||
$eventPoint = $eventRule['group_discuss']['point'] ?? 0;
|
||||
|
||||
if ($eventPoint <= 0) return;
|
||||
|
||||
$eventId = $user->id;
|
||||
$eventType = PointHistoryModel::EVENT_GROUP_DISCUSS;
|
||||
$eventInfo = '群组讨论';
|
||||
|
||||
$historyRepo = new PointHistoryRepo();
|
||||
|
||||
$history = $historyRepo->findEventHistory($eventId, $eventType);
|
||||
|
||||
if ($history) return;
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $eventId;
|
||||
$history->event_type = $eventType;
|
||||
$history->event_info = $eventInfo;
|
||||
$history->event_point = $eventPoint;
|
||||
|
||||
$this->handlePointHistory($history);
|
||||
}
|
||||
|
||||
protected function handlePointHistory(PointHistoryModel $history)
|
||||
{
|
||||
try {
|
||||
|
||||
$this->db->begin();
|
||||
|
||||
if ($history->create() === false) {
|
||||
throw new \RuntimeException('Create Point History Failed');
|
||||
}
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$balance = $userRepo->findUserBalance($history->user_id);
|
||||
|
||||
if ($balance) {
|
||||
$balance->user_id = $history->user_id;
|
||||
$balance->point += $history->event_point;
|
||||
$result = $balance->update();
|
||||
} else {
|
||||
$balance = new UserBalanceModel();
|
||||
$balance->user_id = $history->user_id;
|
||||
$balance->point = $history->event_point;
|
||||
$result = $balance->create();
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Save User Balance Failed');
|
||||
}
|
||||
|
||||
$this->db->commit();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->db->rollback();
|
||||
|
||||
$this->logException($e);
|
||||
|
||||
throw new \RuntimeException('sys.trans_rollback');
|
||||
}
|
||||
}
|
||||
|
||||
protected function logException(\Exception $e)
|
||||
{
|
||||
$logger = $this->getLogger('point');
|
||||
|
||||
$logger->error('Point History Exception ' . kg_json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
]));
|
||||
}
|
||||
|
||||
}
|
125
app/Services/Logic/Point/PointRedeem.php
Normal file
125
app/Services/Logic/Point/PointRedeem.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\Point;
|
||||
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use App\Models\PointHistory as PointHistoryModel;
|
||||
use App\Models\PointRedeem as PointRedeemModel;
|
||||
use App\Models\Task as TaskModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Logic\PointGiftTrait;
|
||||
use App\Services\Logic\Service;
|
||||
use App\Validators\PointRedeem as PointRedeemValidator;
|
||||
|
||||
class PointRedeem extends Service
|
||||
{
|
||||
|
||||
use PointGiftTrait;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$giftId = $this->request->getPost('gift_id', ['trim', 'int']);
|
||||
|
||||
$gift = $this->checkGift($giftId);
|
||||
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$validator = new PointRedeemValidator();
|
||||
|
||||
$validator->checkIfAllowRedeem($gift, $user);
|
||||
|
||||
$this->createPointRedeem($gift, $user);
|
||||
}
|
||||
|
||||
protected function createPointRedeem(PointGiftModel $gift, UserModel $user)
|
||||
{
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$balance = $userRepo->findUserBalance($user->id);
|
||||
|
||||
try {
|
||||
|
||||
$this->db->begin();
|
||||
|
||||
$redeem = new PointRedeemModel();
|
||||
|
||||
$redeem->gift_id = $gift->id;
|
||||
$redeem->gift_type = $gift->type;
|
||||
$redeem->gift_name = $gift->name;
|
||||
$redeem->gift_point = $gift->point;
|
||||
|
||||
$result = $redeem->create();
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Create Point Redeem Failed');
|
||||
}
|
||||
|
||||
$task = new TaskModel();
|
||||
|
||||
$itemInfo = [
|
||||
'point_redeem' => [
|
||||
'id' => $redeem->id,
|
||||
'user_id' => $redeem->user_id,
|
||||
'gift_id' => $redeem->gift_id,
|
||||
]
|
||||
];
|
||||
|
||||
$task->item_id = $redeem->id;
|
||||
$task->item_type = TaskModel::TYPE_POINT_GIFT_AWARD;
|
||||
$task->item_info = $itemInfo;
|
||||
|
||||
$result = $task->create();
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Create Async Task Failed');
|
||||
}
|
||||
|
||||
$history = new PointHistoryModel();
|
||||
|
||||
$eventInfo = [
|
||||
'gift' => [
|
||||
'id' => $gift->id,
|
||||
'name' => $gift->name,
|
||||
]
|
||||
];
|
||||
|
||||
$history->user_id = $user->id;
|
||||
$history->user_name = $user->name;
|
||||
$history->event_id = $gift->id;
|
||||
$history->event_type = PointHistoryModel::EVENT_POINT_REDEEM;
|
||||
$history->event_point = $gift->point;
|
||||
$history->event_info = $eventInfo;
|
||||
|
||||
$result = $history->create();
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Create Point History Failed');
|
||||
}
|
||||
|
||||
$balance->point -= $gift->point;
|
||||
|
||||
$result = $balance->update();
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Update User Balance Failed');
|
||||
}
|
||||
|
||||
$this->db->commit();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->db->rollback();
|
||||
|
||||
$this->logger->error('Point Redeem Exception ' . kg_json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'balance' => ['user_id' => $balance->id, 'point' => $balance->point],
|
||||
'gift' => ['id' => $gift->id, 'point' => $gift->point],
|
||||
]));
|
||||
|
||||
throw new \RuntimeException('sys.trans_rollback');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
app/Services/Logic/PointGiftTrait.php
Normal file
17
app/Services/Logic/PointGiftTrait.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic;
|
||||
|
||||
use App\Validators\PointGift as PointGiftValidator;
|
||||
|
||||
trait PointGiftTrait
|
||||
{
|
||||
|
||||
public function checkGift($id)
|
||||
{
|
||||
$validator = new PointGiftValidator();
|
||||
|
||||
return $validator->checkGift($id);
|
||||
}
|
||||
|
||||
}
|
45
app/Services/Logic/User/Console/ContactInfo.php
Normal file
45
app/Services/Logic/User/Console/ContactInfo.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\User\Console;
|
||||
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Logic\Service;
|
||||
|
||||
class ContactInfo extends Service
|
||||
{
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$contact = $userRepo->findUserContact($user->id);
|
||||
|
||||
if (!$contact) {
|
||||
return $this->defaultContactInfo();
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $contact->name,
|
||||
'phone' => $contact->phone,
|
||||
'add_province' => $contact->add_province,
|
||||
'add_city' => $contact->add_city,
|
||||
'add_county' => $contact->add_county,
|
||||
'add_other' => $contact->add_other,
|
||||
];
|
||||
}
|
||||
|
||||
protected function defaultContactInfo()
|
||||
{
|
||||
return [
|
||||
'name' => '',
|
||||
'phone' => '',
|
||||
'add_province' => '',
|
||||
'add_city' => '',
|
||||
'add_county' => '',
|
||||
'add_other' => '',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
35
app/Services/Logic/User/Console/ContactUpdate.php
Normal file
35
app/Services/Logic/User/Console/ContactUpdate.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\User\Console;
|
||||
|
||||
use App\Models\UserContact as UserContactModel;
|
||||
use App\Services\Logic\Service;
|
||||
use App\Validators\UserContact as UserContactValidator;
|
||||
|
||||
class ContactUpdate extends Service
|
||||
{
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$validator = new UserContactValidator();
|
||||
|
||||
$contact = new UserContactModel();
|
||||
|
||||
$contact->name = $validator->checkName($post['name']);
|
||||
$contact->phone = $validator->checkPhone($post['phone']);
|
||||
$contact->add_province = $validator->checkAddProvince($post['address']['province']);
|
||||
$contact->add_city = $validator->checkAddCity($post['address']['city']);
|
||||
$contact->add_county = $validator->checkAddCounty($post['address']['county']);
|
||||
$contact->add_other = $validator->checkAddOther($post['address']['other']);
|
||||
$contact->user_id = $user->id;
|
||||
|
||||
$contact->save();
|
||||
|
||||
return $contact;
|
||||
}
|
||||
|
||||
}
|
68
app/Services/Logic/User/Console/PointRedeemList.php
Normal file
68
app/Services/Logic/User/Console/PointRedeemList.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\User\Console;
|
||||
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Repos\Order as OrderRepo;
|
||||
use App\Services\Logic\Service;
|
||||
use App\Services\Logic\UserTrait;
|
||||
|
||||
class PointRedeemList extends Service
|
||||
{
|
||||
|
||||
use UserTrait;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
|
||||
$params['user_id'] = $user->id;
|
||||
$params['deleted'] = 0;
|
||||
|
||||
$sort = $pagerQuery->getSort();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$orderRepo = new OrderRepo();
|
||||
|
||||
$pager = $orderRepo->paginate($params, $sort, $page, $limit);
|
||||
|
||||
return $this->handleOrders($pager);
|
||||
}
|
||||
|
||||
public function handleOrders($pager)
|
||||
{
|
||||
if ($pager->total_items == 0) {
|
||||
return $pager;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($pager->items as $item) {
|
||||
$items[] = [
|
||||
'id' => $item->id,
|
||||
'status' => $item->status,
|
||||
'create_time' => $item->create_time,
|
||||
'user' => [
|
||||
'id' => $item->user_id,
|
||||
'name' => $item->user_name,
|
||||
],
|
||||
'gift' => [
|
||||
'id' => $item->gift_id,
|
||||
'type' => $item->gift_type,
|
||||
'name' => $item->gift_name,
|
||||
'point' => $item->gift_point,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$pager->items = $items;
|
||||
|
||||
return $pager;
|
||||
}
|
||||
|
||||
}
|
@ -2,12 +2,11 @@
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use App\Caches\User as UserCache;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Auth as AuthService;
|
||||
use App\Validators\Validator as AppValidator;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Events\Manager as EventsManager;
|
||||
|
||||
trait Auth
|
||||
{
|
||||
@ -23,18 +22,9 @@ trait Auth
|
||||
return $this->getGuestUser();
|
||||
}
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
$userCache = new UserCache();
|
||||
|
||||
$user = $userRepo->findById($authUser['id']);
|
||||
|
||||
/**
|
||||
* @var EventsManager $eventsManager
|
||||
*/
|
||||
$eventsManager = Di::getDefault()->getShared('eventsManager');
|
||||
|
||||
$eventsManager->fire('user:online', $this, $user);
|
||||
|
||||
return $user;
|
||||
return $userCache->get($authUser['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,9 +38,9 @@ trait Auth
|
||||
|
||||
$validator->checkAuthUser($authUser['id']);
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
$userCache = new UserCache();
|
||||
|
||||
return $userRepo->findById($authUser['id']);
|
||||
return $userCache->get($authUser['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,13 +30,6 @@ trait Security
|
||||
$validator->checkRateLimit();
|
||||
}
|
||||
|
||||
public function checkApiSignature()
|
||||
{
|
||||
$validator = new SecurityValidator();
|
||||
|
||||
$validator->checkApiSignature();
|
||||
}
|
||||
|
||||
public function isNotSafeRequest()
|
||||
{
|
||||
/**
|
||||
|
@ -91,7 +91,7 @@ class Help extends Validator
|
||||
throw new BadRequestException('help.content_too_short');
|
||||
}
|
||||
|
||||
if ($length > 3000) {
|
||||
if ($length > 30000) {
|
||||
throw new BadRequestException('help.content_too_long');
|
||||
}
|
||||
|
||||
|
@ -77,9 +77,9 @@ class ImGroup extends Validator
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkAbout($name)
|
||||
public function checkAbout($about)
|
||||
{
|
||||
$value = $this->filter->sanitize($name, ['trim', 'string']);
|
||||
$value = $this->filter->sanitize($about, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
|
@ -86,7 +86,7 @@ class Page extends Validator
|
||||
throw new BadRequestException('page.content_too_short');
|
||||
}
|
||||
|
||||
if ($length > 3000) {
|
||||
if ($length > 30000) {
|
||||
throw new BadRequestException('page.content_too_long');
|
||||
}
|
||||
|
||||
|
153
app/Validators/PointGift.php
Normal file
153
app/Validators/PointGift.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace App\Validators;
|
||||
|
||||
use App\Caches\MaxPointGiftId as MaxPointGiftIdCache;
|
||||
use App\Caches\PointGift as PointGiftCache;
|
||||
use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Library\Validators\Common as CommonValidator;
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use App\Repos\PointGift as PointGiftRepo;
|
||||
|
||||
class PointGift extends Validator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return PointGiftModel
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function checkGiftCache($id)
|
||||
{
|
||||
$this->checkId($id);
|
||||
|
||||
$giftCache = new PointGiftCache();
|
||||
|
||||
$gift = $giftCache->get($id);
|
||||
|
||||
if (!$gift) {
|
||||
throw new BadRequestException('point_gift.not_found');
|
||||
}
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
public function checkGift($id)
|
||||
{
|
||||
$this->checkId($id);
|
||||
|
||||
$giftRepo = new PointGiftRepo();
|
||||
|
||||
$gift = $giftRepo->findById($id);
|
||||
|
||||
if (!$gift) {
|
||||
throw new BadRequestException('point_gift.not_found');
|
||||
}
|
||||
|
||||
return $gift;
|
||||
}
|
||||
|
||||
public function checkId($id)
|
||||
{
|
||||
$id = intval($id);
|
||||
|
||||
$maxGiftIdCache = new MaxPointGiftIdCache();
|
||||
|
||||
$maxId = $maxGiftIdCache->get();
|
||||
|
||||
if ($id < 1 || $id > $maxId) {
|
||||
throw new BadRequestException('point_gift.not_found');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkName($name)
|
||||
{
|
||||
$value = $this->filter->sanitize($name, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 2) {
|
||||
throw new BadRequestException('point_gift.name_too_short');
|
||||
}
|
||||
|
||||
if ($length > 30) {
|
||||
throw new BadRequestException('point_gift.name_too_long');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkDetails($details)
|
||||
{
|
||||
$value = $this->filter->sanitize($details, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length > 30000) {
|
||||
throw new BadRequestException('point_gift.details_too_long');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkCover($cover)
|
||||
{
|
||||
$value = $this->filter->sanitize($cover, ['trim', 'string']);
|
||||
|
||||
if (!CommonValidator::url($value)) {
|
||||
throw new BadRequestException('point_gift.invalid_cover');
|
||||
}
|
||||
|
||||
return kg_cos_img_style_trim($value);
|
||||
}
|
||||
|
||||
public function checkType($type)
|
||||
{
|
||||
$list = PointGiftModel::types();
|
||||
|
||||
if (!isset($list[$type])) {
|
||||
throw new BadRequestException('point_gift.invalid_type');
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
public function checkPoint($point)
|
||||
{
|
||||
$value = $this->filter->sanitize($point, ['trim', 'int']);
|
||||
|
||||
if ($value < 1 || $value > 999999) {
|
||||
throw new BadRequestException('point_gift.invalid_point');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkStock($stock)
|
||||
{
|
||||
$value = $this->filter->sanitize($stock, ['trim', 'int']);
|
||||
|
||||
if ($value < 1 || $value > 999999) {
|
||||
throw new BadRequestException('point_gift.invalid_stock');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkPublishStatus($status)
|
||||
{
|
||||
if (!in_array($status, [0, 1])) {
|
||||
throw new BadRequestException('point_gift.invalid_publish_status');
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function checkCourse($id)
|
||||
{
|
||||
$validator = new Course();
|
||||
|
||||
return $validator->checkCourse($id);
|
||||
}
|
||||
|
||||
}
|
82
app/Validators/PointRedeem.php
Normal file
82
app/Validators/PointRedeem.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Validators;
|
||||
|
||||
use App\Exceptions\BadRequest;
|
||||
use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\PointGift as PointGiftModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\CourseUser as CourseUserRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class PointRedeem extends Validator
|
||||
{
|
||||
|
||||
public function checkGift($giftId)
|
||||
{
|
||||
$validator = new PointGift();
|
||||
|
||||
return $validator->checkGift($giftId);
|
||||
}
|
||||
|
||||
public function checkIfAllowRedeem(PointGiftModel $gift, UserModel $user)
|
||||
{
|
||||
$this->checkPointBalance($gift, $user);
|
||||
|
||||
if ($gift->type == PointGiftModel::TYPE_COURSE) {
|
||||
|
||||
$validator = new Course();
|
||||
|
||||
$course = $validator->checkCourse($gift->attrs['id']);
|
||||
|
||||
$this->checkIfAllowRedeemCourse($course, $user);
|
||||
|
||||
} elseif ($gift->type == PointGiftModel::TYPE_GOODS) {
|
||||
|
||||
$this->checkIfAllowRedeemCommodity($user);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkIfAllowRedeemCourse(CourseModel $course, UserModel $user)
|
||||
{
|
||||
if ($course->published == 0) {
|
||||
throw new BadRequestException('point_redeem.course_not_published');
|
||||
}
|
||||
|
||||
if ($course->market_price == 0) {
|
||||
throw new BadRequestException('point_redeem.course_free');
|
||||
}
|
||||
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseUser($course->id, $user->id);
|
||||
|
||||
if ($courseUser->expiry_time > time()) {
|
||||
throw new BadRequestException('point_redeem.course_owned');
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkIfAllowRedeemCommodity(UserModel $user)
|
||||
{
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$contact = $userRepo->findUserContact($user->id);
|
||||
|
||||
if (!$contact) {
|
||||
throw new BadRequestException('point_redeem.no_user_contact');
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkPointBalance(PointGiftModel $gift, UserModel $user)
|
||||
{
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$balance = $userRepo->findUserBalance($user->id);
|
||||
|
||||
if (!$balance || $balance->point < $gift->point) {
|
||||
throw new BadRequestException('point_redeem.no_enough_point');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
101
app/Validators/UserContact.php
Normal file
101
app/Validators/UserContact.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Validators;
|
||||
|
||||
use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Library\Validators\Common as CommonValidator;
|
||||
use App\Repos\User as UserRepo;
|
||||
|
||||
class UserContact extends Validator
|
||||
{
|
||||
|
||||
public function checkContact($id)
|
||||
{
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($id);
|
||||
|
||||
if (!$user) {
|
||||
throw new BadRequestException('user_contact.not_found');
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function checkName($name)
|
||||
{
|
||||
$value = $this->filter->sanitize($name, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 2 || $length > 15) {
|
||||
throw new BadRequestException('user_contact.invalid_name');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkPhone($phone)
|
||||
{
|
||||
$value = $this->filter->sanitize($phone, ['trim', 'string']);
|
||||
|
||||
if (!CommonValidator::phone($value)) {
|
||||
throw new BadRequestException('user_contact.invalid_phone');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkAddProvince($province)
|
||||
{
|
||||
$value = $this->filter->sanitize($province, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 2 || $length > 15) {
|
||||
throw new BadRequestException('user_contact.invalid_add_province');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkAddCity($city)
|
||||
{
|
||||
$value = $this->filter->sanitize($city, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 2 || $length > 15) {
|
||||
throw new BadRequestException('user_contact.invalid_add_city');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkAddCounty($county)
|
||||
{
|
||||
$value = $this->filter->sanitize($county, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 2 || $length > 15) {
|
||||
throw new BadRequestException('user_contact.invalid_add_county');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkAddOther($other)
|
||||
{
|
||||
$value = $this->filter->sanitize($other, ['trim', 'string']);
|
||||
|
||||
$length = kg_strlen($value);
|
||||
|
||||
if ($length < 5 || $length > 50) {
|
||||
throw new BadRequestException('user_contact.invalid_add_other');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
@ -222,7 +222,7 @@ $error['page.not_found'] = '单页不存在';
|
||||
$error['page.title_too_short'] = '标题太短(少于2个字符)';
|
||||
$error['page.title_too_long'] = '标题太长(多于50个字符)';
|
||||
$error['page.content_too_short'] = '内容太短(少于10个字符)';
|
||||
$error['page.content_too_long'] = '内容太长(多于3000个字符)';
|
||||
$error['page.content_too_long'] = '内容太长(多于30000个字符)';
|
||||
$error['page.invalid_publish_status'] = '无效的发布状态';
|
||||
|
||||
/**
|
||||
@ -232,7 +232,7 @@ $error['help.not_found'] = '帮助不存在';
|
||||
$error['help.title_too_short'] = '标题太短(少于2个字符)';
|
||||
$error['help.title_too_long'] = '标题太长(多于50个字符)';
|
||||
$error['help.content_too_short'] = '内容太短(少于10个字符)';
|
||||
$error['help.content_too_long'] = '内容太长(多于60000个字符)';
|
||||
$error['help.content_too_long'] = '内容太长(多于30000个字符)';
|
||||
$error['help.invalid_priority'] = '无效的排序数值(范围:1-255)';
|
||||
$error['help.invalid_publish_status'] = '无效的发布状态';
|
||||
|
||||
@ -244,7 +244,7 @@ $error['slide.invalid_platform'] = '无效的平台类型';
|
||||
$error['slide.invalid_target'] = '无效的目标类型';
|
||||
$error['slide.invalid_link'] = '无效的链接地址';
|
||||
$error['slide.invalid_priority'] = '无效的排序数值(范围:1-255)';
|
||||
$error['slide.invalid_cover'] = '无效的封面图片';
|
||||
$error['slide.invalid_cover'] = '无效的封面';
|
||||
$error['slide.title_too_short'] = '标题太短(少于2个字符)';
|
||||
$error['slide.title_too_long'] = '标题太长(多于50个字符)';
|
||||
$error['slide.summary_too_long'] = '简介太长(多于255个字符)';
|
||||
@ -356,4 +356,34 @@ $error['im_message.content_too_short'] = '消息内容太短(少于1字符)'
|
||||
$error['im_message.content_too_long'] = '消息内容太长(超过1000字符)';
|
||||
$error['im_message.self_chat'] = '不能给自己发送消息';
|
||||
|
||||
/**
|
||||
* 联系信息相关
|
||||
*/
|
||||
$error['user_contact.invalid_name'] = '无效的用户姓名';
|
||||
$error['user_contact.invalid_phone'] = '无效的手机号码';
|
||||
$error['user_contact.invalid_add_province'] = '无效的地址(省)';
|
||||
$error['user_contact.invalid_add_city'] = '无效的地址(市)';
|
||||
$error['user_contact.invalid_add_county'] = '无效的地址(区)';
|
||||
$error['user_contact.invalid_add_other'] = '无效的地址(详)';
|
||||
|
||||
/**
|
||||
* 积分兑换相关
|
||||
*/
|
||||
$error['point_gift.not_found'] = '礼品不存在';
|
||||
$error['point_gift.name_too_short'] = '礼品名称太短(少于2字符)';
|
||||
$error['point_gift.name_too_long'] = '礼品名称太长(超过30字符)';
|
||||
$error['point_gift.details_too_long'] = '礼品详情太长(多于30000个字符)';
|
||||
$error['point_gift.invalid_cover'] = '无效的封面';
|
||||
$error['point_gift.invalid_type'] = '无效的类型';
|
||||
$error['point_gift.invalid_point'] = '无效的积分值(范围1-999999)';
|
||||
$error['point_gift.invalid_stock'] = '无效的库存值(范围1-999999)';
|
||||
$error['point_gift.invalid_publish_status'] = '无效的发布状态';
|
||||
|
||||
$error['point_redeem.course_not_published'] = '课程尚未发布';
|
||||
$error['point_redeem.course_free'] = '课程当前免费,无需积分兑换';
|
||||
$error['point_redeem.course_owned'] = '您已经拥有课程,无需积分兑换';
|
||||
$error['point_redeem.no_user_contact'] = '您尚未设置收货地址,请前往用户中心设置';
|
||||
$error['point_redeem.no_enough_point'] = '您的积分余额不足以抵扣此次兑换';
|
||||
|
||||
|
||||
return $error;
|
||||
|
@ -1,11 +1,15 @@
|
||||
<?php
|
||||
|
||||
use App\Listeners\Account;
|
||||
use App\Listeners\Pay;
|
||||
use App\Listeners\Site;
|
||||
use App\Listeners\User;
|
||||
use App\Listeners\UserDailyCounter;
|
||||
|
||||
return [
|
||||
'pay' => Pay::class,
|
||||
'user' => User::class,
|
||||
'site' => Site::class,
|
||||
'account' => Account::class,
|
||||
'userDailyCounter' => UserDailyCounter::class,
|
||||
];
|
58
db/migrations/20210126024511_data_202101261130.php
Normal file
58
db/migrations/20210126024511_data_202101261130.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
class Data202101261130 extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
$consumeRule = ['enabled' => 1, 'rate' => 5];
|
||||
|
||||
$eventRule = [
|
||||
'account_register' => ['enabled' => 1, 'point' => 100],
|
||||
'site_visit' => ['enabled' => 1, 'point' => 10],
|
||||
'course_review' => ['enabled' => 1, 'point' => 50],
|
||||
'group_discuss' => ['enabled' => 1, 'point' => 10],
|
||||
'lesson_learning' => ['enabled' => 1, 'point' => 10],
|
||||
];
|
||||
|
||||
$rows = [
|
||||
[
|
||||
'section' => 'point',
|
||||
'item_key' => 'enabled',
|
||||
'item_value' => 1,
|
||||
],
|
||||
[
|
||||
'section' => 'point',
|
||||
'item_key' => 'consume_rule',
|
||||
'item_value' => json_encode($consumeRule),
|
||||
],
|
||||
[
|
||||
'section' => 'point',
|
||||
'item_key' => 'event_rule',
|
||||
'item_value' => json_encode($eventRule),
|
||||
],
|
||||
];
|
||||
|
||||
$this->table('kg_setting')->insert($rows)->save();
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->getQueryBuilder()
|
||||
->delete('kg_setting')
|
||||
->where(['section' => 'point'])
|
||||
->execute();
|
||||
}
|
||||
|
||||
protected function initUserBalanceData()
|
||||
{
|
||||
$dataQuery = $this->getQueryBuilder()->select(['id'])->from('kg_user');
|
||||
|
||||
$this->getQueryBuilder()
|
||||
->insert(['user_id'])
|
||||
->into('kg_user_balance')
|
||||
->values($dataQuery)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -42,13 +42,6 @@ layui.use(['jquery'], function () {
|
||||
value: $textarea.val()
|
||||
});
|
||||
|
||||
/**
|
||||
* 取消提交表单行为
|
||||
*/
|
||||
$('body').on('click', '.vditor-preview__action > button', function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* 同步编辑器内容到表单
|
||||
*/
|
||||
|
@ -1816,4 +1816,45 @@
|
||||
|
||||
.layim-chat-status .offline {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.gift-meta .cover {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.gift-meta .cover img {
|
||||
width: 210px;
|
||||
height: 118px;
|
||||
}
|
||||
|
||||
.gift-meta .info {
|
||||
float: left;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.gift-meta .info p {
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.gift-meta .info .stats {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.gift-meta .info span {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.gift-meta .info .value {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.gift-meta .info .price {
|
||||
font-size: 16px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.gift-details {
|
||||
min-height: 450px;
|
||||
}
|
9
public/static/home/js/point.gift.list.js
Normal file
9
public/static/home/js/point.gift.list.js
Normal file
@ -0,0 +1,9 @@
|
||||
layui.use(['jquery', 'helper'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var helper = layui.helper;
|
||||
var $giftList = $('#gift-list');
|
||||
|
||||
helper.ajaxLoadHtml($giftList.data('url'), $giftList.attr('id'));
|
||||
|
||||
});
|
24
public/static/home/js/point.gift.show.js
Normal file
24
public/static/home/js/point.gift.show.js
Normal file
@ -0,0 +1,24 @@
|
||||
layui.use(['jquery', 'layer'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
|
||||
$('.btn-redeem').on('click', function () {
|
||||
var url = $(this).data('url');
|
||||
var data = {gift_id: $(this).data('id')};
|
||||
layer.confirm('兑换不支持退换,确定要兑换该物品吗?', function () {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: url,
|
||||
data: data,
|
||||
success: function (res) {
|
||||
layer.msg(res.msg, {icon: 1});
|
||||
setTimeout(function () {
|
||||
window.location.href = '/uc/redeems';
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
12
public/static/home/js/user.console.contact.js
Normal file
12
public/static/home/js/user.console.contact.js
Normal file
@ -0,0 +1,12 @@
|
||||
layui.use(['layarea'], function () {
|
||||
|
||||
var layarea = layui.layarea;
|
||||
|
||||
layarea.render({
|
||||
elem: '#area-picker',
|
||||
change: function (res) {
|
||||
console.log(res);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user