1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-08-06 06:21:41 +08:00

增加打赏

This commit is contained in:
xiaochong0302 2020-04-15 19:35:02 +08:00
parent bacdcec7fc
commit 92d9395065
15 changed files with 297 additions and 110 deletions

View File

@ -9,7 +9,7 @@
{{ icon_link("favicon.ico") }}
{{ css_link('lib/layui/css/layui.css') }}
{{ css_link('lib/layui/extends/dropdown.css') }}
{{ css_link('admin/css/style.css') }}
{{ css_link('admin/css/common.css') }}
{{ js_include('lib/layui/layui.js') }}
{{ js_include('admin/js/common.js') }}
</head>

View File

@ -5,8 +5,9 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>管理后台</title>
{{ icon_link('favicon.ico') }}
{{ css_link('lib/layui/css/layui.css') }}
{{ css_link('admin/css/style.css') }}
{{ css_link('admin/css/common.css') }}
{{ js_include('lib/layui/layui.js') }}
{{ js_include('admin/js/index.js') }}
</head>
@ -62,15 +63,14 @@
</div>
<div class="layui-body">
<iframe name="content" width="100%" height="100%" frameborder="0" src="{{ url({'for':'admin.main'}) }}"></iframe>
<iframe name="content" style="width:100%;height:100%;border:0;" src="{{ url({'for':'admin.main'}) }}"></iframe>
</div>
<div class="layui-footer">
© 2018 <a href="http://koogua.com"><b>koogua.com</b></a> all rights reserved
© 2020 <a href="http://koogua.com"><b>koogua.com</b></a> all rights reserved
</div>
</div>
</body>
</html>

View File

@ -21,6 +21,13 @@
<p>商品名称:{{ order.subject }}</p>
<p>商品价格:¥{{ order.amount }}</p>
</div>
{% elseif order.item_type == 'reward' %}
{% set course = order.item_info['course'] %}
{% set reward = order.item_info['reward'] %}
<div class="kg-order-item">
<p>课程名称:{{ course['title'] }}</p>
<p>打赏金额:¥{{ reward['price'] }}</p>
</div>
{% elseif order.item_type == 'test' %}
<div class="kg-order-item">
<p>商品名称:{{ order.subject }}</p>
@ -35,7 +42,9 @@
{% elseif value == 'package' %}
<span class="layui-badge layui-bg-blue">套餐</span>
{% elseif value == 'vip' %}
<span class="layui-badge layui-bg-red">会员</span>
<span class="layui-badge layui-bg-orange">会员</span>
{% elseif value == 'reward' %}
<span class="layui-badge layui-bg-red">打赏</span>
{% elseif value == 'test' %}
<span class="layui-badge layui-bg-black">测试</span>
{% endif %}

View File

@ -8,7 +8,7 @@
<title>{{ seo.getTitle() }}</title>
{{ icon_link("favicon.ico") }}
{{ css_link("lib/layui/css/layui.css") }}
{{ css_link("web/css/style.css") }}
{{ css_link("web/css/common.css") }}
{% block link_css %}{% endblock %}
{% block inline_css %}{% endblock %}
</head>

84
app/Models/Reward.php Normal file
View File

@ -0,0 +1,84 @@
<?php
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class Reward extends Model
{
/**
* 主键编号
*
* @var int
*/
public $id;
/**
* 标题
*
* @var string
*/
public $title;
/**
* 价格
*
* @var float
*/
public $price;
/**
* 删除标识
*
* @var int
*/
public $deleted;
/**
* 创建时间
*
* @var int
*/
public $create_time;
/**
* 更新时间
*
* @var int
*/
public $update_time;
public function getSource()
{
return 'kg_reward';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
public function afterFetch()
{
$this->price = (float)$this->price;
}
}

52
app/Repos/Reward.php Normal file
View File

@ -0,0 +1,52 @@
<?php
namespace App\Repos;
use App\Models\Reward as RewardModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class Reward extends Repository
{
/**
* @param array $where
* @return ResultsetInterface|Resultset|RewardModel[]
*/
public function findAll($where = [])
{
$query = RewardModel::query();
$query->where('1 = 1');
if (isset($where['deleted'])) {
$query->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
return $query->execute();
}
/**
* @param int $id
* @return RewardModel|Model|bool
*/
public function findById($id)
{
return RewardModel::findFirst($id);
}
/**
* @param array $ids
* @param array|string $columns
* @return ResultsetInterface|Resultset|RewardModel[]
*/
public function findByIds($ids, $columns = '*')
{
return RewardModel::query()
->columns($columns)
->inWhere('id', $ids)
->execute();
}
}

View File

@ -1,8 +1,10 @@
<?php
namespace App\Services\Frontend;
namespace App\Services\Frontend\Order;
use App\Models\Order as OrderModel;
use App\Services\Frontend\OrderTrait;
use App\Services\Frontend\Service;
use App\Validators\Order as OrderValidator;
class OrderCancel extends Service

View File

@ -1,12 +1,14 @@
<?php
namespace App\Services\Frontend;
namespace App\Services\Frontend\Order;
use App\Models\Course as CourseModel;
use App\Models\Order as OrderModel;
use App\Repos\Course as CourseRepo;
use App\Models\Package as PackageModel;
use App\Models\Reward as RewardModel;
use App\Models\Vip as VipModel;
use App\Repos\Package as PackageRepo;
use App\Repos\Vip as VipRepo;
use App\Services\Frontend\Service;
use App\Validators\Order as OrderValidator;
class OrderConfirm extends Service
@ -20,7 +22,7 @@ class OrderConfirm extends Service
$validator = new OrderValidator();
$validator->checkItem($query['item_id'], $query['item_type']);
$validator->checkItemType($query['item_type']);
$result = [];
@ -29,24 +31,41 @@ class OrderConfirm extends Service
if ($query['item_type'] == OrderModel::ITEM_COURSE) {
$course = $this->getCourseInfo($query['item_id']);
$course = $validator->checkCourseItem($query['item_id']);
$courseInfo = $this->handleCourseInfo($course);
$result['item_info']['course'] = $course;
$result['amount'] = $user->vip ? $course['vip_price'] : $course['market_price'];
$result['item_info']['course'] = $courseInfo;
$result['amount'] = $user->vip ? $course->vip_price : $course->market_price;
} elseif ($query['item_type'] == OrderModel::ITEM_PACKAGE) {
$package = $this->getPackageInfo($query['item_id']);
$package = $validator->checkPackageItem($query['item_id']);
$packageInfo = $this->handlePackageInfo($package);
$result['item_info']['package'] = $package;
$result['amount'] = $user->vip ? $package['vip_price'] : $package['market_price'];
$result['item_info']['package'] = $packageInfo;
$result['amount'] = $user->vip ? $package->vip_price : $package->market_price;
} elseif ($query['item_type'] == OrderModel::ITEM_VIP) {
$vip = $this->getVipInfo($query['item_id']);
$vip = $validator->checkVipItem($query['item_id']);
$vipInfo = $this->handleVipInfo($vip);
$result['item_info']['vip'] = $vip;
$result['amount'] = $vip['price'];
$result['item_info']['vip'] = $vipInfo;
$result['amount'] = $vip->price;
} elseif ($query['item_type'] == OrderModel::ITEM_REWARD) {
list($courseId, $rewardId) = explode('-', $query['item_id']);
$course = $validator->checkCourseItem($courseId);
$reward = $validator->checkRewardItem($rewardId);
$courseInfo = $this->handleCourseInfo($course);
$rewardInfo = $this->handleRewardInfo($reward);
$result['item_info']['course'] = $courseInfo;
$result['item_info']['reward'] = $rewardInfo;
$result['amount'] = $reward->price;
}
$validator->checkAmount($result['amount']);
@ -54,15 +73,11 @@ class OrderConfirm extends Service
return $result;
}
protected function getCourseInfo($id)
protected function handleCourseInfo(CourseModel $course)
{
$courseRepo = new CourseRepo();
$course = $courseRepo->findById($id);
$course->cover = kg_ci_img_url($course->cover);
$result = [
return [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
@ -74,16 +89,10 @@ class OrderConfirm extends Service
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
];
return $result;
}
protected function getPackageInfo($id)
protected function handlePackageInfo(PackageModel $package)
{
$packageRepo = new PackageRepo();
$package = $packageRepo->findById($id);
$result = [
'id' => $package->id,
'title' => $package->title,
@ -92,10 +101,9 @@ class OrderConfirm extends Service
'vip_price' => $package->vip_price,
];
/**
* @var CourseModel[] $courses
*/
$courses = $packageRepo->findCourses($id);
$packageRepo = new PackageRepo();
$courses = $packageRepo->findCourses($package->id);
$baseUrl = kg_ci_base_url();
@ -120,13 +128,23 @@ class OrderConfirm extends Service
return $result;
}
protected function getVipInfo($id)
protected function handleVipInfo(VipModel $vip)
{
$vipRepo = new VipRepo();
return [
'id' => $vip->id,
'title' => $vip->title,
'expiry' => $vip->expiry,
'price' => $vip->price,
];
}
$result = $vipRepo->findById($id);
return $result;
protected function handleRewardInfo(RewardModel $reward)
{
return [
'id' => $reward->id,
'title' => $reward->title,
'price' => $reward->price,
];
}
}

View File

@ -1,14 +1,16 @@
<?php
namespace App\Services\Frontend;
namespace App\Services\Frontend\Order;
use App\Models\Course as CourseModel;
use App\Models\Order as OrderModel;
use App\Models\Package as PackageModel;
use App\Models\Reward as RewardModel;
use App\Models\User as UserModel;
use App\Models\Vip as VipModel;
use App\Repos\Order as OrderRepo;
use App\Repos\Package as PackageRepo;
use App\Services\Frontend\Service;
use App\Validators\Order as OrderValidator;
use App\Validators\UserDailyLimit as UserDailyLimitValidator;
@ -40,10 +42,8 @@ class OrderCreate extends Service
* 存在新鲜的未支付订单直接返回(减少订单记录)
*/
if ($order) {
$caseA = $order->status == OrderModel::STATUS_PENDING;
$caseB = time() - $order->create_time < 6 * 3600;
if ($caseA && $caseB) {
return $order;
}
@ -51,7 +51,7 @@ class OrderCreate extends Service
if ($post['item_type'] == OrderModel::ITEM_COURSE) {
$course = $validator->checkItemCourse($post['item_id']);
$course = $validator->checkCourseItem($post['item_id']);
$validator->checkIfBoughtCourse($user->id, $course->id);
@ -59,7 +59,7 @@ class OrderCreate extends Service
} elseif ($post['item_type'] == OrderModel::ITEM_PACKAGE) {
$package = $validator->checkItemPackage($post['item_id']);
$package = $validator->checkPackageItem($post['item_id']);
$validator->checkIfBoughtPackage($user->id, $package->id);
@ -67,9 +67,18 @@ class OrderCreate extends Service
} elseif ($post['item_type'] == OrderModel::ITEM_VIP) {
$vip = $validator->checkItemVip($post['item_id']);
$vip = $validator->checkVipItem($post['item_id']);
$order = $this->createVipOrder($vip, $user);
} elseif ($post['item_type'] == OrderModel::ITEM_REWARD) {
list($courseId, $rewardId) = explode('-', $post['item_id']);
$course = $validator->checkCourseItem($courseId);
$reward = $validator->checkRewardItem($rewardId);
$order = $this->createRewardOrder($course, $reward, $user);
}
$this->incrUserDailyOrderCount($user);
@ -77,29 +86,11 @@ class OrderCreate extends Service
return $order;
}
/**
* @param CourseModel $course
* @param UserModel $user
* @return OrderModel $order
*/
public function createCourseOrder(CourseModel $course, UserModel $user)
{
$studyExpiryTime = strtotime("+{$course->study_expiry} months");
$refundExpiryTime = strtotime("+{$course->refund_expiry} days");
$itemInfo = [];
$itemInfo = [
'course' => [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
'study_expiry' => $course->study_expiry,
'refund_expiry' => $course->refund_expiry,
'study_expiry_time' => $studyExpiryTime,
'refund_expiry_time' => $refundExpiryTime,
]
];
$itemInfo['course'] = $this->handleCourseInfo($course);
$amount = $user->vip ? $course->vip_price : $course->market_price;
@ -117,18 +108,10 @@ class OrderCreate extends Service
return $order;
}
/**
* @param PackageModel $package
* @param UserModel $user
* @return OrderModel $order
*/
public function createPackageOrder(PackageModel $package, UserModel $user)
{
$packageRepo = new PackageRepo();
/**
* @var CourseModel[] $courses
*/
$courses = $packageRepo->findCourses($package->id);
$itemInfo = [];
@ -141,21 +124,7 @@ class OrderCreate extends Service
];
foreach ($courses as $course) {
$studyExpiryTime = strtotime("+{$course->study_expiry} months");
$refundExpiryTime = strtotime("+{$course->refund_expiry} days");
$itemInfo['courses'][] = [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
'study_expiry' => $course->study_expiry,
'refund_expiry' => $course->refund_expiry,
'study_expiry_time' => $studyExpiryTime,
'refund_expiry_time' => $refundExpiryTime,
];
$itemInfo['courses'][] = $this->handleCourseInfo($course);
}
$amount = $user->vip ? $package->vip_price : $package->market_price;
@ -174,11 +143,6 @@ class OrderCreate extends Service
return $order;
}
/**
* @param VipModel $vip
* @param UserModel $user
* @return OrderModel
*/
public function createVipOrder(VipModel $vip, UserModel $user)
{
$baseTime = $user->vip_expiry_time > time() ? $user->vip_expiry_time : time();
@ -208,9 +172,49 @@ class OrderCreate extends Service
return $order;
}
/**
* @param UserModel $user
*/
public function createRewardOrder(CourseModel $course, RewardModel $reward, UserModel $user)
{
$itemInfo = [
'course' => $this->handleCourseInfo($course),
'reward' => [
'id' => $reward->id,
'title' => $reward->title,
'price' => $reward->price,
]
];
$order = new OrderModel();
$order->user_id = $user->id;
$order->item_id = $course->id;
$order->item_type = OrderModel::ITEM_REWARD;
$order->item_info = $itemInfo;
$order->amount = $reward->price;
$order->subject = "打赏 - {$course->title}";
$order->create();
return $order;
}
protected function handleCourseInfo(CourseModel $course)
{
$studyExpiryTime = strtotime("+{$course->study_expiry} months");
$refundExpiryTime = strtotime("+{$course->refund_expiry} days");
return [
'id' => $course->id,
'title' => $course->title,
'cover' => $course->cover,
'market_price' => $course->market_price,
'vip_price' => $course->vip_price,
'study_expiry' => $course->study_expiry,
'refund_expiry' => $course->refund_expiry,
'study_expiry_time' => $studyExpiryTime,
'refund_expiry_time' => $refundExpiryTime,
];
}
protected function incrUserDailyOrderCount(UserModel $user)
{
$this->eventsManager->fire('userDailyCounter:incrOrderCount', $this, $user);

View File

@ -1,8 +1,9 @@
<?php
namespace App\Services\Frontend;
namespace App\Services\Frontend\Order;
use App\Models\Order as OrderModel;
use App\Services\Frontend\Service;
use App\Validators\Order as OrderValidator;
class OrderInfo extends Service

View File

@ -1,8 +1,10 @@
<?php
namespace App\Services\Frontend;
namespace App\Services\Frontend\Order;
use App\Models\Trade as TradeModel;
use App\Services\Frontend\OrderTrait;
use App\Services\Frontend\Service;
use App\Services\Payment\Alipay as AlipayService;
use App\Services\Payment\Wxpay as WxPayService;
use App\Validators\Trade as TradeValidator;

View File

@ -7,6 +7,7 @@ use App\Models\Order as OrderModel;
use App\Repos\Course as CourseRepo;
use App\Repos\Order as OrderRepo;
use App\Repos\Package as PackageRepo;
use App\Repos\Reward as RewardRepo;
use App\Repos\Vip as VipRepo;
class Order extends Validator
@ -49,7 +50,7 @@ class Order extends Validator
return $itemType;
}
public function checkItemCourse($itemId)
public function checkCourseItem($itemId)
{
$courseRepo = new CourseRepo();
@ -62,7 +63,7 @@ class Order extends Validator
return $item;
}
public function checkItemPackage($itemId)
public function checkPackageItem($itemId)
{
$packageRepo = new PackageRepo();
@ -75,7 +76,7 @@ class Order extends Validator
return $item;
}
public function checkItemVip($itemId)
public function checkVipItem($itemId)
{
$vipRepo = new VipRepo();
@ -88,6 +89,19 @@ class Order extends Validator
return $item;
}
public function checkRewardItem($itemId)
{
$rewardRepo = new RewardRepo();
$item = $rewardRepo->findById($itemId);
if (!$item) {
throw new BadRequestException('order.item_not_found');
}
return $item;
}
public function checkAmount($amount)
{
$value = $this->filter->sanitize($amount, ['trim', 'float']);

View File

@ -21,27 +21,28 @@ layui.use(['jquery', 'form', 'element', 'layer', 'dropdown'], function () {
form.on('submit(go)', function (data) {
var submit = $(this);
submit.attr('disabled', true).text('提交中...');
submit.attr('disabled', true).addClass('layui-btn-disabled');
$.ajax({
type: 'POST',
url: data.form.action,
data: data.field,
success: function (res) {
var icon = res.code == 0 ? 1 : 2;
if (res.msg != '') {
var icon = res.code === 0 ? 1 : 2;
if (res.msg) {
layer.msg(res.msg, {icon: icon});
}
if (res.location) {
setTimeout(function () {
window.location.href = res.location;
}, 1500);
} else {
submit.attr('disabled', false).removeClass('layui-btn-disabled');
}
submit.attr('disabled', false).text('提交');
},
error: function (xhr) {
var json = JSON.parse(xhr.responseText);
layer.msg(json.msg, {icon: 2});
submit.attr('disabled', false).text('提交');
submit.attr('disabled', false).removeClass('layui-btn-disabled');
}
});
return false;