mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-26 20:52:44 +08:00
增加面授模型,重构群组成员管理
This commit is contained in:
parent
a95aa655cd
commit
6c86f914cc
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,3 +1,13 @@
|
|||||||
|
### [v1.3.0](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.0)(2021-03-26)
|
||||||
|
|
||||||
|
### 更新
|
||||||
|
|
||||||
|
- 课程增加面授模型
|
||||||
|
- 重构前台群组成员管理
|
||||||
|
- 后台增加群组成员管理
|
||||||
|
- 重构订单存储商品详情数据结构
|
||||||
|
- 调整用户和群组列表等UI
|
||||||
|
|
||||||
### [v1.2.9](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.9)(2021-03-22)
|
### [v1.2.9](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.9)(2021-03-22)
|
||||||
|
|
||||||
### 更新
|
### 更新
|
||||||
|
14
README.md
14
README.md
@ -14,12 +14,12 @@
|
|||||||
|
|
||||||
### 系统功能
|
### 系统功能
|
||||||
|
|
||||||
实现了点播、直播、专栏、会员、微聊等,是一个完整的产品,具体功能我也不想写一大堆,自己体验吧!
|
实现了点播、直播、专栏、面授、会员、群组、积分商城、秒杀等,全功能无阉割,100%真开源在线教育解决方案。具体功能我也不想写一大堆,自己体验吧!
|
||||||
|
|
||||||
友情提示:
|
友情提示:
|
||||||
|
|
||||||
- 系统配置低(1核 1G 1M 跑多个容器),切莫压测
|
- 演示系统配置低(1Core,1G,1M 跑多个容器)切莫压测
|
||||||
- 课程数据来源于网络(无实质内容),切莫购买
|
- 课程数据来源于网络(无实质内容)切莫购买
|
||||||
- 管理后台已禁止数据提交,私密配置已过滤
|
- 管理后台已禁止数据提交,私密配置已过滤
|
||||||
|
|
||||||
桌面端演示:
|
桌面端演示:
|
||||||
@ -27,13 +27,13 @@
|
|||||||
- [前台演示](https://ctc.koogua.com)
|
- [前台演示](https://ctc.koogua.com)
|
||||||
- [后台演示](https://ctc.koogua.com/admin)
|
- [后台演示](https://ctc.koogua.com/admin)
|
||||||
|
|
||||||
演示帐号:100015@163.com / 123456 (前后台通用)
|
演示账号:100015@163.com / 123456 (前后台通用)
|
||||||
|
|
||||||
移动端演示:
|
移动端演示:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
演示帐号:13507083515 / 123456
|
演示账号:13507083515 / 123456
|
||||||
|
|
||||||
支付流程演示:
|
支付流程演示:
|
||||||
|
|
||||||
@ -42,10 +42,10 @@
|
|||||||
- [数据库与中间件的基础必修课(0.02元)](https://ctc.koogua.com/order/confirm?item_id=80&item_type=2)
|
- [数据库与中间件的基础必修课(0.02元)](https://ctc.koogua.com/order/confirm?item_id=80&item_type=2)
|
||||||
|
|
||||||
Tips: 测试支付请用手机号注册一个新账户,以便接收订单通知,以及避免课程无法购买
|
Tips: 测试支付请用手机号注册一个新账户,以便接收订单通知,以及避免课程无法购买
|
||||||
|
|
||||||
即时通讯演示:
|
即时通讯演示:
|
||||||
|
|
||||||
请使用以下两个帐号在不同终端或者浏览器登录,打开微聊界面
|
请使用以下两个账号在不同终端或者浏览器登录,打开微聊界面
|
||||||
|
|
||||||
- 帐号A:100015@163.com / 123456
|
- 帐号A:100015@163.com / 123456
|
||||||
- 帐号B:100065@163.com / 123456
|
- 帐号B:100065@163.com / 123456
|
||||||
|
@ -8,6 +8,17 @@ use App\Repos\User as UserRepo;
|
|||||||
class ImGroupList extends Builder
|
class ImGroupList extends Builder
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function handleGroups(array $groups)
|
||||||
|
{
|
||||||
|
$baseUrl = kg_cos_url();
|
||||||
|
|
||||||
|
foreach ($groups as $key => $group) {
|
||||||
|
$groups[$key]['avatar'] = $baseUrl . $group['avatar'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $groups;
|
||||||
|
}
|
||||||
|
|
||||||
public function handleCourses(array $groups)
|
public function handleCourses(array $groups)
|
||||||
{
|
{
|
||||||
$courses = $this->getCourses($groups);
|
$courses = $this->getCourses($groups);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Tasks;
|
namespace App\Console\Tasks;
|
||||||
|
|
||||||
|
use App\Models\Course as CourseModel;
|
||||||
use App\Models\CourseUser as CourseUserModel;
|
use App\Models\CourseUser as CourseUserModel;
|
||||||
use App\Models\ImGroupUser as ImGroupUserModel;
|
use App\Models\ImGroupUser as ImGroupUserModel;
|
||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
@ -105,13 +106,19 @@ class DeliverTask extends Task
|
|||||||
|
|
||||||
protected function handleCourseOrder(OrderModel $order)
|
protected function handleCourseOrder(OrderModel $order)
|
||||||
{
|
{
|
||||||
$itemInfo = $order->item_info;
|
$course = $order->item_info['course'];
|
||||||
|
|
||||||
|
if ($course['model'] == CourseModel::MODEL_OFFLINE) {
|
||||||
|
$expiryTime = strtotime($course['attrs']['end_date']);
|
||||||
|
} else {
|
||||||
|
$expiryTime = $course['study_expiry_time'];
|
||||||
|
}
|
||||||
|
|
||||||
$courseUser = new CourseUserModel();
|
$courseUser = new CourseUserModel();
|
||||||
|
|
||||||
$courseUser->user_id = $order->owner_id;
|
$courseUser->user_id = $order->owner_id;
|
||||||
$courseUser->course_id = $order->item_id;
|
$courseUser->course_id = $order->item_id;
|
||||||
$courseUser->expiry_time = $itemInfo['course']['study_expiry_time'];
|
$courseUser->expiry_time = $expiryTime;
|
||||||
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
||||||
$courseUser->source_type = CourseUserModel::SOURCE_CHARGE;
|
$courseUser->source_type = CourseUserModel::SOURCE_CHARGE;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class UpgradeTask extends Task
|
|||||||
$redis->del($statsKey);
|
$redis->del($statsKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "end reset metadata..." . PHP_EOL;
|
echo "------ end reset metadata ------" . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,10 +79,17 @@ class ChapterController extends Controller
|
|||||||
|
|
||||||
$chapter = $chapterService->createChapter();
|
$chapter = $chapterService->createChapter();
|
||||||
|
|
||||||
$location = $this->url->get([
|
if ($chapter->parent_id > 0) {
|
||||||
'for' => 'admin.course.chapters',
|
$location = $this->url->get([
|
||||||
'id' => $chapter->course_id,
|
'for' => 'admin.chapter.lessons',
|
||||||
]);
|
'id' => $chapter->parent_id,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$location = $this->url->get([
|
||||||
|
'for' => 'admin.course.chapters',
|
||||||
|
'id' => $chapter->course_id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'location' => $location,
|
||||||
@ -131,6 +138,10 @@ class ChapterController extends Controller
|
|||||||
$read = $contentService->getChapterRead($chapter->id);
|
$read = $contentService->getChapterRead($chapter->id);
|
||||||
$this->view->setVar('read', $read);
|
$this->view->setVar('read', $read);
|
||||||
break;
|
break;
|
||||||
|
case CourseModel::MODEL_OFFLINE:
|
||||||
|
$offline = $contentService->getChapterOffline($chapter->id);
|
||||||
|
$this->view->setVar('offline', $offline);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,22 @@ use App\Http\Admin\Services\ImGroup as ImGroupService;
|
|||||||
class ImGroupController extends Controller
|
class ImGroupController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/users", name="admin.im_group.users")
|
||||||
|
*/
|
||||||
|
public function usersAction($id)
|
||||||
|
{
|
||||||
|
$service = new ImGroupService();
|
||||||
|
|
||||||
|
$group = $service->getGroup($id);
|
||||||
|
$pager = $service->getGroupUsers($id);
|
||||||
|
|
||||||
|
$this->view->pick('im/group/users');
|
||||||
|
|
||||||
|
$this->view->setVar('group', $group);
|
||||||
|
$this->view->setVar('pager', $pager);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Get("/list", name="admin.im_group.list")
|
* @Get("/list", name="admin.im_group.list")
|
||||||
*/
|
*/
|
||||||
|
32
app/Http/Admin/Controllers/ImGroupUserController.php
Normal file
32
app/Http/Admin/Controllers/ImGroupUserController.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Admin\Services\ImGroupUser as ImGroupUserService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RoutePrefix("/admin/im/group/user")
|
||||||
|
*/
|
||||||
|
class ImGroupUserController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete", name="admin.im_group_user.delete")
|
||||||
|
*/
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
$groupService = new ImGroupUserService();
|
||||||
|
|
||||||
|
$groupService->deleteGroupUser();
|
||||||
|
|
||||||
|
$location = $this->request->getHTTPReferer();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '删除成员成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -381,6 +381,18 @@ class AuthNode extends Service
|
|||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.im_group.delete',
|
'route' => 'admin.im_group.delete',
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'id' => '2-4-6',
|
||||||
|
'title' => '群员列表',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.im_group.users',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '2-4-7',
|
||||||
|
'title' => '删除群员',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.im_group_user.delete',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -7,6 +7,7 @@ use App\Caches\Chapter as ChapterCache;
|
|||||||
use App\Caches\CourseChapterList as CatalogCache;
|
use App\Caches\CourseChapterList as CatalogCache;
|
||||||
use App\Models\Chapter as ChapterModel;
|
use App\Models\Chapter as ChapterModel;
|
||||||
use App\Models\ChapterLive as ChapterLiveModel;
|
use App\Models\ChapterLive as ChapterLiveModel;
|
||||||
|
use App\Models\ChapterOffline as ChapterOfflineModel;
|
||||||
use App\Models\ChapterRead as ChapterReadModel;
|
use App\Models\ChapterRead as ChapterReadModel;
|
||||||
use App\Models\ChapterVod as ChapterVodModel;
|
use App\Models\ChapterVod as ChapterVodModel;
|
||||||
use App\Models\Course as CourseModel;
|
use App\Models\Course as CourseModel;
|
||||||
@ -25,9 +26,7 @@ class Chapter extends Service
|
|||||||
|
|
||||||
$resources = $resourceRepo->findByChapterId($id);
|
$resources = $resourceRepo->findByChapterId($id);
|
||||||
|
|
||||||
if ($resources->count() == 0) {
|
if ($resources->count() == 0) return [];
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$builder = new ResourceListBuilder();
|
$builder = new ResourceListBuilder();
|
||||||
|
|
||||||
@ -118,6 +117,10 @@ class Chapter extends Service
|
|||||||
$chapterRead = new ChapterReadModel();
|
$chapterRead = new ChapterReadModel();
|
||||||
$attrs = $chapterRead->create($data);
|
$attrs = $chapterRead->create($data);
|
||||||
break;
|
break;
|
||||||
|
case CourseModel::MODEL_OFFLINE:
|
||||||
|
$chapterOffline = new ChapterOfflineModel();
|
||||||
|
$attrs = $chapterOffline->create($data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($attrs === false) {
|
if ($attrs === false) {
|
||||||
@ -137,10 +140,11 @@ class Chapter extends Service
|
|||||||
|
|
||||||
$this->db->rollback();
|
$this->db->rollback();
|
||||||
|
|
||||||
$logger = $this->getLogger();
|
$logger = $this->getLogger('http');
|
||||||
|
|
||||||
$logger->error('Create Chapter Error ' . kg_json_encode([
|
$logger->error('Create Chapter Error ' . kg_json_encode([
|
||||||
'code' => $e->getCode(),
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -176,7 +180,7 @@ class Chapter extends Service
|
|||||||
|
|
||||||
if (isset($post['published'])) {
|
if (isset($post['published'])) {
|
||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
if ($chapter->published == 0 && $post['published'] == 1) {
|
if ($post['published'] == 1) {
|
||||||
$validator->checkPublishAbility($chapter);
|
$validator->checkPublishAbility($chapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,6 +263,8 @@ class Chapter extends Service
|
|||||||
$courseStats->updateLiveAttrs($course->id);
|
$courseStats->updateLiveAttrs($course->id);
|
||||||
} elseif ($course->model == CourseModel::MODEL_READ) {
|
} elseif ($course->model == CourseModel::MODEL_READ) {
|
||||||
$courseStats->updateReadAttrs($course->id);
|
$courseStats->updateReadAttrs($course->id);
|
||||||
|
} elseif ($course->model == CourseModel::MODEL_OFFLINE) {
|
||||||
|
$courseStats->updateOfflineAttrs($course->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ use App\Services\ChapterVod as ChapterVodService;
|
|||||||
use App\Services\CourseStat as CourseStatService;
|
use App\Services\CourseStat as CourseStatService;
|
||||||
use App\Services\Vod as VodService;
|
use App\Services\Vod as VodService;
|
||||||
use App\Validators\ChapterLive as ChapterLiveValidator;
|
use App\Validators\ChapterLive as ChapterLiveValidator;
|
||||||
|
use App\Validators\ChapterOffline as ChapterOfflineValidator;
|
||||||
use App\Validators\ChapterRead as ChapterReadValidator;
|
use App\Validators\ChapterRead as ChapterReadValidator;
|
||||||
use App\Validators\ChapterVod as ChapterVodValidator;
|
use App\Validators\ChapterVod as ChapterVodValidator;
|
||||||
|
|
||||||
@ -39,6 +40,13 @@ class ChapterContent extends Service
|
|||||||
return $chapterRepo->findChapterRead($chapterId);
|
return $chapterRepo->findChapterRead($chapterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getChapterOffline($chapterId)
|
||||||
|
{
|
||||||
|
$chapterRepo = new ChapterRepo();
|
||||||
|
|
||||||
|
return $chapterRepo->findChapterOffline($chapterId);
|
||||||
|
}
|
||||||
|
|
||||||
public function getPlayUrls($chapterId)
|
public function getPlayUrls($chapterId)
|
||||||
{
|
{
|
||||||
$service = new ChapterVodService();
|
$service = new ChapterVodService();
|
||||||
@ -64,6 +72,9 @@ class ChapterContent extends Service
|
|||||||
case CourseModel::MODEL_READ:
|
case CourseModel::MODEL_READ:
|
||||||
$this->updateChapterRead($chapter);
|
$this->updateChapterRead($chapter);
|
||||||
break;
|
break;
|
||||||
|
case CourseModel::MODEL_OFFLINE:
|
||||||
|
$this->updateChapterOffline($chapter);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rebuildCatalogCache($chapter);
|
$this->rebuildCatalogCache($chapter);
|
||||||
@ -84,9 +95,7 @@ class ChapterContent extends Service
|
|||||||
/**
|
/**
|
||||||
* 无新文件上传
|
* 无新文件上传
|
||||||
*/
|
*/
|
||||||
if ($fileId == $vod->file_id) {
|
if ($fileId == $vod->file_id) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除旧文件
|
* 删除旧文件
|
||||||
@ -95,21 +104,17 @@ class ChapterContent extends Service
|
|||||||
$this->deleteVodFile($vod->file_id);
|
$this->deleteVodFile($vod->file_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$vod->update([
|
$vod->file_id = $fileId;
|
||||||
'file_id' => $fileId,
|
$vod->file_transcode = [];
|
||||||
'file_transcode' => '',
|
|
||||||
]);
|
$vod->update();
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $chapter->attrs;
|
$attrs = $chapter->attrs;
|
||||||
|
|
||||||
$attrs['duration'] = 0;
|
$attrs['duration'] = 0;
|
||||||
|
|
||||||
$attrs['file']['status'] = ChapterModel::FS_UPLOADED;
|
$attrs['file']['status'] = ChapterModel::FS_UPLOADED;
|
||||||
|
$chapter->attrs = $attrs;
|
||||||
|
|
||||||
$chapter->update(['attrs' => $attrs]);
|
$chapter->update();
|
||||||
|
|
||||||
$this->updateCourseVodAttrs($vod->course_id);
|
$this->updateCourseVodAttrs($vod->course_id);
|
||||||
}
|
}
|
||||||
@ -129,20 +134,17 @@ class ChapterContent extends Service
|
|||||||
|
|
||||||
$validator->checkTimeRange($startTime, $endTime);
|
$validator->checkTimeRange($startTime, $endTime);
|
||||||
|
|
||||||
$live->update([
|
$live->start_time = $startTime;
|
||||||
'start_time' => $startTime,
|
$live->end_time = $endTime;
|
||||||
'end_time' => $endTime,
|
|
||||||
]);
|
$live->update();
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $chapter->attrs;
|
$attrs = $chapter->attrs;
|
||||||
|
|
||||||
$attrs['start_time'] = $startTime;
|
$attrs['start_time'] = $startTime;
|
||||||
$attrs['end_time'] = $endTime;
|
$attrs['end_time'] = $endTime;
|
||||||
|
$chapter->attrs = $attrs;
|
||||||
|
|
||||||
$chapter->update(['attrs' => $attrs]);
|
$chapter->update();
|
||||||
|
|
||||||
$this->updateCourseLiveAttrs($live->course_id);
|
$this->updateCourseLiveAttrs($live->course_id);
|
||||||
}
|
}
|
||||||
@ -161,9 +163,6 @@ class ChapterContent extends Service
|
|||||||
|
|
||||||
$read->update(['content' => $content]);
|
$read->update(['content' => $content]);
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $chapter->attrs;
|
$attrs = $chapter->attrs;
|
||||||
|
|
||||||
$attrs['word_count'] = WordUtil::getWordCount($content);
|
$attrs['word_count'] = WordUtil::getWordCount($content);
|
||||||
@ -174,6 +173,36 @@ class ChapterContent extends Service
|
|||||||
$this->updateCourseReadAttrs($read->course_id);
|
$this->updateCourseReadAttrs($read->course_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function updateChapterOffline(ChapterModel $chapter)
|
||||||
|
{
|
||||||
|
$post = $this->request->getPost();
|
||||||
|
|
||||||
|
$chapterRepo = new ChapterRepo();
|
||||||
|
|
||||||
|
$offline = $chapterRepo->findChapterOffline($chapter->id);
|
||||||
|
|
||||||
|
$validator = new ChapterOfflineValidator();
|
||||||
|
|
||||||
|
$startTime = $validator->checkStartTime($post['start_time']);
|
||||||
|
$endTime = $validator->checkEndTime($post['end_time']);
|
||||||
|
|
||||||
|
$validator->checkTimeRange($startTime, $endTime);
|
||||||
|
|
||||||
|
$offline->start_time = $startTime;
|
||||||
|
$offline->end_time = $endTime;
|
||||||
|
|
||||||
|
$offline->update();
|
||||||
|
|
||||||
|
$attrs = $chapter->attrs;
|
||||||
|
$attrs['start_time'] = $startTime;
|
||||||
|
$attrs['end_time'] = $endTime;
|
||||||
|
$chapter->attrs = $attrs;
|
||||||
|
|
||||||
|
$chapter->update();
|
||||||
|
|
||||||
|
$this->updateCourseOfflineAttrs($offline->course_id);
|
||||||
|
}
|
||||||
|
|
||||||
protected function updateCourseVodAttrs($courseId)
|
protected function updateCourseVodAttrs($courseId)
|
||||||
{
|
{
|
||||||
$statService = new CourseStatService();
|
$statService = new CourseStatService();
|
||||||
@ -195,6 +224,13 @@ class ChapterContent extends Service
|
|||||||
$statService->updateReadAttrs($courseId);
|
$statService->updateReadAttrs($courseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function updateCourseOfflineAttrs($courseId)
|
||||||
|
{
|
||||||
|
$statService = new CourseStatService();
|
||||||
|
|
||||||
|
$statService->updateOfflineAttrs($courseId);
|
||||||
|
}
|
||||||
|
|
||||||
protected function deleteVodFile($fileId)
|
protected function deleteVodFile($fileId)
|
||||||
{
|
{
|
||||||
$vodService = new VodService();
|
$vodService = new VodService();
|
||||||
|
@ -26,6 +26,7 @@ use App\Repos\ImGroup as ImGroupRepo;
|
|||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
use App\Services\Sync\CourseIndex as CourseIndexSync;
|
use App\Services\Sync\CourseIndex as CourseIndexSync;
|
||||||
use App\Validators\Course as CourseValidator;
|
use App\Validators\Course as CourseValidator;
|
||||||
|
use App\Validators\CourseOffline as CourseOfflineValidator;
|
||||||
|
|
||||||
class Course extends Service
|
class Course extends Service
|
||||||
{
|
{
|
||||||
@ -114,7 +115,7 @@ class Course extends Service
|
|||||||
|
|
||||||
$this->db->rollback();
|
$this->db->rollback();
|
||||||
|
|
||||||
$logger = $this->getLogger();
|
$logger = $this->getLogger('http');
|
||||||
|
|
||||||
$logger->error('Create Course Error ' . kg_json_encode([
|
$logger->error('Create Course Error ' . kg_json_encode([
|
||||||
'code' => $e->getCode(),
|
'code' => $e->getCode(),
|
||||||
@ -159,17 +160,24 @@ class Course extends Service
|
|||||||
$data['level'] = $validator->checkLevel($post['level']);
|
$data['level'] = $validator->checkLevel($post['level']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['price_mode'])) {
|
if (isset($post['study_expiry'])) {
|
||||||
if ($post['price_mode'] == 'free') {
|
$data['study_expiry'] = $validator->checkStudyExpiry($post['study_expiry']);
|
||||||
$data['market_price'] = 0;
|
}
|
||||||
$data['vip_price'] = 0;
|
|
||||||
} else {
|
if (isset($post['refund_expiry'])) {
|
||||||
$data['origin_price'] = $validator->checkOriginPrice($post['origin_price']);
|
$data['refund_expiry'] = $validator->checkRefundExpiry($post['refund_expiry']);
|
||||||
$data['market_price'] = $validator->checkMarketPrice($post['market_price']);
|
}
|
||||||
$data['vip_price'] = $validator->checkVipPrice($post['vip_price']);
|
|
||||||
$data['study_expiry'] = $validator->checkStudyExpiry($post['study_expiry']);
|
if (isset($post['origin_price'])) {
|
||||||
$data['refund_expiry'] = $validator->checkRefundExpiry($post['refund_expiry']);
|
$data['origin_price'] = $validator->checkOriginPrice($post['origin_price']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['market_price'])) {
|
||||||
|
$data['market_price'] = $validator->checkMarketPrice($post['market_price']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['vip_price'])) {
|
||||||
|
$data['vip_price'] = $validator->checkVipPrice($post['vip_price']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['featured'])) {
|
if (isset($post['featured'])) {
|
||||||
@ -195,6 +203,28 @@ class Course extends Service
|
|||||||
$this->saveRelatedCourses($course, $post['xm_course_ids']);
|
$this->saveRelatedCourses($course, $post['xm_course_ids']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($course->model == CourseModel::MODEL_OFFLINE) {
|
||||||
|
|
||||||
|
$validator = new CourseOfflineValidator();
|
||||||
|
|
||||||
|
$data['study_expiry'] = 0;
|
||||||
|
$data['refund_expiry'] = 0;
|
||||||
|
|
||||||
|
if (isset($post['attrs']['start_date']) && isset($post['attrs']['end_date'])) {
|
||||||
|
$data['attrs']['start_date'] = $validator->checkStartDate($post['attrs']['start_date']);
|
||||||
|
$data['attrs']['end_date'] = $validator->checkEndDate($post['attrs']['end_date']);
|
||||||
|
$validator->checkDateRange($data['attrs']['start_date'], $data['attrs']['end_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['attrs']['user_limit'])) {
|
||||||
|
$data['attrs']['user_limit'] = $validator->checkUserLimit($post['attrs']['user_limit']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['attrs']['location'])) {
|
||||||
|
$data['attrs']['location'] = $validator->checkLocation($post['attrs']['location']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$course->update($data);
|
$course->update($data);
|
||||||
|
|
||||||
$this->updateImGroup($course);
|
$this->updateImGroup($course);
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
namespace App\Http\Admin\Services;
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
use App\Builders\ImGroupList as ImGroupListBuilder;
|
use App\Builders\ImGroupList as ImGroupListBuilder;
|
||||||
|
use App\Builders\ImGroupUserList as ImGroupUserListBuilder;
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
use App\Models\ImGroup as ImGroupModel;
|
use App\Models\ImGroup as ImGroupModel;
|
||||||
use App\Models\ImGroupUser as ImGroupUserModel;
|
use App\Models\ImGroupUser as ImGroupUserModel;
|
||||||
use App\Models\User as UserModel;
|
use App\Models\ImUser as ImUserModel;
|
||||||
use App\Repos\ImGroup as ImGroupRepo;
|
use App\Repos\ImGroup as ImGroupRepo;
|
||||||
use App\Repos\ImGroupUser as ImGroupUserRepo;
|
use App\Repos\ImGroupUser as ImGroupUserRepo;
|
||||||
use App\Validators\ImGroup as ImGroupValidator;
|
use App\Validators\ImGroup as ImGroupValidator;
|
||||||
|
use App\Validators\ImGroupUser as ImGroupUserValidator;
|
||||||
|
|
||||||
class ImGroup extends Service
|
class ImGroup extends Service
|
||||||
{
|
{
|
||||||
@ -89,9 +91,10 @@ class ImGroup extends Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['owner_id'])) {
|
if (isset($post['owner_id'])) {
|
||||||
$owner = $validator->checkGroupOwner($post['owner_id']);
|
$validator = new ImGroupUserValidator();
|
||||||
$data['owner_id'] = $owner->id;
|
$user = $validator->checkUser($post['owner_id']);
|
||||||
$this->handleGroupOwner($group, $owner);
|
$data['owner_id'] = $user->id;
|
||||||
|
$this->handleGroupOwner($group, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
$group->update($data);
|
$group->update($data);
|
||||||
@ -121,7 +124,42 @@ class ImGroup extends Service
|
|||||||
return $group;
|
return $group;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleGroupOwner(ImGroupModel $group, UserModel $user)
|
public function getGroupUsers($id)
|
||||||
|
{
|
||||||
|
$pagerQuery = new PagerQuery();
|
||||||
|
|
||||||
|
$params = $pagerQuery->getParams();
|
||||||
|
|
||||||
|
$params['group_id'] = $id;
|
||||||
|
|
||||||
|
$sort = $pagerQuery->getSort();
|
||||||
|
$page = $pagerQuery->getPage();
|
||||||
|
$limit = $pagerQuery->getLimit();
|
||||||
|
|
||||||
|
$groupUserRepo = new ImGroupUserRepo();
|
||||||
|
|
||||||
|
$pager = $groupUserRepo->paginate($params, $sort, $page, $limit);
|
||||||
|
|
||||||
|
return $this->handleGroupUsers($pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleGroupUsers($pager)
|
||||||
|
{
|
||||||
|
if ($pager->total_items == 0) {
|
||||||
|
return $pager;
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder = new ImGroupUserListBuilder();
|
||||||
|
|
||||||
|
$stepA = $pager->items->toArray();
|
||||||
|
$stepB = $builder->handleUsers($stepA);
|
||||||
|
|
||||||
|
$pager->items = $stepB;
|
||||||
|
|
||||||
|
return $pager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleGroupOwner(ImGroupModel $group, ImUserModel $user)
|
||||||
{
|
{
|
||||||
$repo = new ImGroupUserRepo();
|
$repo = new ImGroupUserRepo();
|
||||||
|
|
||||||
@ -130,21 +168,40 @@ class ImGroup extends Service
|
|||||||
if ($groupUser) return;
|
if ($groupUser) return;
|
||||||
|
|
||||||
$groupUser = new ImGroupUserModel();
|
$groupUser = new ImGroupUserModel();
|
||||||
|
|
||||||
$groupUser->group_id = $group->id;
|
$groupUser->group_id = $group->id;
|
||||||
$groupUser->user_id = $user->id;
|
$groupUser->user_id = $user->id;
|
||||||
|
|
||||||
$groupUser->create();
|
$groupUser->create();
|
||||||
|
|
||||||
|
$this->incrGroupUserCount($group);
|
||||||
|
|
||||||
|
$this->incrUserGroupCount($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function incrGroupUserCount(ImGroupModel $group)
|
||||||
|
{
|
||||||
$group->user_count += 1;
|
$group->user_count += 1;
|
||||||
|
|
||||||
$group->update();
|
$group->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function incrUserGroupCount(ImUserModel $user)
|
||||||
|
{
|
||||||
|
$user->group_count += 1;
|
||||||
|
|
||||||
|
$user->update();
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleGroups($pager)
|
protected function handleGroups($pager)
|
||||||
{
|
{
|
||||||
if ($pager->total_items > 0) {
|
if ($pager->total_items > 0) {
|
||||||
|
|
||||||
$builder = new ImGroupListBuilder();
|
$builder = new ImGroupListBuilder();
|
||||||
|
|
||||||
$pipeA = $pager->items->toArray();
|
$items = $pager->items->toArray();
|
||||||
|
|
||||||
|
$pipeA = $builder->handleGroups($items);
|
||||||
$pipeB = $builder->handleUsers($pipeA);
|
$pipeB = $builder->handleUsers($pipeA);
|
||||||
$pipeC = $builder->objects($pipeB);
|
$pipeC = $builder->objects($pipeB);
|
||||||
|
|
||||||
|
55
app/Http/Admin/Services/ImGroupUser.php
Normal file
55
app/Http/Admin/Services/ImGroupUser.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
|
use App\Models\ImGroup as ImGroupModel;
|
||||||
|
use App\Models\ImUser as ImUserModel;
|
||||||
|
use App\Validators\ImGroupUser as ImGroupUserValidator;
|
||||||
|
|
||||||
|
class ImGroupUser extends Service
|
||||||
|
{
|
||||||
|
|
||||||
|
public function deleteGroupUser()
|
||||||
|
{
|
||||||
|
$groupId = $this->request->getQuery('group_id', 'int', 0);
|
||||||
|
$userId = $this->request->getQuery('user_id', 'int', 0);
|
||||||
|
|
||||||
|
$validator = new ImGroupUserValidator();
|
||||||
|
|
||||||
|
$group = $validator->checkGroup($groupId);
|
||||||
|
$user = $validator->checkUser($userId);
|
||||||
|
|
||||||
|
$validator->checkIfAllowDelete($groupId, $userId);
|
||||||
|
|
||||||
|
$groupUser = $this->findOrFail($groupId, $userId);
|
||||||
|
|
||||||
|
$groupUser->delete();
|
||||||
|
|
||||||
|
$this->decrGroupUserCount($group);
|
||||||
|
$this->decrUserGroupCount($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decrGroupUserCount(ImGroupModel $group)
|
||||||
|
{
|
||||||
|
if ($group->user_count > 0) {
|
||||||
|
$group->user_count -= 1;
|
||||||
|
$group->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decrUserGroupCount(ImUserModel $user)
|
||||||
|
{
|
||||||
|
if ($user->group_count > 0) {
|
||||||
|
$user->group_count -= 1;
|
||||||
|
$user->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findOrFail($groupId, $userId)
|
||||||
|
{
|
||||||
|
$validator = new ImGroupUserValidator();
|
||||||
|
|
||||||
|
return $validator->checkGroupUser($groupId, $userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,6 +6,7 @@ use App\Caches\CoursePackageList as CoursePackageListCache;
|
|||||||
use App\Caches\Package as PackageCache;
|
use App\Caches\Package as PackageCache;
|
||||||
use App\Caches\PackageCourseList as PackageCourseListCache;
|
use App\Caches\PackageCourseList as PackageCourseListCache;
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
|
use App\Models\Course as CourseModel;
|
||||||
use App\Models\CoursePackage as CoursePackageModel;
|
use App\Models\CoursePackage as CoursePackageModel;
|
||||||
use App\Models\Package as PackageModel;
|
use App\Models\Package as PackageModel;
|
||||||
use App\Repos\Course as CourseRepo;
|
use App\Repos\Course as CourseRepo;
|
||||||
@ -32,7 +33,20 @@ class Package extends Service
|
|||||||
|
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
$items = $courseRepo->findAll(['free' => 0, 'published' => 1]);
|
/**
|
||||||
|
* 面授课程不参与套餐计划,因为无法进行退款计算
|
||||||
|
*/
|
||||||
|
$model = [
|
||||||
|
CourseModel::MODEL_VOD,
|
||||||
|
CourseModel::MODEL_LIVE,
|
||||||
|
CourseModel::MODEL_READ,
|
||||||
|
];
|
||||||
|
|
||||||
|
$items = $courseRepo->findAll([
|
||||||
|
'model' => $model,
|
||||||
|
'free' => 0,
|
||||||
|
'published' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
if ($items->count() == 0) return [];
|
if ($items->count() == 0) return [];
|
||||||
|
|
||||||
|
@ -267,7 +267,9 @@ class User extends Service
|
|||||||
|
|
||||||
$builder = new UserListBuilder();
|
$builder = new UserListBuilder();
|
||||||
|
|
||||||
$pipeA = $pager->items->toArray();
|
$items = $pager->items->toArray();
|
||||||
|
|
||||||
|
$pipeA = $builder->handleUsers($items);
|
||||||
$pipeB = $builder->handleAdminRoles($pipeA);
|
$pipeB = $builder->handleAdminRoles($pipeA);
|
||||||
$pipeC = $builder->handleEduRoles($pipeB);
|
$pipeC = $builder->handleEduRoles($pipeB);
|
||||||
$pipeD = $builder->objects($pipeC);
|
$pipeD = $builder->objects($pipeC);
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
直播信息
|
直播信息
|
||||||
{% elseif model == '3' %}
|
{% elseif model == '3' %}
|
||||||
图文信息
|
图文信息
|
||||||
|
{% elseif model == '4' %}
|
||||||
|
面授信息
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
@ -33,6 +35,8 @@
|
|||||||
{{ partial('chapter/edit_lesson_live') }}
|
{{ partial('chapter/edit_lesson_live') }}
|
||||||
{% elseif course.model == 3 %}
|
{% elseif course.model == 3 %}
|
||||||
{{ partial('chapter/edit_lesson_read') }}
|
{{ partial('chapter/edit_lesson_read') }}
|
||||||
|
{% elseif course.model == 4 %}
|
||||||
|
{{ partial('chapter/edit_lesson_offline') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-tab-item">
|
<div class="layui-tab-item">
|
||||||
|
24
app/Http/Admin/Views/chapter/edit_lesson_offline.volt
Normal file
24
app/Http/Admin/Views/chapter/edit_lesson_offline.volt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{% set offline.start_time = offline.start_time > 0 ? date('Y-m-d H:i:s',offline.start_time) : '' %}
|
||||||
|
{% set offline.end_time = offline.end_time > 0 ? date('Y-m-d H:i:s',offline.end_time) : '' %}
|
||||||
|
|
||||||
|
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.chapter.content','id':chapter.id}) }}">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">开始时间</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input class="layui-input" type="text" name="start_time" autocomplete="off" value="{{ offline.start_time }}" 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="end_time" autocomplete="off" value="{{ offline.end_time }}" lay-verify="required">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label"></label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -27,6 +27,8 @@
|
|||||||
{{ partial('chapter/lessons_live') }}
|
{{ partial('chapter/lessons_live') }}
|
||||||
{% elseif course.model == 3 %}
|
{% elseif course.model == 3 %}
|
||||||
{{ partial('chapter/lessons_read') }}
|
{{ partial('chapter/lessons_read') }}
|
||||||
|
{% elseif course.model == 4 %}
|
||||||
|
{{ partial('chapter/lessons_offline') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
64
app/Http/Admin/Views/chapter/lessons_offline.volt
Normal file
64
app/Http/Admin/Views/chapter/lessons_offline.volt
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
{%- macro offline_time_info(attrs) %}
|
||||||
|
{% if attrs['start_time'] > 0 %}
|
||||||
|
<p>开始:{{ date('Y-m-d H:i',attrs['start_time']) }}</p>
|
||||||
|
<p>结束:{{ date('Y-m-d H:i',attrs['end_time']) }}</p>
|
||||||
|
{% else %}
|
||||||
|
N/A
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
<table class="layui-table kg-table layui-form">
|
||||||
|
<colgroup>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col width="12%">
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>编号</th>
|
||||||
|
<th>名称</th>
|
||||||
|
<th>时间</th>
|
||||||
|
<th>排序</th>
|
||||||
|
<th>免费</th>
|
||||||
|
<th>发布</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in lessons %}
|
||||||
|
{% set edit_url = url({'for':'admin.chapter.edit','id':item.id}) %}
|
||||||
|
{% set update_url = url({'for':'admin.chapter.update','id':item.id}) %}
|
||||||
|
{% set delete_url = url({'for':'admin.chapter.delete','id':item.id}) %}
|
||||||
|
{% set restore_url = url({'for':'admin.chapter.restore','id':item.id}) %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.id }}</td>
|
||||||
|
<td>
|
||||||
|
<span><a href="{{ edit_url }}">{{ item.title }}</a></span>
|
||||||
|
<span class="layui-badge layui-bg-green">课</span>
|
||||||
|
</td>
|
||||||
|
<td>{{ offline_time_info(item.attrs) }}</td>
|
||||||
|
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||||
|
<td><input type="checkbox" name="free" value="1" lay-skin="switch" lay-text="是|否" lay-filter="free" data-url="{{ update_url }}" {% if item.free == 1 %}checked="checked"{% endif %}></td>
|
||||||
|
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" 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="{{ 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="{{ delete_url }}">还原</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
@ -50,7 +50,8 @@
|
|||||||
var modelTips = {
|
var modelTips = {
|
||||||
'1': '通过音视频呈现课程内容,内容可视化,有图像有声音,适合大部分场景',
|
'1': '通过音视频呈现课程内容,内容可视化,有图像有声音,适合大部分场景',
|
||||||
'2': '通过直播呈现课程内容,交互性强,适合需要交互反馈、情绪表达的场景',
|
'2': '通过直播呈现课程内容,交互性强,适合需要交互反馈、情绪表达的场景',
|
||||||
'3': '通过图文呈现课程内容,简单直接,适合撰写文档、书籍、教程的场景'
|
'3': '通过图文呈现课程内容,简单直接,适合撰写文档、书籍、教程的场景',
|
||||||
|
'4': '面对面讲授课程内容,传统教学,适合有条件开展线下教学的场景',
|
||||||
};
|
};
|
||||||
|
|
||||||
var modelTipsBlock = $('#model-tips');
|
var modelTipsBlock = $('#model-tips');
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
<div class="layui-tab layui-tab-brief">
|
<div class="layui-tab layui-tab-brief">
|
||||||
<ul class="layui-tab-title kg-tab-title">
|
<ul class="layui-tab-title kg-tab-title">
|
||||||
<li class="layui-this">基本信息</li>
|
<li class="layui-this">基本信息</li>
|
||||||
|
{% if course.model == 4 %}
|
||||||
|
<li>面授信息</li>
|
||||||
|
{% endif %}
|
||||||
<li>课程介绍</li>
|
<li>课程介绍</li>
|
||||||
<li>营销设置</li>
|
<li>营销设置</li>
|
||||||
<li>相关课程</li>
|
<li>相关课程</li>
|
||||||
@ -17,6 +20,11 @@
|
|||||||
<div class="layui-tab-item layui-show">
|
<div class="layui-tab-item layui-show">
|
||||||
{{ partial('course/edit_basic') }}
|
{{ partial('course/edit_basic') }}
|
||||||
</div>
|
</div>
|
||||||
|
{% if course.model == 4 %}
|
||||||
|
<div class="layui-tab-item">
|
||||||
|
{{ partial('course/edit_offline') }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="layui-tab-item">
|
<div class="layui-tab-item">
|
||||||
{{ partial('course/edit_desc') }}
|
{{ partial('course/edit_desc') }}
|
||||||
</div>
|
</div>
|
||||||
@ -53,23 +61,16 @@
|
|||||||
xmSelect.render({
|
xmSelect.render({
|
||||||
el: '#xm-category-ids',
|
el: '#xm-category-ids',
|
||||||
name: 'xm_category_ids',
|
name: 'xm_category_ids',
|
||||||
|
filterable: true,
|
||||||
max: 5,
|
max: 5,
|
||||||
prop: {
|
|
||||||
name: 'name',
|
|
||||||
value: 'id'
|
|
||||||
},
|
|
||||||
data: {{ xm_categories|json_encode }}
|
data: {{ xm_categories|json_encode }}
|
||||||
});
|
});
|
||||||
|
|
||||||
xmSelect.render({
|
xmSelect.render({
|
||||||
el: '#xm-teacher-ids',
|
el: '#xm-teacher-ids',
|
||||||
name: 'xm_teacher_ids',
|
name: 'xm_teacher_ids',
|
||||||
paging: true,
|
filterable: true,
|
||||||
max: 5,
|
max: 5,
|
||||||
prop: {
|
|
||||||
name: 'name',
|
|
||||||
value: 'id'
|
|
||||||
},
|
|
||||||
data: {{ xm_teachers|json_encode }}
|
data: {{ xm_teachers|json_encode }}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -86,19 +87,20 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
layui.use(['jquery', 'form', 'layer'], function () {
|
layui.use(['jquery', 'form', 'layer', 'laydate'], function () {
|
||||||
|
|
||||||
var $ = layui.jquery;
|
var $ = layui.jquery;
|
||||||
var form = layui.form;
|
|
||||||
var layer = layui.layer;
|
var layer = layui.layer;
|
||||||
|
var laydate = layui.laydate;
|
||||||
|
|
||||||
form.on('radio(price_mode)', function (data) {
|
laydate.render({
|
||||||
var priceBlock = $('#price-block');
|
elem: 'input[name="attrs[start_date]"]',
|
||||||
if (data.value === 'free') {
|
type: 'date'
|
||||||
priceBlock.hide();
|
});
|
||||||
} else {
|
|
||||||
priceBlock.show();
|
laydate.render({
|
||||||
}
|
elem: 'input[name="attrs[end_date]"]',
|
||||||
|
type: 'date'
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.kg-submit').on('click', function () {
|
$('.kg-submit').on('click', function () {
|
||||||
|
33
app/Http/Admin/Views/course/edit_offline.volt
Normal file
33
app/Http/Admin/Views/course/edit_offline.volt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.course.update','id':course.id}) }}">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">开始日期</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input class="layui-input" type="text" name="attrs[start_date]" autocomplete="off" value="{{ course.attrs['start_date'] }}" 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="attrs[end_date]" autocomplete="off" value="{{ course.attrs['end_date'] }}" 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="attrs[location]" value="{{ course.attrs['location'] }}" placeholder="可以用于导航的地理位置" 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="attrs[user_limit]" value="{{ course.attrs['user_limit'] }}" lay-verify="required">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label"></label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<button id="sale-submit" 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>
|
@ -1,42 +1,32 @@
|
|||||||
{% set free = course.market_price == 0 %}
|
|
||||||
{% set price_display = course.market_price > 0 ? 'display:block' : 'display:none' %}
|
|
||||||
|
|
||||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.course.update','id':course.id}) }}">
|
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.course.update','id':course.id}) }}">
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">模式</label>
|
<div class="layui-inline">
|
||||||
<div class="layui-input-block">
|
<label class="layui-form-label">原始价格</label>
|
||||||
<input type="radio" name="price_mode" value="free" title="免费" lay-filter="price_mode" {% if free %}checked="checked"{% endif %}>
|
<div class="layui-input-inline">
|
||||||
<input type="radio" name="price_mode" value="charge" title="收费" lay-filter="price_mode" {% if not free %}checked="checked"{% endif %}>
|
<input class="layui-input" type="text" name="origin_price" value="{{ course.origin_price }}" lay-verify="number">
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-mid layui-word-aux">元</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="price-block" style="{{ price_display }}">
|
<div class="layui-form-item">
|
||||||
<div class="layui-form-item">
|
<div class="layui-inline">
|
||||||
<div class="layui-inline">
|
<label class="layui-form-label">市场价格</label>
|
||||||
<label class="layui-form-label">原始价格</label>
|
<div class="layui-input-inline">
|
||||||
<div class="layui-input-inline">
|
<input class="layui-input" type="text" name="market_price" value="{{ course.market_price }}" lay-verify="number">
|
||||||
<input class="layui-input" type="text" name="origin_price" value="{{ course.origin_price }}" lay-verify="number">
|
|
||||||
</div>
|
|
||||||
<div class="layui-form-mid layui-word-aux">元</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-form-mid layui-word-aux">元</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
</div>
|
||||||
<div class="layui-inline">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">市场价格</label>
|
<div class="layui-inline">
|
||||||
<div class="layui-input-inline">
|
<label class="layui-form-label">会员价格</label>
|
||||||
<input class="layui-input" type="text" name="market_price" value="{{ course.market_price }}" lay-verify="number">
|
<div class="layui-input-inline">
|
||||||
</div>
|
<input class="layui-input" type="text" name="vip_price" value="{{ course.vip_price }}" lay-verify="number">
|
||||||
<div class="layui-form-mid layui-word-aux">元</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="layui-form-item">
|
|
||||||
<div class="layui-inline">
|
|
||||||
<label class="layui-form-label">会员价格</label>
|
|
||||||
<div class="layui-input-inline">
|
|
||||||
<input class="layui-input" type="text" name="vip_price" value="{{ course.vip_price }}" lay-verify="number">
|
|
||||||
</div>
|
|
||||||
<div class="layui-form-mid layui-word-aux">元</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-form-mid layui-word-aux">元</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if course.model in [1,2,3] %}
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">学习期限</label>
|
<label class="layui-form-label">学习期限</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
@ -53,7 +43,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label"></label>
|
<label class="layui-form-label"></label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
{%- macro study_expiry_info(value) %}
|
|
||||||
{% if value == 1 %}
|
|
||||||
1个月
|
|
||||||
{% elseif value == 3 %}
|
|
||||||
3个月
|
|
||||||
{% elseif value == 6 %}
|
|
||||||
6个月
|
|
||||||
{% elseif value == 12 %}
|
|
||||||
12个月
|
|
||||||
{% elseif value == 36 %}
|
|
||||||
36个月
|
|
||||||
{% else %}
|
|
||||||
N/A
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro refund_expiry_info(value) %}
|
|
||||||
{% if value == 7 %}
|
|
||||||
7天
|
|
||||||
{% elseif value == 14 %}
|
|
||||||
14天
|
|
||||||
{% elseif value == 30 %}
|
|
||||||
30天
|
|
||||||
{% elseif value == 90 %}
|
|
||||||
90天
|
|
||||||
{% elseif value == 180 %}
|
|
||||||
180天
|
|
||||||
{% else %}
|
|
||||||
N/A
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
@ -2,32 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{%- macro model_info(value) %}
|
{{ partial('macros/course') }}
|
||||||
{% if value == 1 %}
|
|
||||||
点播
|
|
||||||
{% elseif value == 2 %}
|
|
||||||
直播
|
|
||||||
{% elseif value == 3 %}
|
|
||||||
专栏
|
|
||||||
{% else %}
|
|
||||||
未知
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro level_info(value) %}
|
|
||||||
{% if value == 1 %}
|
|
||||||
入门
|
|
||||||
{% elseif value == 2 %}
|
|
||||||
初级
|
|
||||||
{% elseif value == 3 %}
|
|
||||||
中级
|
|
||||||
{% elseif value == 4 %}
|
|
||||||
高级
|
|
||||||
{% else %}
|
|
||||||
未知
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{% set add_url = url({'for':'admin.course.add'}) %}
|
{% set add_url = url({'for':'admin.course.add'}) %}
|
||||||
{% set search_url = url({'for':'admin.course.search'}) %}
|
{% set search_url = url({'for':'admin.course.search'}) %}
|
||||||
|
@ -2,26 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{%- macro type_info(value) %}
|
{{ partial('macros/group') }}
|
||||||
{% if value == 1 %}
|
|
||||||
课程
|
|
||||||
{% elseif value == 2 %}
|
|
||||||
水吧
|
|
||||||
{% elseif value == 3 %}
|
|
||||||
职工
|
|
||||||
{% else %}
|
|
||||||
未知
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro owner_info(owner) %}
|
|
||||||
{% if owner.id is defined %}
|
|
||||||
{% set filter_url = url({'for':'admin.im_group.list'},{'owner_id':owner.id}) %}
|
|
||||||
<a href="{{ filter_url }}">{{ owner.name }}</a>({{ owner.id }})
|
|
||||||
{% else %}
|
|
||||||
未设置
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{% set add_url = url({'for':'admin.im_group.add'}) %}
|
{% set add_url = url({'for':'admin.im_group.add'}) %}
|
||||||
{% set search_url = url({'for':'admin.im_group.search'}) %}
|
{% set search_url = url({'for':'admin.im_group.search'}) %}
|
||||||
@ -44,7 +25,7 @@
|
|||||||
|
|
||||||
<table class="kg-table layui-table layui-form">
|
<table class="kg-table layui-table layui-form">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col width="10%">
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -54,10 +35,10 @@
|
|||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>编号</th>
|
<th>头像</th>
|
||||||
<th>名称</th>
|
<th>名称</th>
|
||||||
<th>类型</th>
|
|
||||||
<th>群主</th>
|
<th>群主</th>
|
||||||
|
<th>类型</th>
|
||||||
<th>成员</th>
|
<th>成员</th>
|
||||||
<th>发布</th>
|
<th>发布</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
@ -70,18 +51,28 @@
|
|||||||
{% set update_url = url({'for':'admin.im_group.update','id':item.id}) %}
|
{% set update_url = url({'for':'admin.im_group.update','id':item.id}) %}
|
||||||
{% set delete_url = url({'for':'admin.im_group.delete','id':item.id}) %}
|
{% set delete_url = url({'for':'admin.im_group.delete','id':item.id}) %}
|
||||||
{% set restore_url = url({'for':'admin.im_group.restore','id':item.id}) %}
|
{% set restore_url = url({'for':'admin.im_group.restore','id':item.id}) %}
|
||||||
|
{% set users_url = url({'for':'admin.im_group.users','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.id }}</td>
|
<td class="center">
|
||||||
<td><a href="{{ edit_url }}">{{ item.name }}</a></td>
|
<img class="avatar-sm" src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
|
||||||
|
</td>
|
||||||
|
<td><a href="{{ preview_url }}" title="{{ item.about }}" target="_blank">{{ item.name }}</a>({{ item.id }})</td>
|
||||||
|
<td>
|
||||||
|
{% if item.owner.id is defined %}
|
||||||
|
<a href="{{ url({'for':'home.user.show','id':item.owner.id}) }}" target="_blank">{{ item.owner.name }}</a>({{ item.owner.id }})
|
||||||
|
{% else %}
|
||||||
|
N/A
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td> {{ type_info(item.type) }}</td>
|
<td> {{ type_info(item.type) }}</td>
|
||||||
<td>{{ owner_info(item.owner) }}</td>
|
<td><a href="{{ users_url }}" class="layui-badge layui-bg-green">{{ item.user_count }}</a></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><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">
|
<td class="center">
|
||||||
<div class="layui-dropdown">
|
<div class="layui-dropdown">
|
||||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
|
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
|
||||||
|
<li><a href="{{ users_url }}">成员</a></li>
|
||||||
<li><a href="{{ edit_url }}">编辑</a></li>
|
<li><a href="{{ edit_url }}">编辑</a></li>
|
||||||
{% if item.deleted == 0 %}
|
{% if item.deleted == 0 %}
|
||||||
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
|
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
|
||||||
|
70
app/Http/Admin/Views/im/group/users.volt
Normal file
70
app/Http/Admin/Views/im/group/users.volt
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{% extends 'templates/main.volt' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ partial('macros/user') }}
|
||||||
|
|
||||||
|
{% set back_url = url({'for':'admin.im_group.list'}) %}
|
||||||
|
|
||||||
|
<div class="kg-nav">
|
||||||
|
<div class="kg-nav-left">
|
||||||
|
<span class="layui-breadcrumb">
|
||||||
|
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
|
<a href="{{ back_url }}"><cite>群组列表</cite></a>
|
||||||
|
<a><cite>{{ group.name }}</cite></a>
|
||||||
|
<a><cite>成员管理</cite></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="kg-table layui-table">
|
||||||
|
<colgroup>
|
||||||
|
<col width="10%">
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col width="10%">
|
||||||
|
</colgroup>
|
||||||
|
<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 user_url = url({'for':'home.user.show','id':item.user.id}) %}
|
||||||
|
{% set delete_url = url({'for':'admin.im_group_user.delete'},{'group_id':item.group_id,'user_id':item.user_id}) %}
|
||||||
|
{% set is_owner = item.user.id == group.owner_id ? 1 : 0 %}
|
||||||
|
{% set role_type = is_owner == 1 ? '群主' : '成员' %}
|
||||||
|
<tr>
|
||||||
|
<td class="center">
|
||||||
|
<img class="avatar-sm" src="{{ item.user.avatar }}!avatar_160" alt="{{ item.user.name }}">
|
||||||
|
</td>
|
||||||
|
<td><a href="{{ user_url }}" title="{{ item.user.about }}" target="_blank">{{ item.user.name }}</a>({{ item.user.id }})</td>
|
||||||
|
<td>{{ item.user.area }}</td>
|
||||||
|
<td>{{ gender_info(item.user.gender) }}</td>
|
||||||
|
<td>{{ role_type }}</td>
|
||||||
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
|
<td class="center">
|
||||||
|
{% if is_owner == 0 %}
|
||||||
|
<button class="layui-btn layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="layui-btn layui-btn-disabled">删除</button>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{ partial('partials/pager') }}
|
||||||
|
|
||||||
|
{% endblock %}
|
27
app/Http/Admin/Views/macros/course.volt
Normal file
27
app/Http/Admin/Views/macros/course.volt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{%- macro model_info(value) %}
|
||||||
|
{% if value == 1 %}
|
||||||
|
点播
|
||||||
|
{% elseif value == 2 %}
|
||||||
|
直播
|
||||||
|
{% elseif value == 3 %}
|
||||||
|
专栏
|
||||||
|
{% elseif value == 4 %}
|
||||||
|
面授
|
||||||
|
{% else %}
|
||||||
|
未知
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro level_info(value) %}
|
||||||
|
{% if value == 1 %}
|
||||||
|
入门
|
||||||
|
{% elseif value == 2 %}
|
||||||
|
初级
|
||||||
|
{% elseif value == 3 %}
|
||||||
|
中级
|
||||||
|
{% elseif value == 4 %}
|
||||||
|
高级
|
||||||
|
{% else %}
|
||||||
|
未知
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
11
app/Http/Admin/Views/macros/group.volt
Normal file
11
app/Http/Admin/Views/macros/group.volt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{%- macro type_info(value) %}
|
||||||
|
{% if value == 1 %}
|
||||||
|
课程
|
||||||
|
{% elseif value == 2 %}
|
||||||
|
水吧
|
||||||
|
{% elseif value == 3 %}
|
||||||
|
职工
|
||||||
|
{% else %}
|
||||||
|
未知
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
34
app/Http/Admin/Views/macros/user.volt
Normal file
34
app/Http/Admin/Views/macros/user.volt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{%- macro gender_info(value) %}
|
||||||
|
{% if value == 1 %}
|
||||||
|
男
|
||||||
|
{% elseif value == 2 %}
|
||||||
|
女
|
||||||
|
{% elseif value == 3 %}
|
||||||
|
密
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro edu_role_info(role) %}
|
||||||
|
{% if role.id == 1 %}
|
||||||
|
学员
|
||||||
|
{% elseif role.id == 2 %}
|
||||||
|
讲师
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro admin_role_info(role) %}
|
||||||
|
{% if role.id > 0 %}
|
||||||
|
{{ role.name }}
|
||||||
|
{% else %}
|
||||||
|
N/A
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro status_info(user) %}
|
||||||
|
{% if user.vip == 1 %}
|
||||||
|
<span class="layui-badge layui-bg-orange" title="期限:{{ date('Y-m-d H:i:s',user.vip_expiry_time) }}">会员</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.locked == 1 %}
|
||||||
|
<span class="layui-badge" title="期限:{{ date('Y-m-d H:i:s',user.lock_expiry_time) }}">锁定</span>
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
@ -26,12 +26,14 @@
|
|||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
<col>
|
||||||
<col width="10%">
|
<col width="10%">
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>商品信息</th>
|
<th>商品信息</th>
|
||||||
<th>买家信息</th>
|
<th>买家信息</th>
|
||||||
|
<th>促销类型</th>
|
||||||
<th>订单金额</th>
|
<th>订单金额</th>
|
||||||
<th>订单状态</th>
|
<th>订单状态</th>
|
||||||
<th>创建时间</th>
|
<th>创建时间</th>
|
||||||
@ -44,17 +46,13 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<p>名称:{{ item.subject }}</p>
|
<p>名称:{{ item.subject }}</p>
|
||||||
<p class="meta">
|
<p>单号:{{ item.sn }}</p>
|
||||||
<span>单号:{{ item.sn }}</span>
|
|
||||||
{% if item.promotion_type > 0 %}
|
|
||||||
<span>促销:{{ promotion_type(item.promotion_type) }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<p>昵称:{{ item.owner.name }}</p>
|
<p>昵称:{{ item.owner.name }}</p>
|
||||||
<p>编号:{{ item.owner.id }}</p>
|
<p>编号:{{ item.owner.id }}</p>
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ promotion_type(item.promotion_type) }}</td>
|
||||||
<td>{{ '¥%0.2f'|format(item.amount) }}</td>
|
<td>{{ '¥%0.2f'|format(item.amount) }}</td>
|
||||||
<td>{{ order_status(item.status) }}</td>
|
<td>{{ order_status(item.status) }}</td>
|
||||||
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
|
@ -3,16 +3,35 @@
|
|||||||
{% set course = order.item_info['course'] %}
|
{% set course = order.item_info['course'] %}
|
||||||
<div class="kg-order-item">
|
<div class="kg-order-item">
|
||||||
<p>课程名称:{{ course['title'] }}</p>
|
<p>课程名称:{{ course['title'] }}</p>
|
||||||
<p>市场价格:{{ '¥%0.2f'|format(course['market_price']) }},会员价格:{{ '¥%0.2f'|format(course['vip_price']) }}</p>
|
<p>
|
||||||
<p>学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }},退款期限:{% if course['refund_expiry'] > 0 %}{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}{% else %}不支持{% endif %}</p>
|
<span>市场价格:{{ '¥%0.2f'|format(course['market_price']) }}</span>
|
||||||
|
<span>会员价格:{{ '¥%0.2f'|format(course['vip_price']) }}</span>
|
||||||
|
</p>
|
||||||
|
{% if course['model'] in [1,2,3] %}
|
||||||
|
<p>
|
||||||
|
<span>学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }}</span>
|
||||||
|
<span>退款期限:{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}</span>
|
||||||
|
</p>
|
||||||
|
{% elseif course['model'] == 4 %}
|
||||||
|
<p>上课时间:{{ course['attrs']['start_date'] }} ~ {{ course['attrs']['end_date'] }}</p>
|
||||||
|
<p>上课地点:{{ course['attrs']['location'] }}</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% elseif order.item_type == 2 %}
|
{% elseif order.item_type == 2 %}
|
||||||
{% set courses = order.item_info['courses'] %}
|
{% set courses = order.item_info['courses'] %}
|
||||||
{% for course in courses %}
|
{% for course in courses %}
|
||||||
<div class="kg-order-item">
|
<div class="kg-order-item">
|
||||||
<p>课程名称:{{ course['title'] }}</p>
|
<p>课程名称:{{ course['title'] }}</p>
|
||||||
<p>市场价格:{{ '¥%0.2f'|format(course['market_price']) }},会员价格:{{ '¥%0.2f'|format(course['vip_price']) }}</p>
|
<p>
|
||||||
<p>学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }},退款期限:{% if course['refund_expiry'] > 0 %}{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}{% else %}不支持{% endif %}</p>
|
<span>市场价格:{{ '¥%0.2f'|format(course['market_price']) }}</span>
|
||||||
|
<span>会员价格:{{ '¥%0.2f'|format(course['vip_price']) }}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% if course['model'] in [1,2,3] %}
|
||||||
|
<span>学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }}</span>
|
||||||
|
<span>退款期限:{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% elseif order.item_type == 3 %}
|
{% elseif order.item_type == 3 %}
|
||||||
@ -65,11 +84,11 @@
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro promotion_type(value) %}
|
{%- macro promotion_type(value) %}
|
||||||
{% if value == 0 %}
|
{% if value == 1 %}
|
||||||
N/A
|
|
||||||
{% elseif value == 1 %}
|
|
||||||
秒杀
|
秒杀
|
||||||
{% elseif value == 2 %}
|
{% elseif value == 2 %}
|
||||||
折扣
|
折扣
|
||||||
|
{% else %}
|
||||||
|
N/A
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
@ -2,38 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{%- macro gender_info(value) %}
|
{{ partial('macros/user') }}
|
||||||
{% if value == 1 %}
|
|
||||||
男
|
|
||||||
{% elseif value == 2 %}
|
|
||||||
女
|
|
||||||
{% elseif value == 3 %}
|
|
||||||
密
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro edu_role_info(role) %}
|
|
||||||
{% if role.id == 1 %}
|
|
||||||
学员
|
|
||||||
{% elseif role.id == 2 %}
|
|
||||||
讲师
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro admin_role_info(role) %}
|
|
||||||
{% if role.id > 0 %}
|
|
||||||
{{ role.name }}
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro status_info(user) %}
|
|
||||||
{% if user.vip == 1 %}
|
|
||||||
<span class="layui-badge layui-bg-orange" title="期限:{{ date('Y-m-d H:i:s',user.vip_expiry_time) }}">会员</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if user.locked == 1 %}
|
|
||||||
<span class="layui-badge" title="期限:{{ date('Y-m-d H:i:s',user.lock_expiry_time) }}">锁定</span>
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{% set add_url = url({'for':'admin.user.add'}) %}
|
{% set add_url = url({'for':'admin.user.add'}) %}
|
||||||
{% set search_url = url({'for':'admin.user.search'}) %}
|
{% set search_url = url({'for':'admin.user.search'}) %}
|
||||||
@ -56,22 +25,22 @@
|
|||||||
|
|
||||||
<table class="layui-table kg-table">
|
<table class="layui-table kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
|
<col width="10%">
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col width="10%">
|
||||||
<col width="12%">
|
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>编号</th>
|
<th>用户头像</th>
|
||||||
<th>昵称</th>
|
<th>用户昵称</th>
|
||||||
<th>性别</th>
|
<th>所在地区</th>
|
||||||
<th>教学角色</th>
|
<th>用户性别</th>
|
||||||
<th>后台角色</th>
|
<th>用户角色</th>
|
||||||
<th>活跃时间</th>
|
<th>活跃时间</th>
|
||||||
<th>注册时间</th>
|
<th>注册时间</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
@ -82,11 +51,16 @@
|
|||||||
{% set preview_url = url({'for':'home.user.show','id':item.id}) %}
|
{% set preview_url = url({'for':'home.user.show','id':item.id}) %}
|
||||||
{% set edit_url = url({'for':'admin.user.edit','id':item.id}) %}
|
{% set edit_url = url({'for':'admin.user.edit','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.id }}</td>
|
<td class="center">
|
||||||
<td><a href="{{ edit_url }}" title="{{ item.about }}">{{ item.name }}</a>{{ status_info(item) }}</td>
|
<img class="avatar-sm" src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
|
||||||
|
</td>
|
||||||
|
<td><a href="{{ preview_url }}" title="{{ item.about }}" target="_blank">{{ item.name }}</a>({{ item.id }}){{ status_info(item) }}</td>
|
||||||
|
<td>{{ item.area }}</td>
|
||||||
<td>{{ gender_info(item.gender) }}</td>
|
<td>{{ gender_info(item.gender) }}</td>
|
||||||
<td>{{ edu_role_info(item.edu_role) }}</td>
|
<td>
|
||||||
<td>{{ admin_role_info(item.admin_role) }}</td>
|
<p>教学:{{ edu_role_info(item.edu_role) }}</p>
|
||||||
|
<p>后台:{{ admin_role_info(item.admin_role) }}</p>
|
||||||
|
</td>
|
||||||
<td>{{ date('Y-m-d H:i:s',item.active_time) }}</td>
|
<td>{{ date('Y-m-d H:i:s',item.active_time) }}</td>
|
||||||
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
|
@ -68,6 +68,19 @@ class ImGroupController extends Controller
|
|||||||
$this->view->setVar('pager', $pager);
|
$this->view->setVar('pager', $pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/edit", name="home.im_group.edit")
|
||||||
|
*/
|
||||||
|
public function editAction($id)
|
||||||
|
{
|
||||||
|
$service = new ImGroupService();
|
||||||
|
|
||||||
|
$group = $service->getGroup($id);
|
||||||
|
|
||||||
|
$this->view->pick('im/group/edit');
|
||||||
|
$this->view->setVar('group', $group);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Get("/{id:[0-9]+}/users/active", name="home.im_group.active_users")
|
* @Get("/{id:[0-9]+}/users/active", name="home.im_group.active_users")
|
||||||
*/
|
*/
|
||||||
@ -82,4 +95,31 @@ class ImGroupController extends Controller
|
|||||||
$this->view->setVar('users', $users);
|
$this->view->setVar('users', $users);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/users/manage", name="home.im_group.manage_users")
|
||||||
|
*/
|
||||||
|
public function manageUsersAction($id)
|
||||||
|
{
|
||||||
|
$service = new ImGroupService();
|
||||||
|
|
||||||
|
$group = $service->getGroup($id);
|
||||||
|
$pager = $service->getGroupUsers($id);
|
||||||
|
|
||||||
|
$this->view->pick('im/group/manage_users');
|
||||||
|
$this->view->setVar('group', $group);
|
||||||
|
$this->view->setVar('pager', $pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/{id:[0-9]+}/update", name="home.im_group.update")
|
||||||
|
*/
|
||||||
|
public function updateAction($id)
|
||||||
|
{
|
||||||
|
$service = new ImGroupService();
|
||||||
|
|
||||||
|
$service->updateGroup($id);
|
||||||
|
|
||||||
|
return $this->jsonSuccess(['msg' => '更新群组成功']);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Home\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Home\Services\ImGroup as ImGroupService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @RoutePrefix("/igm")
|
|
||||||
*/
|
|
||||||
class ImGroupManageController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/{id:[0-9]+}/users", name="home.igm.users")
|
|
||||||
*/
|
|
||||||
public function usersAction($id)
|
|
||||||
{
|
|
||||||
$service = new ImGroupService();
|
|
||||||
|
|
||||||
$group = $service->getGroup($id);
|
|
||||||
|
|
||||||
$pager = $service->getGroupUsers($id);
|
|
||||||
|
|
||||||
$this->view->pick('im/group/manage/users');
|
|
||||||
$this->view->setVar('group', $group);
|
|
||||||
$this->view->setVar('pager', $pager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/{id:[0-9]+}/edit", name="home.igm.edit")
|
|
||||||
*/
|
|
||||||
public function editAction($id)
|
|
||||||
{
|
|
||||||
$service = new ImGroupService();
|
|
||||||
|
|
||||||
$group = $service->getGroup($id);
|
|
||||||
|
|
||||||
$this->view->pick('im/group/manage/edit');
|
|
||||||
$this->view->setVar('group', $group);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/{id:[0-9]+}/update", name="home.igm.update")
|
|
||||||
*/
|
|
||||||
public function updateAction($id)
|
|
||||||
{
|
|
||||||
$service = new ImGroupService();
|
|
||||||
|
|
||||||
$service->updateGroup($id);
|
|
||||||
|
|
||||||
return $this->jsonSuccess(['msg' => '更新群组成功']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/{gid:[0-9]+}/user/{uid:[0-9]+}/delete", name="home.igm.delete_user")
|
|
||||||
*/
|
|
||||||
public function deleteGroupUserAction($gid, $uid)
|
|
||||||
{
|
|
||||||
$service = new ImGroupService();
|
|
||||||
|
|
||||||
$service->deleteGroupUser($gid, $uid);
|
|
||||||
|
|
||||||
$location = $this->request->getHTTPReferer();
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '移除用户成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
32
app/Http/Home/Controllers/ImGroupUserController.php
Normal file
32
app/Http/Home/Controllers/ImGroupUserController.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Home\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Home\Services\ImGroupUser as ImGroupUserService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RoutePrefix("/im/group/user")
|
||||||
|
*/
|
||||||
|
class ImGroupUserController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete", name="home.im_group_user.delete")
|
||||||
|
*/
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
$groupService = new ImGroupUserService();
|
||||||
|
|
||||||
|
$groupService->deleteGroupUser();
|
||||||
|
|
||||||
|
$location = $this->request->getHTTPReferer();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '删除成员成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,12 +7,10 @@ use App\Builders\ImGroupUserList as ImGroupUserListBuilder;
|
|||||||
use App\Caches\ImGroupActiveUserList as ImGroupActiveUserListCache;
|
use App\Caches\ImGroupActiveUserList as ImGroupActiveUserListCache;
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
use App\Models\ImGroup as ImGroupModel;
|
use App\Models\ImGroup as ImGroupModel;
|
||||||
use App\Models\ImUser as ImUserModel;
|
|
||||||
use App\Repos\ImGroup as ImGroupRepo;
|
use App\Repos\ImGroup as ImGroupRepo;
|
||||||
use App\Repos\ImGroupUser as ImGroupUserRepo;
|
use App\Repos\ImGroupUser as ImGroupUserRepo;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
use App\Validators\ImGroup as ImGroupValidator;
|
use App\Validators\ImGroup as ImGroupValidator;
|
||||||
use App\Validators\ImGroupUser as ImGroupUserValidator;
|
|
||||||
|
|
||||||
class ImGroup extends Service
|
class ImGroup extends Service
|
||||||
{
|
{
|
||||||
@ -131,27 +129,6 @@ class ImGroup extends Service
|
|||||||
return $group;
|
return $group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteGroupUser($groupId, $userId)
|
|
||||||
{
|
|
||||||
$loginUser = $this->getLoginUser();
|
|
||||||
|
|
||||||
$validator = new ImGroupUserValidator();
|
|
||||||
|
|
||||||
$group = $validator->checkGroup($groupId);
|
|
||||||
|
|
||||||
$user = $validator->checkUser($userId);
|
|
||||||
|
|
||||||
$validator->checkOwner($loginUser->id, $group->owner_id);
|
|
||||||
|
|
||||||
$groupUser = $validator->checkGroupUser($groupId, $userId);
|
|
||||||
|
|
||||||
$groupUser->delete();
|
|
||||||
|
|
||||||
$this->decrGroupUserCount($group);
|
|
||||||
|
|
||||||
$this->decrUserGroupCount($user);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleGroupUsers($pager)
|
protected function handleGroupUsers($pager)
|
||||||
{
|
{
|
||||||
if ($pager->total_items == 0) {
|
if ($pager->total_items == 0) {
|
||||||
@ -160,18 +137,10 @@ class ImGroup extends Service
|
|||||||
|
|
||||||
$builder = new ImGroupUserListBuilder();
|
$builder = new ImGroupUserListBuilder();
|
||||||
|
|
||||||
$relations = $pager->items->toArray();
|
$stepA = $pager->items->toArray();
|
||||||
|
$stepB = $builder->handleUsers($stepA);
|
||||||
|
|
||||||
$users = $builder->getUsers($relations);
|
$pager->items = $stepB;
|
||||||
|
|
||||||
$items = [];
|
|
||||||
|
|
||||||
foreach ($relations as $relation) {
|
|
||||||
$user = $users[$relation['user_id']] ?? new \stdClass();
|
|
||||||
$items[] = $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
$pager->items = $items;
|
|
||||||
|
|
||||||
return $pager;
|
return $pager;
|
||||||
}
|
}
|
||||||
@ -214,20 +183,4 @@ class ImGroup extends Service
|
|||||||
return $pager;
|
return $pager;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function decrGroupUserCount(ImGroupModel $group)
|
|
||||||
{
|
|
||||||
if ($group->user_count > 0) {
|
|
||||||
$group->user_count -= 1;
|
|
||||||
$group->update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function decrUserGroupCount(ImUserModel $user)
|
|
||||||
{
|
|
||||||
if ($user->group_count > 0) {
|
|
||||||
$user->group_count -= 1;
|
|
||||||
$user->update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,8 @@ Trait ImGroupTrait
|
|||||||
|
|
||||||
$groupUser = $validator->checkGroupUser($group->id, $user->id);
|
$groupUser = $validator->checkGroupUser($group->id, $user->id);
|
||||||
|
|
||||||
|
$validator->checkIfAllowDelete($group->id, $user->id);
|
||||||
|
|
||||||
$groupUser->delete();
|
$groupUser->delete();
|
||||||
|
|
||||||
$this->decrGroupUserCount($group);
|
$this->decrGroupUserCount($group);
|
||||||
|
58
app/Http/Home/Services/ImGroupUser.php
Normal file
58
app/Http/Home/Services/ImGroupUser.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Home\Services;
|
||||||
|
|
||||||
|
use App\Models\ImGroup as ImGroupModel;
|
||||||
|
use App\Models\ImUser as ImUserModel;
|
||||||
|
use App\Validators\ImGroupUser as ImGroupUserValidator;
|
||||||
|
|
||||||
|
class ImGroupUser extends Service
|
||||||
|
{
|
||||||
|
|
||||||
|
public function deleteGroupUser()
|
||||||
|
{
|
||||||
|
$groupId = $this->request->getQuery('group_id', 'int', 0);
|
||||||
|
$userId = $this->request->getQuery('user_id', 'int', 0);
|
||||||
|
|
||||||
|
$validator = new ImGroupUserValidator();
|
||||||
|
|
||||||
|
$group = $validator->checkGroup($groupId);
|
||||||
|
$user = $validator->checkUser($userId);
|
||||||
|
|
||||||
|
$loginUser = $this->getLoginUser();
|
||||||
|
|
||||||
|
$validator->checkOwner($loginUser->id, $group->owner_id);
|
||||||
|
$validator->checkIfAllowDelete($groupId, $userId);
|
||||||
|
|
||||||
|
$groupUser = $this->findOrFail($groupId, $userId);
|
||||||
|
|
||||||
|
$groupUser->delete();
|
||||||
|
|
||||||
|
$this->decrGroupUserCount($group);
|
||||||
|
$this->decrUserGroupCount($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decrGroupUserCount(ImGroupModel $group)
|
||||||
|
{
|
||||||
|
if ($group->user_count > 0) {
|
||||||
|
$group->user_count -= 1;
|
||||||
|
$group->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decrUserGroupCount(ImUserModel $user)
|
||||||
|
{
|
||||||
|
if ($user->group_count > 0) {
|
||||||
|
$user->group_count -= 1;
|
||||||
|
$user->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findOrFail($groupId, $userId)
|
||||||
|
{
|
||||||
|
$validator = new ImGroupUserValidator();
|
||||||
|
|
||||||
|
return $validator->checkGroupUser($groupId, $userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -45,6 +45,17 @@
|
|||||||
</a>
|
</a>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro offline_lesson_info(lesson) %}
|
||||||
|
<a class="deny view-lesson" href="javascript:">
|
||||||
|
<i class="layui-icon layui-icon-user"></i>
|
||||||
|
<span class="title">{{ lesson.title }}</span>
|
||||||
|
{% if lesson.free == 1 %}
|
||||||
|
<span class="layui-badge free-badge">免费</span>
|
||||||
|
{% endif %}
|
||||||
|
<span class="live" title="{{ date('Y-m-d H:i',lesson.attrs.start_time) }}">{{ offline_status_info(lesson) }}</span>
|
||||||
|
</a>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro live_status_info(lesson) %}
|
{%- macro live_status_info(lesson) %}
|
||||||
{% if lesson.attrs.stream.status == 'active' %}
|
{% if lesson.attrs.stream.status == 'active' %}
|
||||||
<span class="active">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 直播中</span>
|
<span class="active">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 直播中</span>
|
||||||
@ -55,6 +66,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro offline_status_info(lesson) %}
|
||||||
|
{% if lesson.attrs.start_time < time() and lesson.attrs.end_time > time() %}
|
||||||
|
<span class="active">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 授课中</span>
|
||||||
|
{% elseif lesson.attrs.start_time > time() %}
|
||||||
|
<span class="pending">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 未开始</span>
|
||||||
|
{% elseif lesson.attrs.end_time < time() %}
|
||||||
|
<span class="finished">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 已结束</span>
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{% if chapters %}
|
{% if chapters %}
|
||||||
<div class="layui-collapse">
|
<div class="layui-collapse">
|
||||||
{% for chapter in chapters %}
|
{% for chapter in chapters %}
|
||||||
@ -69,6 +90,8 @@
|
|||||||
<li class="lesson-item clearfix">{{ live_lesson_info(lesson) }}</li>
|
<li class="lesson-item clearfix">{{ live_lesson_info(lesson) }}</li>
|
||||||
{% elseif lesson.model == 3 %}
|
{% elseif lesson.model == 3 %}
|
||||||
<li class="lesson-item clearfix">{{ read_lesson_info(lesson) }}</li>
|
<li class="lesson-item clearfix">{{ read_lesson_info(lesson) }}</li>
|
||||||
|
{% elseif lesson.model == 4 %}
|
||||||
|
<li class="lesson-item clearfix">{{ offline_lesson_info(lesson) }}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{%- macro vod_meta_info(course) %}
|
{%- macro vod_meta_info(course) %}
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="key">课程时长</span><span class="value">{{ course.attrs.duration|duration }}</span>
|
<span class="key">课程时长</span>
|
||||||
|
<span class="value">{{ course.attrs.duration|duration }}</span>
|
||||||
</p>
|
</p>
|
||||||
{{ meta_expiry_info(course) }}
|
{{ meta_expiry_info(course) }}
|
||||||
{{ meta_price_info(course) }}
|
{{ meta_price_info(course) }}
|
||||||
@ -9,7 +10,8 @@
|
|||||||
|
|
||||||
{%- macro live_meta_info(course) %}
|
{%- macro live_meta_info(course) %}
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="key">直播时间</span><span class="value">{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</span>
|
<span class="key">直播时间</span>
|
||||||
|
<span class="value">{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</span>
|
||||||
</p>
|
</p>
|
||||||
{{ meta_expiry_info(course) }}
|
{{ meta_expiry_info(course) }}
|
||||||
{{ meta_price_info(course) }}
|
{{ meta_price_info(course) }}
|
||||||
@ -18,20 +20,41 @@
|
|||||||
|
|
||||||
{%- macro read_meta_info(course) %}
|
{%- macro read_meta_info(course) %}
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="key">课程时长</span><span class="value">{{ course.attrs.duration|duration }}</span>
|
<span class="key">课程时长</span>
|
||||||
|
<span class="value">{{ course.attrs.duration|duration }}</span>
|
||||||
</p>
|
</p>
|
||||||
{{ meta_expiry_info(course) }}
|
{{ meta_expiry_info(course) }}
|
||||||
{{ meta_price_info(course) }}
|
{{ meta_price_info(course) }}
|
||||||
{{ meta_stats_info(course) }}
|
{{ meta_stats_info(course) }}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{%- macro offline_meta_info(course) %}
|
||||||
|
{% set search_url = "https://map.baidu.com/search/%s?querytype=s&wd=%s"|format(course.attrs.location,course.attrs.location) %}
|
||||||
|
<p class="item">
|
||||||
|
<span class="key">上课时间</span>
|
||||||
|
<span class="value">{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</span>
|
||||||
|
</p>
|
||||||
|
<p class="item">
|
||||||
|
<span class="key">上课地点</span>
|
||||||
|
<span class="value">{{ course.attrs.location }}</span>
|
||||||
|
<a class="value" href="{{ search_url }}" title="查看地理位置" target="_blank">
|
||||||
|
<i class="layui-icon layui-icon-location"></i>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{{ meta_price_info(course) }}
|
||||||
|
{{ meta_stats_info(course) }}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro meta_expiry_info(course) %}
|
{%- macro meta_expiry_info(course) %}
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="key">学习期限</span><span class="value">{{ course.study_expiry }}个月</span>
|
<span class="key">学习期限</span>
|
||||||
|
<span class="value">{{ course.study_expiry }}个月</span>
|
||||||
{% if course.refund_expiry > 0 %}
|
{% if course.refund_expiry > 0 %}
|
||||||
<span class="key">退款期限</span><span class="value">{{ course.refund_expiry }}天</span>
|
<span class="key">退款期限</span>
|
||||||
|
<span class="value">{{ course.refund_expiry }}天</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="key">退款期限</span><span class="value">不支持</span>
|
<span class="key">退款期限</span>
|
||||||
|
<span class="value">不支持</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
@ -39,26 +62,34 @@
|
|||||||
{%- macro meta_price_info(course) %}
|
{%- macro meta_price_info(course) %}
|
||||||
<p class="item">
|
<p class="item">
|
||||||
{% if course.origin_price > 0 %}
|
{% if course.origin_price > 0 %}
|
||||||
<span class="key">原始价格</span><span class="value origin-price">{{ '¥%0.2f'|format(course.origin_price) }}</span>
|
<span class="key">原始价格</span>
|
||||||
|
<span class="value origin-price">{{ '¥%0.2f'|format(course.origin_price) }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if course.market_price > 0 %}
|
{% if course.market_price > 0 %}
|
||||||
<span class="key">优惠价格</span><span class="value price">{{ '¥%0.2f'|format(course.market_price) }}</span>
|
<span class="key">优惠价格</span>
|
||||||
|
<span class="value price">{{ '¥%0.2f'|format(course.market_price) }}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="key">优惠价格</span><span class="value free">免费</span>
|
<span class="key">优惠价格</span>
|
||||||
|
<span class="value free">免费</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if course.vip_price > 0 %}
|
{% if course.vip_price > 0 %}
|
||||||
<span class="key">会员价格</span><span class="value price">{{ '¥%0.2f'|format(course.vip_price) }}</span>
|
<span class="key">会员价格</span>
|
||||||
|
<span class="value price">{{ '¥%0.2f'|format(course.vip_price) }}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="key">会员价格</span><span class="value free">免费</span>
|
<span class="key">会员价格</span>
|
||||||
|
<span class="value free">免费</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro meta_stats_info(course) %}
|
{%- macro meta_stats_info(course) %}
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="key">难度级别</span><span class="value">{{ level_info(course.level) }}</span>
|
<span class="key">难度级别</span>
|
||||||
<span class="key">学习人次</span><span class="value">{{ course.user_count }}</span>
|
<span class="value">{{ level_info(course.level) }}</span>
|
||||||
<span class="key">综合评分</span><span class="value">{{ "%0.1f"|format(course.ratings.rating) }}</span>
|
<span class="key">学习人次</span>
|
||||||
|
<span class="value">{{ course.user_count }}</span>
|
||||||
|
<span class="key">综合评分</span>
|
||||||
|
<span class="value">{{ "%0.1f"|format(course.ratings.rating) }}</span>
|
||||||
</p>
|
</p>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
@ -73,6 +104,8 @@
|
|||||||
{{ live_meta_info(course) }}
|
{{ live_meta_info(course) }}
|
||||||
{% elseif course.model == 3 %}
|
{% elseif course.model == 3 %}
|
||||||
{{ read_meta_info(course) }}
|
{{ read_meta_info(course) }}
|
||||||
|
{% elseif course.model == 4 %}
|
||||||
|
{{ offline_meta_info(course) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="rating">
|
<div class="rating">
|
||||||
|
@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
{%- macro sale_item_type(value) %}
|
||||||
|
{% if value == 1 %}
|
||||||
|
课程
|
||||||
|
{% elseif value == 2 %}
|
||||||
|
套餐
|
||||||
|
{% elseif value == 3 %}
|
||||||
|
会员
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{%- macro sale_status(value) %}
|
{%- macro sale_status(value) %}
|
||||||
{% if value == 'active' %}
|
{% if value == 'active' %}
|
||||||
进行中
|
进行中
|
||||||
@ -26,6 +36,7 @@
|
|||||||
{% set course = sale.item_info.course %}
|
{% set course = sale.item_info.course %}
|
||||||
{% set course_url = url({'for':'home.course.show','id':course.id}) %}
|
{% set course_url = url({'for':'home.course.show','id':course.id}) %}
|
||||||
<div class="course-card">
|
<div class="course-card">
|
||||||
|
<span class="model layui-badge layui-bg-green">{{ sale_item_type(sale.item_type) }}</span>
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ course_url }}" target="_blank">
|
<a href="{{ course_url }}" target="_blank">
|
||||||
<img src="{{ course.cover }}!cover_270" alt="{{ course.title }}" title="{{ course.title }}">
|
<img src="{{ course.cover }}!cover_270" alt="{{ course.title }}" title="{{ course.title }}">
|
||||||
@ -52,6 +63,7 @@
|
|||||||
{% set package = sale.item_info.package %}
|
{% set package = sale.item_info.package %}
|
||||||
{% set link_url = url({'for':'home.package.courses','id':package.id}) %}
|
{% set link_url = url({'for':'home.package.courses','id':package.id}) %}
|
||||||
<div class="course-card">
|
<div class="course-card">
|
||||||
|
<span class="model layui-badge layui-bg-green">{{ sale_item_type(sale.item_type) }}</span>
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a class="package-link" href="javascript:" data-url="{{ link_url }}">
|
<a class="package-link" href="javascript:" data-url="{{ link_url }}">
|
||||||
<img src="{{ package.cover }}!cover_270" alt="{{ package.title }}" title="{{ package.title }}">
|
<img src="{{ package.cover }}!cover_270" alt="{{ package.title }}" title="{{ package.title }}">
|
||||||
@ -78,6 +90,7 @@
|
|||||||
{% set vip = sale.item_info.vip %}
|
{% set vip = sale.item_info.vip %}
|
||||||
{% set vip.title = "会员服务(%s)"|format(vip.title) %}
|
{% set vip.title = "会员服务(%s)"|format(vip.title) %}
|
||||||
<div class="course-card">
|
<div class="course-card">
|
||||||
|
<span class="model layui-badge layui-bg-green">{{ sale_item_type(sale.item_type) }}</span>
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<img src="{{ vip.cover }}!cover_270" alt="{{ vip.title }}" title="{{ vip.title }}">
|
<img src="{{ vip.cover }}!cover_270" alt="{{ vip.title }}" title="{{ vip.title }}">
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
{% extends 'templates/layer.volt' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
{% if pager.total_items > 0 %}
|
|
||||||
<div class="bg-wrap">
|
|
||||||
<div class="im-user-list clearfix">
|
|
||||||
<div class="layui-row layui-col-space20">
|
|
||||||
{% for item in pager.items %}
|
|
||||||
{% set delete_url = url({'for':'home.igm.delete_user','gid':group.id,'uid':item.id}) %}
|
|
||||||
<div class="layui-col-md2">
|
|
||||||
<div class="user-card">
|
|
||||||
<div class="avatar">
|
|
||||||
<a href="javascript:" title="{{ item.about }}">
|
|
||||||
<img src="{{ item.avatar }}" alt="{{ item.name }}">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="name layui-elip" title="{{ item.name }}">{{ item.name }}</div>
|
|
||||||
<div class="action">
|
|
||||||
<button class="layui-btn kg-delete" data-tips="你确定要移除该用户吗?" data-url="{{ delete_url }}">移除</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ partial('partials/pager') }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
55
app/Http/Home/Views/im/group/manage_users.volt
Normal file
55
app/Http/Home/Views/im/group/manage_users.volt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{% extends 'templates/layer.volt' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ partial('macros/user') }}
|
||||||
|
|
||||||
|
<table class="layui-table mt0">
|
||||||
|
<colgroup>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col>
|
||||||
|
<col width="10%">
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>头像</th>
|
||||||
|
<th>名称</th>
|
||||||
|
<th>地区</th>
|
||||||
|
<th>性别</th>
|
||||||
|
<th>加入时间</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in pager.items %}
|
||||||
|
{% set user_url = url({'for':'home.user.show','id':item.user.id}) %}
|
||||||
|
{% set delete_url = url({'for':'home.im_group_user.delete'},{'group_id':group.id,'user_id':item.user.id}) %}
|
||||||
|
{% set is_owner = item.user.id == group.owner.id ? 1 : 0 %}
|
||||||
|
<tr>
|
||||||
|
<td class="center">
|
||||||
|
<img class="avatar-sm" src="{{ item.user.avatar }}!avatar_160" alt="{{ item.user.name }}">
|
||||||
|
</td>
|
||||||
|
<td><a href="{{ user_url }}" title="{{ item.user.about }}" target="_blank">{{ item.user.name }}</a>({{ item.user.id }})</td>
|
||||||
|
<td>{{ item.user.area }}</td>
|
||||||
|
<td>{{ gender_info(item.user.gender) }}</td>
|
||||||
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
|
<td class="center">
|
||||||
|
{% if is_owner == 0 %}
|
||||||
|
<button class="layui-btn layui-btn-sm layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="layui-btn layui-btn-sm layui-btn-disabled">删除</button>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{ partial('partials/pager') }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -2,21 +2,21 @@
|
|||||||
<div class="layui-row layui-col-space20">
|
<div class="layui-row layui-col-space20">
|
||||||
{% for item in pager.items %}
|
{% for item in pager.items %}
|
||||||
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
||||||
{% set item.title = item.title ? item.title : '暂露头角' %}
|
{% set item.user.title = item.user.title ? item.user.title : '暂露头角' %}
|
||||||
{% set avatar_class = item.vip == 1 ? 'avatar vip' : 'avatar' %}
|
{% set avatar_class = item.user.vip == 1 ? 'avatar vip' : 'avatar' %}
|
||||||
<div class="layui-col-md3">
|
<div class="layui-col-md3">
|
||||||
<div class="user-card">
|
<div class="user-card">
|
||||||
<div class="{{ avatar_class }}">
|
<div class="{{ avatar_class }}">
|
||||||
<a href="{{ user_url }}" title="{{ item.about }}">
|
<a href="{{ user_url }}" title="{{ item.user.about }}">
|
||||||
<img src="{{ item.avatar }}" alt="{{ item.name }}">
|
<img src="{{ item.user.avatar }}" alt="{{ item.user.name }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="name layui-elip">
|
<div class="name layui-elip">
|
||||||
<a href="{{ user_url }}" title="{{ item.about }}">{{ item.name }}</a>
|
<a href="{{ user_url }}" title="{{ item.user.about }}">{{ item.user.name }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="title layui-elip">{{ item.title }}</div>
|
<div class="title layui-elip">{{ item.user.title }}</div>
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<span class="layui-btn apply-friend" data-id="{{ item.id }}" data-name="{{ item.name }}" data-avatar="{{ item.avatar }}">添加好友</span>
|
<span class="layui-btn apply-friend" data-id="{{ item.user.id }}" data-name="{{ item.user.name }}" data-avatar="{{ item.user.avatar }}">添加好友</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
{%- macro model_info(value) %}
|
{%- macro model_info(value) %}
|
||||||
{% if value == '1' %}
|
{% if value == 1 %}
|
||||||
点播
|
点播
|
||||||
{% elseif value == '2' %}
|
{% elseif value == 2 %}
|
||||||
直播
|
直播
|
||||||
{% elseif value == '3' %}
|
{% elseif value == 3 %}
|
||||||
专栏
|
专栏
|
||||||
|
{% elseif value == 4 %}
|
||||||
|
面授
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro level_info(value) %}
|
{%- macro level_info(value) %}
|
||||||
{% if value == '1' %}
|
{% if value == 1 %}
|
||||||
入门
|
入门
|
||||||
{% elseif value == '2' %}
|
{% elseif value == 2 %}
|
||||||
初级
|
初级
|
||||||
{% elseif value == '3' %}
|
{% elseif value == 3 %}
|
||||||
中级
|
中级
|
||||||
{% elseif value == '4' %}
|
{% elseif value == 4 %}
|
||||||
高级
|
高级
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
@ -2,36 +2,55 @@
|
|||||||
{% if order.item_type == 1 %}
|
{% if order.item_type == 1 %}
|
||||||
{% set course = order.item_info.course %}
|
{% set course = order.item_info.course %}
|
||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>课程名称:<span>{{ course.title }}</span></p>
|
<p>课程名称:{{ course.title }}</p>
|
||||||
<p>优惠价格:<span class="price">{{ '¥%0.2f'|format(course.market_price) }}</span>会员价格:<span class="price">{{ '¥%0.2f'|format(course.vip_price) }}</span></p>
|
<p>
|
||||||
<p>学习期限:<span>{{ date('Y-m-d H:i:s',course.study_expiry_time) }}</span>退款期限:<span>{% if course.refund_expiry > 0 %}{{ date('Y-m-d H:i:s',course.refund_expiry_time) }}{% else %}不支持{% endif %}</span></p>
|
<span>优惠价格:<em class="price">{{ '¥%0.2f'|format(course.market_price) }}</em></span>
|
||||||
|
<span>会员价格:<em class="price">{{ '¥%0.2f'|format(course.vip_price) }}</em></span>
|
||||||
|
</p>
|
||||||
|
{% if course.model in [1,2,3] %}
|
||||||
|
<p>
|
||||||
|
<span>学习期限:{{ date('Y-m-d',course.study_expiry_time) }}</span>
|
||||||
|
<span>退款期限:{{ date('Y-m-d',course.refund_expiry_time) }}</span>
|
||||||
|
</p>
|
||||||
|
{% elseif course.model == 4 %}
|
||||||
|
<p>上课时间:{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</p>
|
||||||
|
<p>上课地点:{{ course.attrs.location }}</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% elseif order.item_type == 2 %}
|
{% elseif order.item_type == 2 %}
|
||||||
{% set courses = order.item_info.courses %}
|
{% set courses = order.item_info.courses %}
|
||||||
{% for course in courses %}
|
{% for course in courses %}
|
||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>课程名称:<span>{{ course.title }}</span></p>
|
<p>课程名称:{{ course.title }}</p>
|
||||||
<p>优惠价格:<span class="price">{{ '¥%0.2f'|format(course.market_price) }}</span>会员价格:<span class="price">{{ '¥%0.2f'|format(course.vip_price) }}</span></p>
|
<p>
|
||||||
<p>学习期限:<span>{{ date('Y-m-d H:i:s',course.study_expiry_time) }}</span>退款期限:<span>{% if course.refund_expiry > 0 %}{{ date('Y-m-d H:i:s',course.refund_expiry_time) }}{% else %}不支持{% endif %}</span></p>
|
<span>优惠价格:{{ '¥%0.2f'|format(course.market_price) }}</span>
|
||||||
|
<span>会员价格:<em class="price">{{ '¥%0.2f'|format(course.vip_price) }}</em></span>
|
||||||
|
</p>
|
||||||
|
{% if course.model in [1,2,3] %}
|
||||||
|
<p>
|
||||||
|
<span>学习期限:{{ date('Y-m-d',course.study_expiry_time) }}</span>
|
||||||
|
<span>退款期限:{{ date('Y-m-d',course.refund_expiry_time) }}</span>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% elseif order.item_type == 3 %}
|
{% elseif order.item_type == 3 %}
|
||||||
{% set course = order.item_info.course %}
|
{% set course = order.item_info.course %}
|
||||||
{% set reward = order.item_info.reward %}
|
{% set reward = order.item_info.reward %}
|
||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>课程名称:<span>{{ course.title }}</span></p>
|
<p>课程名称:{{ course.title }}</p>
|
||||||
<p>赞赏金额:<span class="price">{{ '¥%0.2f'|format(reward.price) }}</span></p>
|
<p>赞赏金额:<em class="price">{{ '¥%0.2f'|format(reward.price) }}</em></p>
|
||||||
</div>
|
</div>
|
||||||
{% elseif order.item_type == 4 %}
|
{% elseif order.item_type == 4 %}
|
||||||
{% set vip = order.item_info.vip %}
|
{% set vip = order.item_info.vip %}
|
||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>商品名称:<span>{{ order.subject }}</span></p>
|
<p>商品名称:{{ order.subject }}</p>
|
||||||
<p>商品价格:<span class="price">{{ '¥%0.2f'|format(order.amount) }}</span></p>
|
<p>商品价格:<em class="price">{{ '¥%0.2f'|format(order.amount) }}</em></p>
|
||||||
</div>
|
</div>
|
||||||
{% elseif order.item_type == 99 %}
|
{% elseif order.item_type == 99 %}
|
||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>商品名称:<span>{{ order.subject }}</span></p>
|
<p>商品名称:{{ order.subject }}</p>
|
||||||
<p>商品价格:<span class="price">{{ '¥%0.2f'|format(order.amount) }}</span></p>
|
<p>商品价格:<em class="price">{{ '¥%0.2f'|format(order.amount) }}</em></p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
@ -67,11 +86,11 @@
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro promotion_type(value) %}
|
{%- macro promotion_type(value) %}
|
||||||
{% if value == 0 %}
|
{% if value == 1 %}
|
||||||
N/A
|
|
||||||
{% elseif value == 1 %}
|
|
||||||
秒杀
|
秒杀
|
||||||
{% elseif value == 2 %}
|
{% elseif value == 2 %}
|
||||||
折扣
|
折扣
|
||||||
|
{% else %}
|
||||||
|
N/A
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
@ -13,18 +13,33 @@
|
|||||||
<div class="info">
|
<div class="info">
|
||||||
<p><a href="{{ course_url }}" target="_blank">{{ course.title }}</a></p>
|
<p><a href="{{ course_url }}" target="_blank">{{ course.title }}</a></p>
|
||||||
<p>
|
<p>
|
||||||
<span class="key">原始价格</span><span class="value origin-price">{{ '¥%0.2f'|format(course.origin_price) }}</span>
|
<span class="key">原始价格</span>
|
||||||
<span class="key">优惠价格</span><span class="price">{{ '¥%0.2f'|format(course.market_price) }}</span>
|
<span class="value origin-price">{{ '¥%0.2f'|format(course.origin_price) }}</span>
|
||||||
<span class="key">会员价格</span><span class="price">{{ '¥%0.2f'|format(course.vip_price) }}</span>
|
<span class="key">优惠价格</span>
|
||||||
</p>
|
<span class="price">{{ '¥%0.2f'|format(course.market_price) }}</span>
|
||||||
<p>
|
<span class="key">会员价格</span>
|
||||||
<span class="key">学习期限</span><span class="value">{{ course.study_expiry }}个月</span>
|
<span class="price">{{ '¥%0.2f'|format(course.vip_price) }}</span>
|
||||||
{% if course.refund_expiry > 0 %}
|
|
||||||
<span class="key">退款期限</span><span class="value">{{ course.refund_expiry }}天</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="key">退款期限</span><span class="value">不支持</span>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
</p>
|
||||||
|
{% if course.model in [1,2,3] %}
|
||||||
|
<p>
|
||||||
|
<span class="key">学习期限</span>
|
||||||
|
<span class="value">{{ course.study_expiry }}个月</span>
|
||||||
|
{% if course.refund_expiry > 0 %}
|
||||||
|
<span class="key">退款期限</span>
|
||||||
|
<span class="value">{{ course.refund_expiry }}天</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="key">退款期限</span>
|
||||||
|
<span class="value">不支持</span>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
{% elseif course.model == 4 %}
|
||||||
|
<p>
|
||||||
|
<span class="key">上课时间</span>
|
||||||
|
<span class="value">{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</span>
|
||||||
|
<span class="key">上课地点</span>
|
||||||
|
<span class="value">{{ course.attrs.location }}</span>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
@ -39,11 +54,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<p><a href="{{ course_url }}" target="_blank">{{ course.title }}</a></p>
|
<p><a href="{{ course_url }}" target="_blank">{{ course.title }}</a></p>
|
||||||
<p>赞赏金额 <span class="price">{{ '¥%0.2f'|format(reward.price) }}</span></p>
|
|
||||||
<p>
|
<p>
|
||||||
难度 <span>{{ level_info(course.level) }}</span>
|
<span class="key">赞赏金额</span>
|
||||||
课时 <span>{{ course.lesson_count }}</span>
|
<span class="price">{{ '¥%0.2f'|format(reward.price) }}</span>
|
||||||
学员 <span>{{ course.user_count }}</span>
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="key">难度</span>
|
||||||
|
<span class="value">{{ level_info(course.level) }}</span>
|
||||||
|
<span class="key">课时</span>
|
||||||
|
<span class="value">{{ course.lesson_count }}</span>
|
||||||
|
<span class="key">学员</span>
|
||||||
|
<span class="value">{{ course.user_count }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -57,8 +78,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<p>会员服务</p>
|
<p>会员服务</p>
|
||||||
<p>价格 <span class="price">{{ '¥%0.2f'|format(vip.price) }}</span></p>
|
<p>
|
||||||
<p>期限 <span class="expiry">{{ vip.expiry }}个月</span></p>
|
<span class="key">价格</span>
|
||||||
|
<span class="price">{{ '¥%0.2f'|format(vip.price) }}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="key">期限</span>
|
||||||
|
<span class="expiry">{{ vip.expiry }}个月</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
<table class="layui-table order-table">
|
<table class="layui-table order-table">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
订单金额:<span class="price">{{ '¥%0.2f'|format(order.amount) }}</span>
|
<span>订单金额:<em class="price">{{ '¥%0.2f'|format(order.amount) }}</em></span>
|
||||||
订单状态:<span class="status">{{ order_status(order.status) }}</span>
|
<span>订单状态:{{ order_status(order.status) }}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -21,10 +21,10 @@
|
|||||||
</table>
|
</table>
|
||||||
<br>
|
<br>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
{% if order.status == 1 %}
|
{% if order.me.allow_pay == 1 %}
|
||||||
<a class="layui-btn layui-bg-blue" href="{{ order_pay_url }}" target="_top">立即支付</a>
|
<a class="layui-btn layui-bg-blue" href="{{ order_pay_url }}" target="_top">立即支付</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if (order.item_type in [1,2]) and (order.status == 3) %}
|
{% if order.me.allow_refund == 1 %}
|
||||||
<a class="layui-btn layui-bg-blue" href="{{ refund_confirm_url }}">申请退款</a>
|
<a class="layui-btn layui-bg-blue" href="{{ refund_confirm_url }}">申请退款</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,31 +2,29 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div>
|
<table class="layui-table mt0">
|
||||||
<table class="layui-table">
|
<colgroup>
|
||||||
<colgroup>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
</colgroup>
|
||||||
</colgroup>
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
|
<th>课程标题</th>
|
||||||
|
<th>销售价格</th>
|
||||||
|
<th>购买人次</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in courses %}
|
||||||
|
{% set course_url = url({'for':'home.course.show','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>标题</th>
|
<td><a href="{{ course_url }}" target="_blank">{{ item.title }}</a></td>
|
||||||
<th>学员数</th>
|
<td class="red">{{ '¥%0.2f'|format(item.market_price) }}</td>
|
||||||
<th>价格</th>
|
<td>{{ item.user_count }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody>
|
</tbody>
|
||||||
{% for item in courses %}
|
</table>
|
||||||
{% set course_url = url({'for':'home.course.show','id':item.id}) %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{{ course_url }}" target="_blank">{{ item.title }}</a></td>
|
|
||||||
<td>{{ item.user_count }}</td>
|
|
||||||
<td class="red">{{ '¥%0.2f'|format(item.market_price) }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -12,20 +12,22 @@
|
|||||||
<span class="title">我的好友</span>
|
<span class="title">我的好友</span>
|
||||||
</div>
|
</div>
|
||||||
{% if pager.total_pages > 0 %}
|
{% if pager.total_pages > 0 %}
|
||||||
<table class="layui-table" lay-size="lg">
|
<table class="layui-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col width="10%">
|
<col>
|
||||||
|
<col width="12%">
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>头像</th>
|
||||||
<th>昵称</th>
|
<th>昵称</th>
|
||||||
<th>性别</th>
|
<th>性别</th>
|
||||||
<th>地区</th>
|
<th>地区</th>
|
||||||
<th>最后活跃</th>
|
<th>活跃</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -34,11 +36,14 @@
|
|||||||
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
||||||
{% set delete_url = url({'for':'home.im.quit_friend','id':item.id}) %}
|
{% set delete_url = url({'for':'home.im.quit_friend','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{ user_url }}" title="{{ item.about }}">{{ item.name }}</a></td>
|
<td class="center">
|
||||||
|
<img class="avatar-sm" src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
|
||||||
|
</td>
|
||||||
|
<td><a href="{{ user_url }}" title="{{ item.about }}" target="_blank">{{ item.name }}</a></td>
|
||||||
<td>{{ gender_info(item.gender) }}</td>
|
<td>{{ gender_info(item.gender) }}</td>
|
||||||
<td>{{ item.area }}</td>
|
<td>{{ item.area }}</td>
|
||||||
<td>{{ item.active_time|time_ago }}</td>
|
<td>{{ item.active_time|time_ago }}</td>
|
||||||
<td>
|
<td class="center">
|
||||||
<button class="layui-btn layui-btn-sm kg-delete" data-url="{{ delete_url }}">删除</button>
|
<button class="layui-btn layui-btn-sm kg-delete" data-url="{{ delete_url }}">删除</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{% if pager.total_pages > 0 %}
|
{% if pager.total_pages > 0 %}
|
||||||
<table class="layui-table" lay-size="lg">
|
<table class="layui-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -9,10 +9,10 @@
|
|||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>头像</th>
|
||||||
<th>名称</th>
|
<th>名称</th>
|
||||||
<th>类型</th>
|
<th>类型</th>
|
||||||
<th>组长</th>
|
<th>组长</th>
|
||||||
<th>成员</th>
|
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -21,13 +21,20 @@
|
|||||||
{% set show_url = url({'for':'home.im_group.show','id':item.id}) %}
|
{% set show_url = url({'for':'home.im_group.show','id':item.id}) %}
|
||||||
{% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %}
|
{% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %}
|
||||||
{% set delete_url = url({'for':'home.im.quit_group','id':item.id}) %}
|
{% set delete_url = url({'for':'home.im.quit_group','id':item.id}) %}
|
||||||
|
{% set is_owner = auth_user.id == item.owner.id ? 1 : 0 %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td class="center">
|
||||||
|
<img class="avatar-sm" src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
|
||||||
|
</td>
|
||||||
<td><a href="{{ show_url }}" title="{{ item.about }}">{{ item.name }}</a></td>
|
<td><a href="{{ show_url }}" title="{{ item.about }}">{{ item.name }}</a></td>
|
||||||
<td>{{ type_info(item.type) }}</td>
|
<td>{{ type_info(item.type) }}</td>
|
||||||
<td><a href="{{ owner_url }}">{{ item.owner.name }}</a></td>
|
<td><a href="{{ owner_url }}">{{ item.owner.name }}</a></td>
|
||||||
<td>{{ item.user_count }}</td>
|
<td class="center">
|
||||||
<td>
|
{% if is_owner == 0 %}
|
||||||
<button class="layui-btn layui-btn-sm kg-delete" data-tips="确定要退出吗?" data-url="{{ delete_url }}">退出</button>
|
<button class="layui-btn layui-btn-sm layui-bg-red kg-delete" data-tips="确定要退出吗?" data-url="{{ delete_url }}">退出</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="layui-btn layui-btn-sm layui-btn-disabled">退出</button>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
{% if pager.total_pages > 0 %}
|
{% if pager.total_pages > 0 %}
|
||||||
<table class="layui-table" lay-size="lg">
|
<table class="layui-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
<col>
|
||||||
<col width="18%">
|
<col width="18%">
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>头像</th>
|
||||||
<th>名称</th>
|
<th>名称</th>
|
||||||
<th>类型</th>
|
<th>类型</th>
|
||||||
<th>成员</th>
|
<th>成员</th>
|
||||||
@ -18,14 +20,18 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for item in pager.items %}
|
{% for item in pager.items %}
|
||||||
{% set edit_url = url({'for':'home.igm.edit','id':item.id}) %}
|
{% set show_url = url({'for':'home.im_group.show','id':item.id}) %}
|
||||||
{% set users_url = url({'for':'home.igm.users','id':item.id}) %}
|
{% set edit_url = url({'for':'home.im_group.edit','id':item.id}) %}
|
||||||
|
{% set users_url = url({'for':'home.im_group.manage_users','id':item.id},{'limit':10}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span title="{{ item.about }}">{{ item.name }}</span></td>
|
<td class="center">
|
||||||
|
<img class="avatar-sm" src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
|
||||||
|
</td>
|
||||||
|
<td><a href="{{ show_url }}" title="{{ item.about }}">{{ item.name }}</a></td>
|
||||||
<td>{{ type_info(item.type) }}</td>
|
<td>{{ type_info(item.type) }}</td>
|
||||||
<td>{{ item.user_count }}</td>
|
<td>{{ item.user_count }}</td>
|
||||||
<td>{{ item.msg_count }}</td>
|
<td>{{ item.msg_count }}</td>
|
||||||
<td>
|
<td class="center">
|
||||||
<span class="layui-btn layui-btn-xs layui-bg-blue btn-group-user" data-url="{{ users_url }}">成员</span>
|
<span class="layui-btn layui-btn-xs layui-bg-blue btn-group-user" data-url="{{ users_url }}">成员</span>
|
||||||
<span class="layui-btn layui-btn-xs btn-edit-group" data-url="{{ edit_url }}">编辑</span>
|
<span class="layui-btn layui-btn-xs btn-edit-group" data-url="{{ edit_url }}">编辑</span>
|
||||||
</td>
|
</td>
|
||||||
|
@ -11,7 +11,7 @@ class AppInfo
|
|||||||
|
|
||||||
protected $link = 'https://koogua.com';
|
protected $link = 'https://koogua.com';
|
||||||
|
|
||||||
protected $version = '1.2.9';
|
protected $version = '1.3.0';
|
||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,16 @@ class Chapter extends Model
|
|||||||
'word_count' => 0,
|
'word_count' => 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* 面授扩展属性
|
||||||
|
*/
|
||||||
|
protected $_offline_attrs = [
|
||||||
|
'start_time' => 0,
|
||||||
|
'end_time' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主键编号
|
* 主键编号
|
||||||
*
|
*
|
||||||
@ -212,11 +222,14 @@ class Chapter extends Model
|
|||||||
$this->attrs = $this->_live_attrs;
|
$this->attrs = $this->_live_attrs;
|
||||||
} elseif ($this->model == Course::MODEL_READ) {
|
} elseif ($this->model == Course::MODEL_READ) {
|
||||||
$this->attrs = $this->_read_attrs;
|
$this->attrs = $this->_read_attrs;
|
||||||
|
} elseif ($this->model == Course::MODEL_OFFLINE) {
|
||||||
|
$this->attrs = $this->_offline_attrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_array($this->attrs)) {
|
}
|
||||||
$this->attrs = kg_json_encode($this->attrs);
|
|
||||||
}
|
if (is_array($this->attrs)) {
|
||||||
|
$this->attrs = kg_json_encode($this->attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->create_time = time();
|
$this->create_time = time();
|
||||||
|
72
app/Models/ChapterOffline.php
Normal file
72
app/Models/ChapterOffline.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
class ChapterOffline extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键编号
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $id = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程编号
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $course_id = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 章节编号
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $chapter_id = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $start_time = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $end_time = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $create_time = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $update_time = 0;
|
||||||
|
|
||||||
|
public function getSource(): string
|
||||||
|
{
|
||||||
|
return 'kg_chapter_offline';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function beforeCreate()
|
||||||
|
{
|
||||||
|
$this->create_time = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function beforeUpdate()
|
||||||
|
{
|
||||||
|
$this->update_time = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,7 +16,8 @@ class Course extends Model
|
|||||||
*/
|
*/
|
||||||
const MODEL_VOD = 1; // 点播
|
const MODEL_VOD = 1; // 点播
|
||||||
const MODEL_LIVE = 2; // 直播
|
const MODEL_LIVE = 2; // 直播
|
||||||
const MODEL_READ = 3; // 图文
|
const MODEL_READ = 3; // 专栏
|
||||||
|
const MODEL_OFFLINE = 4; // 面授
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 级别
|
* 级别
|
||||||
@ -31,21 +32,41 @@ class Course extends Model
|
|||||||
*
|
*
|
||||||
* 点播扩展属性
|
* 点播扩展属性
|
||||||
*/
|
*/
|
||||||
protected $_vod_attrs = ['duration' => 0];
|
protected $_vod_attrs = [
|
||||||
|
'duration' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
* 直播扩展属性
|
* 直播扩展属性
|
||||||
*/
|
*/
|
||||||
protected $_live_attrs = ['start_date' => '', 'end_date' => ''];
|
protected $_live_attrs = [
|
||||||
|
'start_date' => '',
|
||||||
|
'end_date' => '',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
* 图文扩展属性
|
* 图文扩展属性
|
||||||
*/
|
*/
|
||||||
protected $_read_attrs = ['duration' => 0, 'word_count' => 0];
|
protected $_read_attrs = [
|
||||||
|
'duration' => 0,
|
||||||
|
'word_count' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* 面授扩展属性
|
||||||
|
*/
|
||||||
|
protected $_offline_attrs = [
|
||||||
|
'start_date' => '',
|
||||||
|
'end_date' => '',
|
||||||
|
'user_limit' => 30,
|
||||||
|
'location' => '',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主键编号
|
* 主键编号
|
||||||
@ -129,14 +150,14 @@ class Course extends Model
|
|||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
public $study_expiry = 0;
|
public $study_expiry = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款期限(天)
|
* 退款期限(天)
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
public $refund_expiry = 0;
|
public $refund_expiry = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户评价
|
* 用户评价
|
||||||
@ -157,14 +178,14 @@ class Course extends Model
|
|||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
public $model = 0;
|
public $model = self::MODEL_VOD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 难度级别
|
* 难度级别
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
public $level = 0;
|
public $level = self::LEVEL_JUNIOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 扩展属性
|
* 扩展属性
|
||||||
@ -285,6 +306,8 @@ class Course extends Model
|
|||||||
$this->attrs = $this->_live_attrs;
|
$this->attrs = $this->_live_attrs;
|
||||||
} elseif ($this->model == self::MODEL_READ) {
|
} elseif ($this->model == self::MODEL_READ) {
|
||||||
$this->attrs = $this->_read_attrs;
|
$this->attrs = $this->_read_attrs;
|
||||||
|
} elseif ($this->model == self::MODEL_OFFLINE) {
|
||||||
|
$this->attrs = $this->_offline_attrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,6 +392,7 @@ class Course extends Model
|
|||||||
self::MODEL_VOD => '点播',
|
self::MODEL_VOD => '点播',
|
||||||
self::MODEL_LIVE => '直播',
|
self::MODEL_LIVE => '直播',
|
||||||
self::MODEL_READ => '专栏',
|
self::MODEL_READ => '专栏',
|
||||||
|
self::MODEL_OFFLINE => '面授',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ class ImGroup extends Model
|
|||||||
public function beforeCreate()
|
public function beforeCreate()
|
||||||
{
|
{
|
||||||
if (empty($this->avatar)) {
|
if (empty($this->avatar)) {
|
||||||
$this->avatar = kg_default_avatar_path();
|
$this->avatar = kg_default_user_avatar_path();
|
||||||
} elseif (Text::startsWith($this->avatar, 'http')) {
|
} elseif (Text::startsWith($this->avatar, 'http')) {
|
||||||
$this->avatar = self::getAvatarPath($this->avatar);
|
$this->avatar = self::getAvatarPath($this->avatar);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ class ImUser extends Model
|
|||||||
public function beforeCreate()
|
public function beforeCreate()
|
||||||
{
|
{
|
||||||
if (empty($this->avatar)) {
|
if (empty($this->avatar)) {
|
||||||
$this->avatar = kg_default_avatar_path();
|
$this->avatar = kg_default_group_avatar_path();
|
||||||
} elseif (Text::startsWith($this->avatar, 'http')) {
|
} elseif (Text::startsWith($this->avatar, 'http')) {
|
||||||
$this->avatar = self::getAvatarPath($this->avatar);
|
$this->avatar = self::getAvatarPath($this->avatar);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ namespace App\Repos;
|
|||||||
use App\Models\Chapter as ChapterModel;
|
use App\Models\Chapter as ChapterModel;
|
||||||
use App\Models\ChapterLike as ChapterLikeModel;
|
use App\Models\ChapterLike as ChapterLikeModel;
|
||||||
use App\Models\ChapterLive as ChapterLiveModel;
|
use App\Models\ChapterLive as ChapterLiveModel;
|
||||||
|
use App\Models\ChapterOffline as ChapterOfflineModel;
|
||||||
use App\Models\ChapterRead as ChapterReadModel;
|
use App\Models\ChapterRead as ChapterReadModel;
|
||||||
use App\Models\ChapterUser as ChapterUserModel;
|
use App\Models\ChapterUser as ChapterUserModel;
|
||||||
use App\Models\ChapterVod as ChapterVodModel;
|
use App\Models\ChapterVod as ChapterVodModel;
|
||||||
@ -121,6 +122,18 @@ class Chapter extends Repository
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $chapterId
|
||||||
|
* @return ChapterOfflineModel|Model|bool
|
||||||
|
*/
|
||||||
|
public function findChapterOffline($chapterId)
|
||||||
|
{
|
||||||
|
return ChapterOfflineModel::findFirst([
|
||||||
|
'conditions' => 'chapter_id = :chapter_id:',
|
||||||
|
'bind' => ['chapter_id' => $chapterId],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function maxChapterPriority($courseId)
|
public function maxChapterPriority($courseId)
|
||||||
{
|
{
|
||||||
return (int)ChapterModel::maximum([
|
return (int)ChapterModel::maximum([
|
||||||
|
@ -52,11 +52,19 @@ class Course extends Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($where['model'])) {
|
if (!empty($where['model'])) {
|
||||||
$builder->andWhere('model = :model:', ['model' => $where['model']]);
|
if (is_array($where['model'])) {
|
||||||
|
$builder->inWhere('model', $where['model']);
|
||||||
|
} else {
|
||||||
|
$builder->andWhere('model = :model:', ['model' => $where['model']]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($where['level'])) {
|
if (!empty($where['level'])) {
|
||||||
$builder->andWhere('level = :level:', ['level' => $where['level']]);
|
if (is_array($where['level'])) {
|
||||||
|
$builder->inWhere('level', $where['model']);
|
||||||
|
} else {
|
||||||
|
$builder->andWhere('level = :level:', ['level' => $where['level']]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($where['free'])) {
|
if (isset($where['free'])) {
|
||||||
|
@ -82,9 +82,7 @@ class CourseStat extends Service
|
|||||||
|
|
||||||
$lessons = $courseRepo->findLessons($courseId);
|
$lessons = $courseRepo->findLessons($courseId);
|
||||||
|
|
||||||
if ($lessons->count() == 0) {
|
if ($lessons->count() == 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$wordCount = 0;
|
$wordCount = 0;
|
||||||
|
|
||||||
@ -92,9 +90,6 @@ class CourseStat extends Service
|
|||||||
|
|
||||||
foreach ($lessons as $lesson) {
|
foreach ($lessons as $lesson) {
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $lesson->attrs;
|
$attrs = $lesson->attrs;
|
||||||
|
|
||||||
if (isset($attrs['word_count'])) {
|
if (isset($attrs['word_count'])) {
|
||||||
@ -106,9 +101,6 @@ class CourseStat extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $course->attrs;
|
$attrs = $course->attrs;
|
||||||
|
|
||||||
$attrs['word_count'] = $wordCount;
|
$attrs['word_count'] = $wordCount;
|
||||||
@ -125,17 +117,12 @@ class CourseStat extends Service
|
|||||||
|
|
||||||
$lessons = $courseRepo->findLessons($course->id);
|
$lessons = $courseRepo->findLessons($course->id);
|
||||||
|
|
||||||
if ($lessons->count() == 0) {
|
if ($lessons->count() == 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scopes = [];
|
$scopes = [];
|
||||||
|
|
||||||
foreach ($lessons as $lesson) {
|
foreach ($lessons as $lesson) {
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $lesson->attrs;
|
$attrs = $lesson->attrs;
|
||||||
|
|
||||||
if (isset($attrs['start_time'])) {
|
if (isset($attrs['start_time'])) {
|
||||||
@ -145,9 +132,6 @@ class CourseStat extends Service
|
|||||||
|
|
||||||
if (!$scopes) return;
|
if (!$scopes) return;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $course->attrs;
|
$attrs = $course->attrs;
|
||||||
|
|
||||||
$attrs['start_date'] = date('Y-m-d', min($scopes));
|
$attrs['start_date'] = date('Y-m-d', min($scopes));
|
||||||
@ -164,17 +148,12 @@ class CourseStat extends Service
|
|||||||
|
|
||||||
$lessons = $courseRepo->findChapters($course->id);
|
$lessons = $courseRepo->findChapters($course->id);
|
||||||
|
|
||||||
if ($lessons->count() == 0) {
|
if ($lessons->count() == 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$duration = 0;
|
$duration = 0;
|
||||||
|
|
||||||
foreach ($lessons as $lesson) {
|
foreach ($lessons as $lesson) {
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $lesson->attrs;
|
$attrs = $lesson->attrs;
|
||||||
|
|
||||||
if (isset($attrs['duration'])) {
|
if (isset($attrs['duration'])) {
|
||||||
@ -182,9 +161,6 @@ class CourseStat extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array $attrs
|
|
||||||
*/
|
|
||||||
$attrs = $course->attrs;
|
$attrs = $course->attrs;
|
||||||
|
|
||||||
$attrs['duration'] = $duration;
|
$attrs['duration'] = $duration;
|
||||||
@ -192,6 +168,11 @@ class CourseStat extends Service
|
|||||||
$course->update(['attrs' => $attrs]);
|
$course->update(['attrs' => $attrs]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateOfflineAttrs($courseId)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function calculateFreeCourseScore(CourseModel $course)
|
protected function calculateFreeCourseScore(CourseModel $course)
|
||||||
{
|
{
|
||||||
$weight = [
|
$weight = [
|
||||||
|
@ -31,9 +31,7 @@ class ChapterList extends Service
|
|||||||
|
|
||||||
$chapters = $cache->get($course->id);
|
$chapters = $cache->get($course->id);
|
||||||
|
|
||||||
if (count($chapters) == 0) {
|
if (count($chapters) == 0) return [];
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user->id > 0 && $this->courseUser) {
|
if ($user->id > 0 && $this->courseUser) {
|
||||||
$mapping = $this->getLearningMapping($course->id, $user->id, $this->courseUser->plan_id);
|
$mapping = $this->getLearningMapping($course->id, $user->id, $this->courseUser->plan_id);
|
||||||
@ -67,9 +65,7 @@ class ChapterList extends Service
|
|||||||
|
|
||||||
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $planId);
|
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $planId);
|
||||||
|
|
||||||
if ($userLearnings->count() == 0) {
|
if ($userLearnings->count() == 0) return [];
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$mapping = [];
|
$mapping = [];
|
||||||
|
|
||||||
|
@ -135,6 +135,7 @@ class OrderConfirm extends Service
|
|||||||
'cover' => $course->cover,
|
'cover' => $course->cover,
|
||||||
'model' => $course->model,
|
'model' => $course->model,
|
||||||
'level' => $course->level,
|
'level' => $course->level,
|
||||||
|
'attrs' => $course->attrs,
|
||||||
'user_count' => $course->user_count,
|
'user_count' => $course->user_count,
|
||||||
'lesson_count' => $course->lesson_count,
|
'lesson_count' => $course->lesson_count,
|
||||||
'study_expiry' => $course->study_expiry,
|
'study_expiry' => $course->study_expiry,
|
||||||
|
@ -246,6 +246,8 @@ class OrderCreate extends Service
|
|||||||
'id' => $course->id,
|
'id' => $course->id,
|
||||||
'title' => $course->title,
|
'title' => $course->title,
|
||||||
'cover' => $course->cover,
|
'cover' => $course->cover,
|
||||||
|
'model' => $course->model,
|
||||||
|
'attrs' => $course->attrs,
|
||||||
'market_price' => $course->market_price,
|
'market_price' => $course->market_price,
|
||||||
'vip_price' => $course->vip_price,
|
'vip_price' => $course->vip_price,
|
||||||
'study_expiry' => $course->study_expiry,
|
'study_expiry' => $course->study_expiry,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Services\Logic\Order;
|
namespace App\Services\Logic\Order;
|
||||||
|
|
||||||
|
use App\Models\Course as CourseModel;
|
||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
use App\Repos\Order as OrderRepo;
|
use App\Repos\Order as OrderRepo;
|
||||||
use App\Services\Logic\Service;
|
use App\Services\Logic\Service;
|
||||||
@ -25,7 +26,10 @@ class OrderInfo extends Service
|
|||||||
|
|
||||||
$statusHistory = $this->handleStatusHistory($order->id);
|
$statusHistory = $this->handleStatusHistory($order->id);
|
||||||
|
|
||||||
|
$me = $this->handleMeInfo($order);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'me' => $me,
|
||||||
'sn' => $order->sn,
|
'sn' => $order->sn,
|
||||||
'subject' => $order->subject,
|
'subject' => $order->subject,
|
||||||
'amount' => $order->amount,
|
'amount' => $order->amount,
|
||||||
@ -48,9 +52,7 @@ class OrderInfo extends Service
|
|||||||
|
|
||||||
$records = $orderRepo->findStatusHistory($orderId);
|
$records = $orderRepo->findStatusHistory($orderId);
|
||||||
|
|
||||||
if ($records->count() == 0) {
|
if ($records->count() == 0) return [];
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
@ -64,11 +66,37 @@ class OrderInfo extends Service
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleMeInfo(OrderModel $order)
|
||||||
|
{
|
||||||
|
$result = [
|
||||||
|
'allow_pay' => 0,
|
||||||
|
'allow_refund' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($order->status == OrderModel::STATUS_PENDING) {
|
||||||
|
$result['allow_pay'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($order->status == OrderModel::STATUS_FINISHED) {
|
||||||
|
/**
|
||||||
|
* 只允许线上课程退款,因为线下课程无法进行退款计算
|
||||||
|
*/
|
||||||
|
if ($order->item_type == OrderModel::ITEM_COURSE) {
|
||||||
|
$result['allow_refund'] = 1;
|
||||||
|
$course = $order->item_info['course'];
|
||||||
|
if (isset($course['model']) && $course['model'] == CourseModel::MODEL_OFFLINE) {
|
||||||
|
$result['allow_refund'] = 0;
|
||||||
|
}
|
||||||
|
} elseif ($order->item_type == OrderModel::ITEM_PACKAGE) {
|
||||||
|
$result['allow_refund'] = $order->status == OrderModel::STATUS_FINISHED ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleItemInfo(OrderModel $order)
|
protected function handleItemInfo(OrderModel $order)
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var array $itemInfo
|
|
||||||
*/
|
|
||||||
$itemInfo = $order->item_info;
|
$itemInfo = $order->item_info;
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
|
@ -200,6 +200,10 @@ class Chapter extends Validator
|
|||||||
if ($attrs['word_count'] == 0) {
|
if ($attrs['word_count'] == 0) {
|
||||||
throw new BadRequestException('chapter.read_not_ready');
|
throw new BadRequestException('chapter.read_not_ready');
|
||||||
}
|
}
|
||||||
|
} elseif ($chapter->model == CourseModel::MODEL_READ) {
|
||||||
|
if ($attrs['start_time'] == 0) {
|
||||||
|
throw new BadRequestException('chapter.offline_time_empty');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,14 +28,6 @@ class ChapterLive extends Validator
|
|||||||
|
|
||||||
public function checkTimeRange($startTime, $endTime)
|
public function checkTimeRange($startTime, $endTime)
|
||||||
{
|
{
|
||||||
if ($startTime < time()) {
|
|
||||||
throw new BadRequestException('chapter_live.start_lt_now');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($startTime < time()) {
|
|
||||||
throw new BadRequestException('chapter_live.end_lt_now');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($startTime >= $endTime) {
|
if ($startTime >= $endTime) {
|
||||||
throw new BadRequestException('chapter_live.start_gt_end');
|
throw new BadRequestException('chapter_live.start_gt_end');
|
||||||
}
|
}
|
||||||
|
36
app/Validators/ChapterOffline.php
Normal file
36
app/Validators/ChapterOffline.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Validators;
|
||||||
|
|
||||||
|
use App\Exceptions\BadRequest as BadRequestException;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
|
|
||||||
|
class ChapterOffline extends Validator
|
||||||
|
{
|
||||||
|
|
||||||
|
public function checkStartTime($startTime)
|
||||||
|
{
|
||||||
|
if (!CommonValidator::date($startTime, 'Y-m-d H:i:s')) {
|
||||||
|
throw new BadRequestException('chapter_offline.invalid_start_time');
|
||||||
|
}
|
||||||
|
|
||||||
|
return strtotime($startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkEndTime($endTime)
|
||||||
|
{
|
||||||
|
if (!CommonValidator::date($endTime, 'Y-m-d H:i:s')) {
|
||||||
|
throw new BadRequestException('chapter_offline.invalid_end_time');
|
||||||
|
}
|
||||||
|
|
||||||
|
return strtotime($endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkTimeRange($startTime, $endTime)
|
||||||
|
{
|
||||||
|
if ($startTime >= $endTime) {
|
||||||
|
throw new BadRequestException('chapter_offline.start_gt_end');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -165,7 +165,7 @@ class Course extends Validator
|
|||||||
{
|
{
|
||||||
$value = $this->filter->sanitize($price, ['trim', 'float']);
|
$value = $this->filter->sanitize($price, ['trim', 'float']);
|
||||||
|
|
||||||
if ($value < 0 || $value > 10000) {
|
if ($value < 0 || $value > 999999) {
|
||||||
throw new BadRequestException('course.invalid_origin_price');
|
throw new BadRequestException('course.invalid_origin_price');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ class Course extends Validator
|
|||||||
{
|
{
|
||||||
$value = $this->filter->sanitize($price, ['trim', 'float']);
|
$value = $this->filter->sanitize($price, ['trim', 'float']);
|
||||||
|
|
||||||
if ($value < 0 || $value > 10000) {
|
if ($value < 0 || $value > 999999) {
|
||||||
throw new BadRequestException('course.invalid_market_price');
|
throw new BadRequestException('course.invalid_market_price');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ class Course extends Validator
|
|||||||
{
|
{
|
||||||
$value = $this->filter->sanitize($price, ['trim', 'float']);
|
$value = $this->filter->sanitize($price, ['trim', 'float']);
|
||||||
|
|
||||||
if ($value < 0 || $value > 10000) {
|
if ($value < 0 || $value > 999999) {
|
||||||
throw new BadRequestException('course.invalid_vip_price');
|
throw new BadRequestException('course.invalid_vip_price');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +236,8 @@ class Course extends Validator
|
|||||||
|
|
||||||
public function checkPublishAbility(CourseModel $course)
|
public function checkPublishAbility(CourseModel $course)
|
||||||
{
|
{
|
||||||
|
if ($course->model == CourseModel::MODEL_OFFLINE) return true;
|
||||||
|
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
$chapters = $courseRepo->findChapters($course->id);
|
$chapters = $courseRepo->findChapters($course->id);
|
||||||
|
60
app/Validators/CourseOffline.php
Normal file
60
app/Validators/CourseOffline.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Validators;
|
||||||
|
|
||||||
|
use App\Exceptions\BadRequest as BadRequestException;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
|
|
||||||
|
class CourseOffline extends Validator
|
||||||
|
{
|
||||||
|
|
||||||
|
public function checkStartDate($startDate)
|
||||||
|
{
|
||||||
|
if (!CommonValidator::date($startDate)) {
|
||||||
|
throw new BadRequestException('course_offline.invalid_start_date');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkEndDate($endDate)
|
||||||
|
{
|
||||||
|
if (!CommonValidator::date($endDate)) {
|
||||||
|
throw new BadRequestException('course_offline.invalid_end_date');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkDateRange($startDate, $endDate)
|
||||||
|
{
|
||||||
|
if (strtotime($startDate) >= strtotime($endDate)) {
|
||||||
|
throw new BadRequestException('course_offline.start_gt_end');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkUserLimit($limit)
|
||||||
|
{
|
||||||
|
$value = $this->filter->sanitize($limit, ['trim', 'int']);
|
||||||
|
|
||||||
|
if ($value < 1 || $value > 999) {
|
||||||
|
throw new BadRequestException('course_offline.invalid_user_limit');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkLocation($location)
|
||||||
|
{
|
||||||
|
$value = $this->filter->sanitize($location, ['trim', 'string']);
|
||||||
|
|
||||||
|
$length = kg_strlen($value);
|
||||||
|
|
||||||
|
if ($length < 1 || $length > 50) {
|
||||||
|
throw new BadRequestException('course_offline.invalid_location');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -100,4 +100,13 @@ class ImGroupUser extends Validator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkIfAllowDelete($groupId, $userId)
|
||||||
|
{
|
||||||
|
$group = $this->checkGroup($groupId);
|
||||||
|
|
||||||
|
if ($group->owner_id == $userId) {
|
||||||
|
throw new BadRequestException('im_group_user.delete_owner_not_allowed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,9 @@ $error['course.details_too_long'] = '详情太长(多于5000个字符)';
|
|||||||
$error['course.invalid_model'] = '无效的模型类别';
|
$error['course.invalid_model'] = '无效的模型类别';
|
||||||
$error['course.invalid_level'] = '无效的难度级别';
|
$error['course.invalid_level'] = '无效的难度级别';
|
||||||
$error['course.invalid_cover'] = '无效的封面';
|
$error['course.invalid_cover'] = '无效的封面';
|
||||||
$error['course.invalid_origin_price'] = '无效的原始价格(范围:0-10000)';
|
$error['course.invalid_origin_price'] = '无效的原始价格(范围:0-999999)';
|
||||||
$error['course.invalid_market_price'] = '无效的优惠价格(范围:0-10000)';
|
$error['course.invalid_market_price'] = '无效的优惠价格(范围:0-999999)';
|
||||||
$error['course.invalid_vip_price'] = '无效的会员价格(范围:0-10000)';
|
$error['course.invalid_vip_price'] = '无效的会员价格(范围:0-999999)';
|
||||||
$error['course.invalid_study_expiry'] = '无效的学习期限';
|
$error['course.invalid_study_expiry'] = '无效的学习期限';
|
||||||
$error['course.invalid_refund_expiry'] = '无效的退款期限';
|
$error['course.invalid_refund_expiry'] = '无效的退款期限';
|
||||||
$error['course.invalid_feature_status'] = '无效的推荐状态';
|
$error['course.invalid_feature_status'] = '无效的推荐状态';
|
||||||
@ -119,6 +119,15 @@ $error['course.invalid_publish_status'] = '无效的发布状态';
|
|||||||
$error['course.pub_chapter_not_found'] = '尚未发现已发布的课时';
|
$error['course.pub_chapter_not_found'] = '尚未发现已发布的课时';
|
||||||
$error['course.pub_chapter_not_enough'] = '已发布的课时太少(小于30%)';
|
$error['course.pub_chapter_not_enough'] = '已发布的课时太少(小于30%)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 面授课程相关
|
||||||
|
*/
|
||||||
|
$error['course_offline.invalid_start_date'] = '无效的开始日期';
|
||||||
|
$error['course_offline.invalid_end_date'] = '无效的结束日期';
|
||||||
|
$error['course_offline.start_gt_end'] = '开始日期大于结束日期';
|
||||||
|
$error['course_offline.invalid_user_limit'] = '无效的用户限额(范围:1-999)';
|
||||||
|
$error['course_offline.invalid_location'] = '无效的上课地点(范围10-50字符)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 话题相关
|
* 话题相关
|
||||||
*/
|
*/
|
||||||
@ -181,6 +190,7 @@ $error['chapter.vod_not_ready'] = '点播资源尚未就绪';
|
|||||||
$error['chapter.read_not_ready'] = '文章内容尚未就绪';
|
$error['chapter.read_not_ready'] = '文章内容尚未就绪';
|
||||||
$error['chapter.live_not_start'] = '直播尚未开始';
|
$error['chapter.live_not_start'] = '直播尚未开始';
|
||||||
$error['chapter.live_time_empty'] = '直播时间尚未设置';
|
$error['chapter.live_time_empty'] = '直播时间尚未设置';
|
||||||
|
$error['chapter.offline_time_empty'] = '面授时间尚未设置';
|
||||||
$error['chapter.child_existed'] = '不允许相关操作(存在子章节)';
|
$error['chapter.child_existed'] = '不允许相关操作(存在子章节)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,6 +215,13 @@ $error['chapter_read.not_found'] = '文章不存在';
|
|||||||
$error['chapter_read.content_too_short'] = '文章内容太短(少于10个字符)';
|
$error['chapter_read.content_too_short'] = '文章内容太短(少于10个字符)';
|
||||||
$error['chapter_read.content_too_long'] = '文章内容太长(多于60000个字符)';
|
$error['chapter_read.content_too_long'] = '文章内容太长(多于60000个字符)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 面授相关
|
||||||
|
*/
|
||||||
|
$error['chapter_offline.invalid_start_time'] = '无效的开始时间';
|
||||||
|
$error['chapter_offline.invalid_end_time'] = '无效的结束时间';
|
||||||
|
$error['chapter_offline.start_gt_end'] = '开始时间大于结束时间';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 评价相关
|
* 评价相关
|
||||||
*/
|
*/
|
||||||
@ -361,6 +378,7 @@ $error['im_group_user.not_found'] = '群组关系不存在';
|
|||||||
$error['im_group_user.remark_too_long'] = '验证信息太长(超过30字符)';
|
$error['im_group_user.remark_too_long'] = '验证信息太长(超过30字符)';
|
||||||
$error['im_group_user.has_joined'] = '已经加入过群组';
|
$error['im_group_user.has_joined'] = '已经加入过群组';
|
||||||
$error['im_group_user.join_not_allowed'] = '当前不允许加入群组';
|
$error['im_group_user.join_not_allowed'] = '当前不允许加入群组';
|
||||||
|
$error['im_group_user.delete_owner_not_allowed'] = '当前不允许删除群主';
|
||||||
|
|
||||||
$error['im_friend_user.not_found'] = '好友关系不存在';
|
$error['im_friend_user.not_found'] = '好友关系不存在';
|
||||||
$error['im_friend_user.remark_too_long'] = '验证信息太长(超过30字符)';
|
$error['im_friend_user.remark_too_long'] = '验证信息太长(超过30字符)';
|
||||||
|
86
db/migrations/20210324064239.php
Normal file
86
db/migrations/20210324064239.php
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class V20210324064239 extends AbstractMigration
|
||||||
|
{
|
||||||
|
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$orders = $this->findOrders();
|
||||||
|
|
||||||
|
if ($orders->count() == 0) return;
|
||||||
|
|
||||||
|
foreach ($orders as $order) {
|
||||||
|
if ($order['item_type'] == 1) {
|
||||||
|
$this->handleCourseOrder($order);
|
||||||
|
} elseif ($order['item_type'] == 2) {
|
||||||
|
$this->handlePackageOrder($order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程订单补充信息
|
||||||
|
*
|
||||||
|
* @param array $order
|
||||||
|
*/
|
||||||
|
protected function handleCourseOrder($order)
|
||||||
|
{
|
||||||
|
$itemInfo = json_decode($order['item_info'], true);
|
||||||
|
|
||||||
|
$course = $this->findCourseById($itemInfo['course']['id']);
|
||||||
|
|
||||||
|
$itemInfo['course']['model'] = $course['model'];
|
||||||
|
$itemInfo['course']['attrs'] = json_decode($course['attrs'], JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
$this->updateOrderItemInfo($order['id'], $itemInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 套餐订单补充信息
|
||||||
|
*
|
||||||
|
* @param array $order
|
||||||
|
*/
|
||||||
|
protected function handlePackageOrder($order)
|
||||||
|
{
|
||||||
|
$itemInfo = json_decode($order['item_info'], true);
|
||||||
|
|
||||||
|
foreach ($itemInfo['courses'] as &$pkgCourse) {
|
||||||
|
$course = $this->findCourseById($pkgCourse['id']);
|
||||||
|
$pkgCourse['model'] = $course['model'];
|
||||||
|
$pkgCourse['attrs'] = json_decode($course['attrs'], JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->updateOrderItemInfo($order['id'], $itemInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateOrderItemInfo($id, $itemInfo)
|
||||||
|
{
|
||||||
|
$itemInfo = json_encode($itemInfo, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
$this->getQueryBuilder()
|
||||||
|
->update('kg_order')
|
||||||
|
->set('item_info', $itemInfo)
|
||||||
|
->where(['id' => $id])
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findCourseById($id)
|
||||||
|
{
|
||||||
|
return $this->getQueryBuilder()
|
||||||
|
->select('*')
|
||||||
|
->from('kg_course')
|
||||||
|
->where(['id' => $id])
|
||||||
|
->execute()->fetch('assoc');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findOrders()
|
||||||
|
{
|
||||||
|
return $this->getQueryBuilder()
|
||||||
|
->select('*')
|
||||||
|
->from('kg_order')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -54,6 +54,12 @@
|
|||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-sm {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -203,6 +209,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kg-table span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.kg-item-elip {
|
.kg-item-elip {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layer .layui-table {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix {
|
.clearfix {
|
||||||
zoom: 1
|
zoom: 1
|
||||||
}
|
}
|
||||||
@ -30,6 +26,10 @@
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mt0 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.mb0 {
|
.mb0 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
@ -54,6 +54,12 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-sm {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.layui-table .meta span {
|
.layui-table .meta span {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
@ -402,7 +408,7 @@
|
|||||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-card .model {
|
.course-card .model, .course-card .type {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
@ -511,7 +517,7 @@
|
|||||||
|
|
||||||
.course-meta .info {
|
.course-meta .info {
|
||||||
float: left;
|
float: left;
|
||||||
width: 400px;
|
width: 560px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-meta .rating {
|
.course-meta .rating {
|
||||||
@ -1455,7 +1461,17 @@
|
|||||||
|
|
||||||
.group-user-list .user-card {
|
.group-user-list .user-card {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
height: 220px;
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-user-list .avatar {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-user-list .avatar img {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-list {
|
.group-list {
|
||||||
@ -1684,6 +1700,10 @@
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.order-table em {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.order-table .price {
|
.order-table .price {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ layui.use(['jquery', 'layer', 'helper'], function () {
|
|||||||
type: 2,
|
type: 2,
|
||||||
title: '套餐课程',
|
title: '套餐课程',
|
||||||
content: url,
|
content: url,
|
||||||
area: '800px'
|
area: ['800px', '280px']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,8 +119,8 @@ layui.use(['jquery', 'layer', 'helper'], function () {
|
|||||||
title: '成员管理',
|
title: '成员管理',
|
||||||
maxmin: true,
|
maxmin: true,
|
||||||
resize: false,
|
resize: false,
|
||||||
content: [url, 'no'],
|
content: [url],
|
||||||
area: ['1000px', '510px']
|
area: ['1000px', '600px']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user