初始化项目:添加后端代码、ThinkPHP框架、前端资源

This commit is contained in:
amb
2026-09-03 12:42:39 +08:00
commit 482bece22e
3726 changed files with 416708 additions and 0 deletions
@@ -0,0 +1,229 @@
<?php
namespace app\admin\model\course;
use think\Model;
use app\admin\model\course\Course;
class ColumnBind extends Model
{
// 表名
protected $name = 'course_bind_column';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
];
public function course()
{
return $this->belongsTo('Course', 'course_id', 'id', [], 'right')->setEagerlyType(0);
}
/**
* 专栏绑定的课程
* 考虑绑定类型可能还有目录
* @return mixed
*/
public function bindcourse()
{
return $this->belongsTo('Course', 'course_id', 'id', [], 'left')->setEagerlyType(0);
}
/**
* 内容绑定专栏
* @param $courseId 内容ID
* @param $column 专栏
* @return void
*/
public function setCourseBindColumn($courseId,$columns){
$columnIds = [];
if($columns){
foreach ($columns as $column){
$columnIds[] = $column['id'];
}
}
$courseBindColumnIds = $this->getCourseBindColumnIds($courseId);
//判断已经绑定的专栏列表 是不是在这次更新的列表中,不在则删除
if(!empty($courseBindColumnIds)){
foreach ($courseBindColumnIds as $columnId){
if(!in_array($columnId,$columnIds)){
self::where([
'column_id'=>$columnId,
'course_id'=>$courseId,
])->delete();
}
}
}
if(!empty($columnIds)){
foreach ($columnIds as $columnId){
$this->setColumnBindCourse($columnId,[$courseId]);
}
}
}
/**
* 获取内容绑定的专栏
* @param $courseId
* @return array
*/
public function getCourseBindColumn($courseId){
$CourseModel = new \app\admin\model\course\Course();
$ids = $this->getCourseBindColumnIds($courseId);
return $CourseModel->where('id','in',$ids)->field(['id','name','createtime'])->select();
}
/**
* 获取内容绑定的专栏ID
* @param $courseId
* @return array
*/
public function getCourseBindColumnIds($courseId){
$columnIds = self::where(['course_id'=>$courseId])->field('column_id')->select();
if(!$columnIds){
return [];
}
$ids = [];
foreach ($columnIds as $id){
$ids[] = $id['column_id'];
}
return $ids;
}
/**
* 绑定内容
* @param $columnId
* @param $courseIds
* @param $dir
* @return bool
*/
public function setColumnBindCourse($columnId,$courseIds,$p_id = 0,$type = 1,$title = ''){
$bindCourseId = $this->getBindCourseId($columnId);
//获取专栏已经绑定过的课程,如果需要被绑定的课程不再已经绑定的列表中,则添加
if(!empty($courseIds)){
foreach ($courseIds as $item){
if(!in_array($item,$bindCourseId)){
$row = [
'course_id'=>$item,
'column_id'=>$columnId,
'try'=>0,
'type'=>$type,
'title'=>$title,
'p_id'=>$p_id,
'uniacid'=>UNIACID,
'createtime'=>time(),
];
$row['sort']=$this->defineSort($columnId,$p_id);
//改变课程的sales_type
$courseInfo = Course::where([
'id'=>$item
])->field("sales_type")->find();
if($courseInfo){
$salesType = json_decode($courseInfo['sales_type'],true);
if(!in_array("column",$salesType)){
$salesType[] = "column";
}
Course::where([
'id'=>$item
])->update([
'sales_type'=>json_encode($salesType)
]);
}
self::insert($row);
}
}
}
return true;
}
/**
* 获取绑定的内容ID
* @param $columnId
* @return mixed
*/
public function getBindCourseId($columnId){
$list = self::where([
'column_id'=>$columnId,
'type'=>1
])->field('course_id')->select();
$ids = [];
if(!empty($list)){
foreach ($list as $item){
$ids[] = $item['course_id'];
}
}
return $ids;
}
/**
* 获取新绑定项的排序值
* 根据专栏(Course)配置的 column_update 决定新条目落在同层的头部还是尾部:
* - column_update = 'desc':最近添加的在前 → 取同层 min(sort) - 1
* - column_update = 'asc' 或未设置:最近添加的在后 → 取同层 max(sort) + 1
* @param int $columnId 专栏IDtuzhi_course.id
* @param int $p_id 上级目录ID
* @return int
*/
public function defineSort($columnId,$p_id = 0){
//读取专栏的更新顺序配置
$columnUpdate = Course::where(['id'=>$columnId])->value('column_update');
$columnUpdate = $columnUpdate === 'desc' ? 'desc' : 'asc';
if($columnUpdate === 'desc'){
//最近添加的在前:排到同层最前面
$minItem = self::where([
'column_id'=>$columnId,
'p_id'=>$p_id
])->field("sort")->order("sort asc")->find();
if(!$minItem){
return 0;
}
return (int)$minItem['sort'] - 1;
}
//最近添加的在后:排到同层最后面
$maxItem = self::where([
'column_id'=>$columnId,
'p_id'=>$p_id
])->field("sort")->order("sort desc")->find();
if(!$maxItem){
return 0;
}
return (int)$maxItem['sort'] + 1;
}
}
@@ -0,0 +1,112 @@
<?php
namespace app\admin\model\course;
use think\Model;
use app\admin\model\course\ColumnBind;
class ColumnDir extends Model
{
// 表名
protected $name = 'course_column_dir';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
];
public function course()
{
return $this->belongsTo('app\admin\model\Course', 'course_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
/**
* 获取目录列表
* @param $courseId
* @return array
*/
public function courseIdGetList($courseId){
$parentDir = $this->selectDir($courseId);
if(!$parentDir){
return [];
}
foreach ($parentDir as &$child){
$children = $this->selectDir($courseId,$child['id']);
if($children){
$child['children'] = $children;
}
}
return $parentDir;
}
/**
* 查询目录
* @param $courseId
* @param $pid
* @return mixed
*/
public function selectDir($courseId,$pid = 0){
$list = self::where(['course_id'=>$courseId,'p_id'=>$pid])->order('sort asc')->select();
if($list){
foreach ($list as &$item){
$item['count'] = ColumnBind::where([
'column_id'=>$courseId,
'dir'=>$item['id']
])->count();
}
}
return $list;
}
/**
* 删除
* @param $id
* @return bool
*/
public function del($id){
$info = self::where(['id'=>$id])->find();
if(!$info){
return false;
}
self::where(['id'=>$id])->whereOr(['p_id'=>$id])->delete();
return true;
}
/**
* 获取排序
* @return void
*/
public function defineSort($courseId,$pid){
$maxItem = self::where([
'course_id'=>$courseId,
'p_id'=>$pid
])->field("sort")->order("sort desc")->find();
if(!$maxItem){
return 0;
}
return $maxItem['sort'] + 1;
}
}
+245
View File
@@ -0,0 +1,245 @@
<?php
namespace app\admin\model\course;
use think\Model;
use app\admin\model\course\GroupBind;
class Course extends Model
{
// 表名
protected $name = 'course';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
//需要转换的数组参数
protected $arrayField = ['unshelf_status','hide','live_video','try_listen_course','try_watch_content','shelf_type_time_pause','try_read_status','audio_path','try_listen_status','try_listen_content','try_watch_course','try_watch_status','video_path','try_watch_status','shelf_pause','hide','limit_watch','bind_data','sales_type'];
protected $timeField = ['validity_fix_time','shelf_time','unshelf_time','live_start_time','live_end_time'];
// 追加属性
protected $append = [
// 'type_text',
// 'pay_type_text',
// 'validity_type_text',
// 'validity_diy_time_text',
// 'validity_fix_time_text',
// 'shelf_time_text',
// 'unshelf_time_text'
];
/**
* 检查状态
* @param $params
* @return void
*/
public function checkStatus($params){
//立即上架
if($params['shelf_type'] == 'now'){
return 1;
}
//暂不上架
if($params['shelf_type'] == 'no'){
return 0;
}
//定时上架
if($params['shelf_type'] == 'time' && $params['shelf_time'] > time()){
return 1;
}
//定时下架
if(!empty($params['unshelf_status']) && $params['unshelf_time'] > time()){
return 0;
}
return 0;
}
/**
* 转换参数格式
* @param $params 参数
* @param $type 类型 编码encode 解码decode
* @return array
*/
public function structrue($params,$type = 'encode'){
$groupBindModel = new GroupBind();
$data = [];
foreach ($params as $key => $item){
if(in_array($key,$this->arrayField)){
if($type=='encode'){
$data[$key] = json_encode($item);
}else{
$data[$key] = json_decode($item,true);
}
}elseif(in_array($key,$this->timeField)){
if($type=='decode'){
if($item){
$time = $item;
}else{
$time = time();
}
$data[$key] = date('Y-m-d H:i:s',$time);
$data[$key.'_num'] = $time;
}else{
$data[$key] = is_string($item) ? strtotime($item) : ceil($item / 1000);
}
}elseif($key=='group'){
if($type=='decode'){
$data[$key] = [];
if(isset($params['id'])){
$data[$key] = $groupBindModel->getCourseBindGroup($params['id']);
}
}else{
$data[$key] = $item;
}
}else{
$data[$key] = $item;
}
}
if($type=='encode'){
foreach ($this->timeField as $timeField){
unset($data[$timeField.'_num']);
}
if(isset($data['live_type']) && $data['live_type'] == 2){
$data['live_end_time'] = $data['live_start_time'] + $data['live_video_duration'];
}
}
$data['uniacid'] = UNIACID;
return $data;
}
public function getTypeList()
{
return ['article' => __('Article'), 'video' => __('Video'), 'audio' => __('Audio'), 'column' => __('Column')];
}
public function getPayTypeList()
{
return ['free' => __('Free'), 'pay' => __('Pay'), 'password' => __('Password')];
}
public function getValidityTypeList()
{
return ['diy' => __('Diy'), 'fix' => __('Fix'), 'long' => __('Long')];
}
public function getTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['type']) ? $data['type'] : '');
$list = $this->getTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getPayTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['pay_type']) ? $data['pay_type'] : '');
$list = $this->getPayTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getValidityTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['validity_type']) ? $data['validity_type'] : '');
$list = $this->getValidityTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getValidityDiyTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['validity_diy_time']) ? $data['validity_diy_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getValidityFixTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['validity_fix_time']) ? $data['validity_fix_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getShelfTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['shelf_time']) ? $data['shelf_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getUnshelfTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['unshelf_time']) ? $data['unshelf_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
protected function setValidityDiyTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setValidityFixTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setShelfTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setUnshelfTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
public function agentGoods()
{
return $this->belongsTo('app\admin\model\app\agent\Goods', 'id', 'goods_id', [], 'left')->setEagerlyType(0);
}
public function study()
{
return $this->belongsTo('app\admin\model\data\Study', 'id','course_id', [], 'LEFT')->setEagerlyType(0);
}
/**
* 获取直播课程 IDS
* @return void
*/
public function getLiveCourseIds(){
return self::where([
'type'=>'live'
])->order('id','desc')->column('id');
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace app\admin\model\course;
use think\Model;
class Group extends Model
{
// 表名
protected $name = 'course_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
'status_text'
];
/**
* 状态列表
*/
public function getStatusList()
{
return [
0 => '禁用',
1 => '启用'
];
}
/**
* 状态文本
*/
public function getStatusTextAttr($value, $data)
{
$list = $this->getStatusList();
return isset($list[$data['status']]) ? $list[$data['status']] : '';
}
/**
* 获取排序
*/
public function defineSort()
{
$maxItem = self::field("sort")->where('uniacid', UNIACID)->order("sort desc")->find();
if (!$maxItem) {
return 0;
}
return $maxItem['sort'] + 1;
}
}
@@ -0,0 +1,172 @@
<?php
namespace app\admin\model\course;
use think\Model;
class GroupBind extends Model
{
// 表名
protected $name = 'course_bind_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
];
public function course()
{
return $this->belongsTo('Course', 'course_id', 'id', [], 'RIGHT')->setEagerlyType(0);
}
/**
* 通过内容ID设置绑定
* @param $courseId 内容ID
* @param $column 专栏
* @return void
*/
public function setCourseBindGroup($courseId,$groupIds){
//删除旧的
$courseBindGroupIds = $this->getCourseBindGroup($courseId);
if(!empty($courseBindGroupIds)){
foreach ($courseBindGroupIds as $groupId){
if(!in_array($groupId,$groupIds)){
self::where([
'group_id'=>$groupId,
'course_id'=>$courseId,
])->delete();
}
}
}
//添加新的
if(!empty($groupIds)){
foreach ($groupIds as $groupId){
$this->setGroupBindCourse($groupId,[$courseId]);
}
}
}
/**
* 通过分组ID设置绑定
* @param $courseId 内容ID
* @param $column 专栏
* @return void
*/
public function setGroupBindCourse($groupId,$courseIds){
$bindCourseId = $this->getGroupBindCourse($groupId);
if(!empty($courseIds)){
foreach ($courseIds as $item){
if(!in_array($item,$bindCourseId)){
$row = [
'uniacid'=>UNIACID,
'course_id'=>$item,
'group_id'=>$groupId,
'createtime'=>time(),
];
$row['sort']=$this->defineSort($groupId);
self::insert($row);
}
}
}
return true;
}
/**
* 获取排序
* @return void
*/
public function defineSort($columnId){
$maxItem = self::where([
'group_id'=>$columnId
])->field("sort")->order("sort desc")->find();
if(!$maxItem){
return 0;
}
return $maxItem['sort'] + 1;
}
/**
* 获取内容绑定分组
* @param $courseId
* @return array
*/
public function getCourseBindGroup($courseId){
$groupIds = self::where(['course_id'=>$courseId])->field('group_id')->select();
if(!$groupIds){
return [];
}
$ids = [];
foreach ($groupIds as $id){
$ids[] = $id['group_id'];
}
return $ids;
}
/**
* 获取分组绑定内容
* @param $courseId
* @return array
*/
public function getGroupBindCourse($groupId){
$courseIds = self::where(['group_id'=>$groupId])->field('course_id')->select();
if(!$courseIds){
return [];
}
$ids = [];
foreach ($courseIds as $id){
$ids[] = $id['course_id'];
}
return $ids;
}
/**
* 获取分组绑定内容数量
* @param $courseId
* @return mixed
*/
public function groupGetCourseBindCount($groupId){
return self::where(['group_id'=>$groupId])->count();
}
/**
* 取消某分组绑定的内容(全部)
* @param $groupId
* @return mixed
*/
public function groupDelCourseBind($groupId){
return self::where(['group_id'=>$groupId])->delete();
}
/**
* 取消分组与内容的绑定(单个)
* @param $groupId
* @return mixed
*/
public function groupCancelCourse($groupId,$courseId){
return self::where(['group_id'=>$groupId,'course_id'=>$courseId])->delete();
}
}
+181
View File
@@ -0,0 +1,181 @@
<?php
namespace app\admin\model\course;
use think\Model;
use app\admin\model\course\GroupBind;
class Live extends Model
{
// 表名
protected $name = 'course';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
'live_status',
'live_status_text',
'live_start_time_text'
// 'pay_type_text',
// 'validity_type_text',
// 'validity_diy_time_text',
// 'validity_fix_time_text',
// 'shelf_time_text',
// 'unshelf_time_text'
];
/**
* 通过优惠券 ids 集合获取可正常展示的优惠券
* @param $ids
* @return void
*/
public function idsGetLives($ids,$limit=0){
$lives = self::normal()
->where([
'id'=>['in',$ids]
]) // 符合指定商品,并且检测商品所属分类
->order('id', 'desc');
if($limit){
$lives = $lives->limit($limit);
}
$lives = $lives->select();
$lives = collection($lives)->each(function ($coupon) {
});
return $lives;
}
public function scopeNormal($query)
{
return $query->where([
'status'=>1,
'sales_type'=>['like',"%alone%"],
'hide'=>0,
'type'=>'live'
]);
}
/**
* 直播中
* @param $query
* @return void
*/
public function scopeIng($query){
return $query->where([
'live_start_time'=>['<',time()],
'live_end_time'=>['>',time()]
]);
}
/**
* 未开始
* @param $query
* @return void
*/
public function scopeUnstart($query){
return $query->where([
'live_start_time'=>['>',time()]
]);
}
/**
* 已结束
* @param $query
* @return void
*/
public function scopeEnd($query){
return $query->where([
'live_end_time'=>['<',time()]
]);
}
/**
* 最近直播
* @param $query
* @return void
*/
public function scopeRecently($query){
return $query->order('live_start_time','desc');
}
/**
* 最近直播
* @param $query
* @return void
*/
public function scopeFieldLimit($query){
return $query->field(['id','name','price','price_marking','pay_type','cover','briefing','status','live_start_time','live_end_time']);
}
/**
* 直播状态
* @return void
*/
public function getLiveStatusList()
{
return [
'ing'=>'直播中',
'recently'=>'最近直播',
'unstart'=>'未开始',
'end'=>'已结束'
];
}
public function getLiveStatusAttr($value, $data)
{
if($data['live_end_time'] < time()){
return 'end';
}
if($data['live_start_time'] > time()){
return 'unstart';
}
if($data['live_end_time'] > time() && $data['live_start_time'] < time()){
return 'ing';
}
}
public function getLiveStatusTextAttr($value, $data)
{
$liveStatusList = $this->getLiveStatusList();
return $liveStatusList[$this->getLiveStatusAttr($value, $data)];
}
public function getLiveStartTimeTextAttr($value, $data)
{
return date('Y-m-d H:i',$data['live_start_time']);
}
public function getPayTypeList()
{
return ['free' => __('Free'), 'pay' => __('Pay'), 'password' => __('Password')];
}
public function getTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['type']) ? $data['type'] : '');
$list = $this->getTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
}