|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace App\Models;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use EasyWeChat\Factory;
|
|
|
|
|
|
use Illuminate\Filesystem\Filesystem;
|
|
|
|
|
|
|
|
|
|
|
|
class Course extends SoftDeletesModel
|
|
|
|
|
|
{
|
|
|
|
|
|
protected $appends = [
|
|
|
|
|
|
'date_status',
|
|
|
|
|
|
'publicize',
|
|
|
|
|
|
'sign_date_status',
|
|
|
|
|
|
'qrcode',
|
|
|
|
|
|
'teacher_detail',
|
|
|
|
|
|
'status_text',
|
|
|
|
|
|
'is_fee_text',
|
|
|
|
|
|
'is_arrange_text',
|
|
|
|
|
|
'show_txl_text',
|
|
|
|
|
|
'show_mobile_text',
|
|
|
|
|
|
'auto_schoolmate_text',
|
|
|
|
|
|
'is_virtual_text'
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
protected $casts = ['publicize_ids' => 'json'];
|
|
|
|
|
|
|
|
|
|
|
|
public function getStatusTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '待发布', 1 => '已发布'];
|
|
|
|
|
|
return $array[$this->attributes['status']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getIsFeeTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '免费', 1 => '收费'];
|
|
|
|
|
|
return $array[$this->attributes['is_fee']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getIsArrangeTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '否', 1 => '是'];
|
|
|
|
|
|
return $array[$this->attributes['is_arrange']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getShowTxlTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '否', 1 => '是'];
|
|
|
|
|
|
return $array[$this->attributes['show_txl']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getShowMobileTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '否', 1 => '是'];
|
|
|
|
|
|
return $array[$this->attributes['show_mobile']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getAutoSchoolmateTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '否', 1 => '是'];
|
|
|
|
|
|
return $array[$this->attributes['auto_schoolmate']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getIsVirtualTextAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$array = [0 => '否', 1 => '是'];
|
|
|
|
|
|
return $array[$this->attributes['is_virtual']];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getQrcodeAttribute($value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->getCourseQrcode($this->attributes['id']);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getTeacherDetailAttribute($value)
|
|
|
|
|
|
{
|
|
|
|
|
|
$teacherIds = explode(',', $this->teacher_id);
|
|
|
|
|
|
return Teacher::whereIn('id', $teacherIds)->get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getPublicizeAttribute($value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (empty($this->publicize_ids))
|
|
|
|
|
|
return [];
|
|
|
|
|
|
return Upload::whereIn('id', $this->publicize_ids)->get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getDateStatusAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$text = '课程未开始';
|
|
|
|
|
|
if ($this->course_status == 10) {
|
|
|
|
|
|
$text = '课程进行中';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($this->course_status == 40) {
|
|
|
|
|
|
$text = '课程已结束';
|
|
|
|
|
|
}
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function getSignDateStatusAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
$text = '未开始';
|
|
|
|
|
|
if ($this->sign_status == 10) {
|
|
|
|
|
|
$text = '进行中';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($this->sign_status == 40) {
|
|
|
|
|
|
$text = '已结束';
|
|
|
|
|
|
}
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function typeDetail()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasOne(CourseType::class, 'id', 'type');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function courseForms()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasMany(CourseForm::class, 'course_id', 'id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function teacher()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasOne(Teacher::class, 'id', 'teacher_id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function courseSettings()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasMany(CourseSetting::class, 'course_id', 'id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function coursePeriods()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasMany(CoursePeriod::class, 'course_id', 'id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function courseSigns()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasMany(CourseSign::class, 'course_id', 'id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function image()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasOne(Upload::class, 'id', 'image_id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function qunImage()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasOne(Upload::class, 'id', 'qun_image_id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function courseContents()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasMany(CourseContent::class, 'course_id', 'id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function courseContentEvaluation()
|
|
|
|
|
|
{
|
|
|
|
|
|
return $this->hasMany(CourseContentEvaluation::class, 'course_id', 'id');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更新课程报名状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function updateSignStatus($courseId)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 进行中-未开始-已结束
|
|
|
|
|
|
$now = date('Y-m-d');
|
|
|
|
|
|
$course = Course::find($courseId);
|
|
|
|
|
|
// 默认未开始
|
|
|
|
|
|
$sign_status = 30;
|
|
|
|
|
|
if ($course->sign_start_date && $now < $course->sign_start_date) {
|
|
|
|
|
|
// 未开始
|
|
|
|
|
|
$sign_status = 20;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($course->sign_start_date && $now >= $course->sign_start_date) {
|
|
|
|
|
|
// 进行中
|
|
|
|
|
|
$sign_status = 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($course->sign_end_date && $now > $course->sign_end_date) {
|
|
|
|
|
|
// 已结束
|
|
|
|
|
|
$sign_status = 40;
|
|
|
|
|
|
}
|
|
|
|
|
|
$course->sign_status = $sign_status;
|
|
|
|
|
|
$course->save();
|
|
|
|
|
|
return $course;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更新课程状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function updateStatus($courseId)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 进行中-未开始-已结束
|
|
|
|
|
|
$now = date('Y-m-d');
|
|
|
|
|
|
$course = Course::find($courseId);
|
|
|
|
|
|
// 默认待定
|
|
|
|
|
|
$course_status = 30;
|
|
|
|
|
|
if ($course->start_date && $now < $course->start_date) {
|
|
|
|
|
|
// 未开始
|
|
|
|
|
|
$course_status = 20;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($course->start_date && $now >= $course->start_date) {
|
|
|
|
|
|
// 进行中
|
|
|
|
|
|
$course_status = 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($course->end_date && $now > $course->end_date) {
|
|
|
|
|
|
// 已结束
|
|
|
|
|
|
$course_status = 40;
|
|
|
|
|
|
}
|
|
|
|
|
|
$course->course_status = $course_status;
|
|
|
|
|
|
$course->save();
|
|
|
|
|
|
return $course;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取课程详情小程序码
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getCourseQrcode($courseId)
|
|
|
|
|
|
{
|
|
|
|
|
|
$course = Course::find($courseId);
|
|
|
|
|
|
$path = config('filesystems.disks.public.root') . '/course_qrcode/' . $course->id . '.png';
|
|
|
|
|
|
$url = config('filesystems.disks.public.url') . '/course_qrcode/' . $course->id . '.png';
|
|
|
|
|
|
$fileSys = new Filesystem();
|
|
|
|
|
|
if ($fileSys->exists($path)) {
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
$config = [
|
|
|
|
|
|
'app_id' => \config('app.applet_appid'),
|
|
|
|
|
|
'secret' => \config('app.applet_secret')
|
|
|
|
|
|
];
|
|
|
|
|
|
$app = Factory::miniProgram($config);
|
|
|
|
|
|
$tmp = $app->app_code->get('packages/course/detail?' . 'id=' . $courseId, [
|
|
|
|
|
|
'env_version' => "release" // 正式版
|
|
|
|
|
|
// 'env_version' => "trial" // 体验版
|
|
|
|
|
|
]);
|
|
|
|
|
|
$dir = dirname($path);
|
|
|
|
|
|
$fileSys->ensureDirectoryExists($dir, 0755, true);
|
|
|
|
|
|
$fileSys->put($path, $tmp);
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取课程报名小程序码
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getCourseCheckQrcode($courseId)
|
|
|
|
|
|
{
|
|
|
|
|
|
$course = Course::find($courseId);
|
|
|
|
|
|
$path = config('filesystems.disks.public.root') . '/course_check_qrcode/' . $course->id . '.png';
|
|
|
|
|
|
$url = config('filesystems.disks.public.url') . '/course_check_qrcode/' . $course->id . '.png';
|
|
|
|
|
|
$fileSys = new Filesystem();
|
|
|
|
|
|
if ($fileSys->exists($path)) {
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
$config = [
|
|
|
|
|
|
'app_id' => \config('app.applet_appid'),
|
|
|
|
|
|
'secret' => \config('app.applet_secret')
|
|
|
|
|
|
];
|
|
|
|
|
|
$app = Factory::miniProgram($config);
|
|
|
|
|
|
$tmp = $app->app_code->get('packages/sign/course?course_id=' . $courseId, [
|
|
|
|
|
|
'env_version' => "release" // 正式版
|
|
|
|
|
|
]);
|
|
|
|
|
|
$dir = dirname($path);
|
|
|
|
|
|
$fileSys->ensureDirectoryExists($dir, 0755, true);
|
|
|
|
|
|
$fileSys->put($path, $tmp);
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取问卷小程序码
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getEvaluationQrcode($id)
|
|
|
|
|
|
{
|
|
|
|
|
|
$courseContentEvaluation = CourseContentEvaluation::find($id);
|
|
|
|
|
|
$path = config('filesystems.disks.public.root') . '/course_evaluation_qrcode/' . $courseContentEvaluation->id . '.png';
|
|
|
|
|
|
$url = config('filesystems.disks.public.url') . '/course_evaluation_qrcode/' . $courseContentEvaluation->id . '.png';
|
|
|
|
|
|
$fileSys = new Filesystem();
|
|
|
|
|
|
if ($fileSys->exists($path)) {
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
$config = [
|
|
|
|
|
|
'app_id' => \config('app.applet_appid'),
|
|
|
|
|
|
'secret' => \config('app.applet_secret')
|
|
|
|
|
|
];
|
|
|
|
|
|
$app = Factory::miniProgram($config);
|
|
|
|
|
|
$tmp = $app->app_code->get('packages/surveyFill/index?id=' . $id, [
|
|
|
|
|
|
// todo:: 版本切换
|
|
|
|
|
|
'env_version' => "release" // 正式版
|
|
|
|
|
|
// 'env_version' => "trial" // 体验版
|
|
|
|
|
|
]);
|
|
|
|
|
|
$dir = dirname($path);
|
|
|
|
|
|
$fileSys->ensureDirectoryExists($dir, 0755, true);
|
|
|
|
|
|
$fileSys->put($path, $tmp);
|
|
|
|
|
|
return $url;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取课程统计项元数据
|
|
|
|
|
|
* 返回每个统计项的计算逻辑和验证方法说明
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function getStatisticsMetadata()
|
|
|
|
|
|
{
|
|
|
|
|
|
return [
|
|
|
|
|
|
'course_signs_total' => [
|
|
|
|
|
|
'name' => '报名人数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内的所有报名记录数量。包括所有状态的报名(待审核、已通过、已拒绝等),同时会加上历史课程数据中的人数统计。一个学员报名多个课程会计算多次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'course_signs_pass' => [
|
|
|
|
|
|
'name' => '审核通过人数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内审核通过的报名记录数量。只统计状态为"已通过"的报名,不包括待审核、已拒绝等其他状态。同时会加上历史课程数据中已通过的人数统计。一个学员报名多个课程会计算多次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'course_signs_pass_unique' => [
|
|
|
|
|
|
'name' => '审核通过人数去重',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内审核通过的学员人数(按学员去重)。与"审核通过人数"的区别是:如果同一个学员报名了多个课程,这里只计算一次。通过学员的手机号进行去重,确保每个学员只统计一次。同时会加上历史课程数据中去重后的人数统计。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'course_total' => [
|
|
|
|
|
|
'name' => '开课场次',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程体系范围内的开课场次数。一个课程可能有多个场次(比如分多天上课),这里统计的是场次数,不是课程数。只要场次的开始时间或结束时间在指定时间范围内,就会被统计。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'course_day_total' => [
|
|
|
|
|
|
'name' => '开课天数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程体系范围内的开课天数总和。只统计标记为"需要统计天数"的场次,每个场次可能有不同的天数(比如3天、5天等),将所有场次的天数相加得到总天数。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_market_total' => [
|
|
|
|
|
|
'name' => '上市公司数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内报名的学员中,所在公司为上市公司的公司数量。通过学员关联到其所在公司,筛选出已上市的公司,然后按公司去重统计。如果同一公司有多个学员报名,只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'ganbu_total' => [
|
|
|
|
|
|
'name' => '跟班学员数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内的跟班学员人数。筛选条件:1)学员的"来源"字段包含"跟班学员";2)课程类型标记为"需要统计跟班学员"。同时会加上员工参与表中的额外数据。按学员去重,同一学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_market_year_total' => [
|
|
|
|
|
|
'name' => '今年上市公司数量',
|
|
|
|
|
|
'from' => '统计所有在今年(当前年份)上市的公司数量。直接从上市公司表中查询,统计上市日期在今年内的公司。这个统计不依赖学员报名记录,统计的是所有在今年上市的公司,不管是否有学员报名。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_market_after_enrollment_total' => [
|
|
|
|
|
|
'name' => '入学后上市公司数量',
|
|
|
|
|
|
'from' => '统计所有标记为"入学后上市"的公司数量。直接从上市公司表中查询,统计标记为"入学后上市"的公司。这个统计不依赖学员报名记录,统计的是所有在学员入学后才上市的公司。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'course_signs_invested' => [
|
|
|
|
|
|
'name' => '累计被投企业数',
|
|
|
|
|
|
'from' => '统计从课程开始日期到结束日期,在指定课程范围内报名的学员中,所在公司为被投企业的公司数量。通过学员关联到其所在公司,筛选出标记为"被投企业"的公司,检查公司的被投时间是否在截止日期之前(或没有记录被投时间),然后按公司去重统计。同一公司多个学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_invested_after_enrollment_total' => [
|
|
|
|
|
|
'name' => '入学后被投企业数量',
|
|
|
|
|
|
'from' => '统计在指定时间范围内报名的学员中,所在公司在学员入学后被投的公司数量。以学员报名的课程开课时间作为"入学时间",筛选出公司的被投时间晚于入学时间的公司,然后按公司去重统计。同一公司多个学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_invested_year_total' => [
|
|
|
|
|
|
'name' => '今年被投企业数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内报名的学员中,所在公司在指定年份范围内被投的公司数量。从开始日期和结束日期中提取年份范围,筛选出公司的被投时间在指定年份范围内的公司,然后按公司去重统计。同一公司多个学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_join_total' => [
|
|
|
|
|
|
'name' => '元和员工参与人数',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内报名的学员中,所在公司为元和投资公司的学员人数。通过学员关联到其所在公司,筛选出元和投资的公司,然后按学员去重统计。同一学员报名多个课程只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'company_ganbu_total' => [
|
|
|
|
|
|
'name' => '全市干部参与企业',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内报名的学员中,来源为"跟班学员"且课程类型标记为"需要统计跟班学员"的学员人数。与"跟班学员数"的统计逻辑相同,同时会加上员工参与表中的额外数据。按学员去重,同一学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'cover_head_total' => [
|
|
|
|
|
|
'name' => '苏州头部企业',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内报名的学员中,所在公司为苏州头部企业的公司数量。通过学员关联到其所在公司,筛选出标记为"苏州头部企业"的公司,然后按公司去重统计。同一公司多个学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'cover_rencai_total' => [
|
|
|
|
|
|
'name' => '高层次人才',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内报名的学员中,标记为"高层次人才"的学员人数。通过学员的个人信息(如学历等)判断是否为高层次人才,然后按学员去重统计。同一学员报名多个课程只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
'cover_stock_total' => [
|
|
|
|
|
|
'name' => '重点上市公司',
|
|
|
|
|
|
'from' => '统计在指定时间范围内、指定课程范围内报名的学员中,所在公司为重点上市公司的公司数量。通过学员关联到其所在公司,筛选出重点上市公司,然后按公司去重统计。与"上市公司数"的统计逻辑相同,但筛选的是重点上市公司。同一公司多个学员只计算一次。',
|
|
|
|
|
|
'verify' => ''
|
|
|
|
|
|
],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|