<?php /** * 培训计划表Service * Created by PhpStorm. */ namespace Common\Service; use Common\Common\Constant; use Common\Common\Teacher; use Common\Common\AttachOperation; use Common\Model\PlanModel; class PlanService extends AbstractService { // 计划名称最大长度 const PLAN_NAME_MAX_LENGTH = 62; // 培训计划启用状态:失效 const PLAN_STATUS_CLOSE = 0; // 培训计划启用状态:启用 const PLAN_STATUS_OPEN = 1; // 培训计划操作状态:锁定 const PLAN_OPERATE_LOCK = 0; // 培训计划操作状态:开启 const PLAN_OPERATE_OPEN = 1; // 培训计划操作状态:已完成(已签到,素材、照片墙已查看,完成考试,完成问卷) const PLAN_OPERATE_DONE = 2; // 培训计划类型:签到 const PLAN_TYPE_SIGN = 1; // 培训计划类型:素材 const PLAN_TYPE_SOURCE = 2; // 培训计划类型:问卷 const PLAN_TYPE_QUESTION = 3; // 培训计划类型:考试 const PLAN_TYPE_EXAM = 4; // 培训计划类型:照片墙 const PLAN_TYPE_PHOTO = 5; // 培训计划类型:线下课程 const PLAN_TYPE_UNDER_LINE_COURSE = 6; // 允许员工上传照片 const ALLOW_UPLOAD = 1; // 不允许员工上传照片 const NOT_ALLOW_UPLOAD = 0; // 每个类型计划个数最大值 const PLAN_MAX_COUNT = 10; /** @var PlanModel */ protected $_d; /** @var PlanPicService */ protected $plan_pic_service; /** @var CourseArticleService */ protected $course_article_service; // 计划类型对应的类型名称 protected $plan_type_names = [ self::PLAN_TYPE_SIGN => '签到', self::PLAN_TYPE_SOURCE => '素材', self::PLAN_TYPE_QUESTION => '问卷', self::PLAN_TYPE_EXAM => '考试', self::PLAN_TYPE_PHOTO => '照片墙', self::PLAN_TYPE_UNDER_LINE_COURSE => '线下课程', ]; public function __construct() { parent::__construct(); // 实例化培训计划model $this->_d = new PlanModel(); $this->plan_pic_service = new PlanPicService(); $this->course_article_service = new CourseArticleService(); } /** * 验证培训计划列表数据 * * @author houyingcai * @param array $list 培训计划列表 * @int int $ed_status 培训状态(1=草稿;2=发布;3=已终止) * @int int $old_ed_status 原培训状态(1=草稿;2=已发布;3=已终止) * * @return bool */ public function validate_plan_data($list = [], $ed_status = Constant::EDUCATION_PUBLISH_STATUS_PUBLISHED, $old_ed_status = Constant::EDUCATION_PUBLISH_STATUS_PUBLISHED) { $plan_max_error = []; foreach ($list as $key => $val) { if (isset($plan_max_error[$val['plan_type']])) { // 如果没有定义 默认值已 $plan_max_error[$val['plan_type']] = 1; } else { // 如果存在定义 加一下 $plan_max_error[$val['plan_type']] = $plan_max_error[$val['plan_type']] + 1; } // 判断每个计划不能超过10个 foreach ($plan_max_error as $k => $value) { if ($value > self::PLAN_MAX_COUNT) { E('【' . $this->plan_type_names[$k] . '不能超过10个'); } } // 计划名称不能有空 if (empty($val['plan_name'])) { E('_EMPTY_PLAN_NAME'); } // 计划对应ID不能为空(除签到、线下课程之外) if ($val['plan_type'] != self::PLAN_TYPE_SIGN && $val['plan_type'] != self::PLAN_TYPE_UNDER_LINE_COURSE && !intval($val['plan_obj_id'])) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':计划对应ID不能为空', 2169100); } // 计划类型参数无效(类型必须在 1-6 之间) if (intval($val['plan_type']) < self::PLAN_TYPE_SIGN || intval($val['plan_type']) > self::PLAN_TYPE_UNDER_LINE_COURSE) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':类型参数无效', 2169101); } // 计划启用状态参数无效 if ($val['plan_use_status'] != self::PLAN_OPERATE_LOCK && $val['plan_use_status'] != self::PLAN_OPERATE_OPEN) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':启用状态参数无效', 2169103); } // 计划启用状态时启用时间大于0 if ($val['plan_use_status'] == self::PLAN_STATUS_OPEN && !$val['plan_use_time']) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':启用时间不能为空', 2169104); } // 培训计划类型为:签到类型 if (self::PLAN_TYPE_SIGN == $val['plan_type']) { // 组装签到时间段数组,用于验证时间段是否有重叠 $sign_list[$key]['plan_sign_begin'] = $val['plan_sign_begin']; $sign_list[$key]['plan_sign_end'] = $val['plan_sign_end']; // 签到是否是新增 if (!$val['plan_id']) { // 签到开始时间不能为空 if (empty($val['plan_sign_begin'])) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':签到开始时间不能为空', 2169105); } // 签到结束时间不能为空 if (empty($val['plan_sign_end'])) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':签到结束时间不能为空', 2169106); } // 签到结束时间不能小于开始时间 if ($val['plan_sign_end'] < $val['plan_sign_begin']) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':签到结束时间不能小于当前时间', 2169108); } } // 验证签到时间段是否有重叠 if (!empty($sign_list) && count($sign_list) > 1) { foreach ($sign_list as $k => $v) { // 签到时间段有重叠 if (!empty($val['plan_sign_begin']) && (($val['plan_sign_begin'] >= $v['plan_sign_begin'] && $val['plan_sign_begin'] <= $v['plan_sign_end']) || ($val['plan_sign_end'] >= $v['plan_sign_begin'] && $val['plan_sign_end'] <= $v['plan_sign_end'])) && $k != $key ) { E('_ERR_PLAN_SIGN_TIME_REPEAT'); } } } } // 培训计划类型为:照片墙类型 if (self::PLAN_TYPE_PHOTO == $val['plan_type'] && !in_array(intval($val['plan_allow_upload']), [self::NOT_ALLOW_UPLOAD, self::ALLOW_UPLOAD], true)) { E('【' . $this->plan_type_names[$val['plan_type']] . '】:' . $val['plan_name'] . ':是否允许员工上传参数无效', 2169111); } // 培训计划类型为:线下课程 if (self::PLAN_TYPE_UNDER_LINE_COURSE == $val['plan_type']) { $this->course_article_service->check_data($val['course'], $ed_status, $old_ed_status); } } return true; } /** * 批量删除培训安排 * @author liyifei * @param array $plan_ids 待删除的培训安排id * @int int $ed_status 培训状态(1=草稿;2=发布;3=已终止) * @return bool */ public function delete_plan($plan_ids, $ed_status = Constant::EDUCATION_PUBLISH_STATUS_PUBLISHED) { // 删除线下课程类型的培训计划时,需通知讲师中心、删除课程的计划任务 $conds = [ 'plan_id' => $plan_ids, 'plan_type' => Constant::PLAN_TYPE_UNDER_LINE_COURSE, ]; $article_plan_list = $this->list_by_conds($conds, [], [], 'plan_obj_id'); if (!empty($article_plan_list)) { $articleServ = new CourseArticleService(); $signServ = new SignService(); $cronServ = new CronService(); $teacherServ = &Teacher::instance(); $article_ids = array_column($article_plan_list, 'plan_obj_id'); $article_list = $articleServ->list_by_pks($article_ids); // 删除线下课程数据 $articleServ->delete($article_ids); // 删除线下课程签到数据 $signServ->delete_by_conds(['article_id' => $article_ids]); foreach ($article_list as $article) { if ($ed_status == Constant::EDUCATION_PUBLISH_STATUS_PUBLISHED) { // 将讲师ID设置为0 $article['teacher_id'] = 0; $teacherServ->saveOfflineCourse($article); // 删除课程的计划任务 $cronServ->delCron('', $article['article_id']); } } } // 删除照片墙类型的培训计划时,需删除UC附件服务器文件 $conds['plan_type'] = Constant::PLAN_TYPE_PHOTO; $del_photos = $this->list_by_conds($conds, [], [], 'plan_id'); if (!empty($del_photos)) { $attachServ = new AttachOperation(); $del_photo_plan_ids = array_column($del_photos, 'plan_id'); $attachServ->delete_attach(APP_DIR, 'plan', $del_photo_plan_ids); } $this->delete($plan_ids); } /** * 保存培训安排 * * @author houyingcai * @param int $ed_id 培训ID * @param int $stage_id 培训阶段ID * @param array $data 培训安排数据 * @int int $ed_status 培训状态(1=草稿;2=发布;3=已终止) * * @return bool */ public function save_plan($ed_id = 0, $stage_id = 0, $data = [], $ed_status = Constant::EDUCATION_PUBLISH_STATUS_PUBLISHED) { $courseServ = new CourseArticleService(); // 组装数据 $insert_data = []; foreach ($data as $k => &$v) { unset($v['plan_id']); $v['ed_id'] = $ed_id; $v['stage_id'] = $stage_id; $v['plan_obj_id'] = $v['plan_obj_id'] ? (int)$v['plan_obj_id'] : 0; $v['plan_order'] = $k + 1; $v['plan_name'] = raddslashes($v['plan_name']); $v['plan_sign_begin'] = !empty($v['plan_sign_begin']) ? $v['plan_sign_begin'] : ''; $v['plan_sign_end'] = !empty($v['plan_sign_end']) ? $v['plan_sign_end'] : ''; $v['plan_sign_comments'] = !empty($v['plan_sign_comments']) ? raddslashes($v['plan_sign_comments']) : ''; // 对数组进行排序,防止insert_all时出错 ksort($v); switch ($v['plan_type']) { // 照片墙(数据已提前写入plan表,此处仅需修改即可) case self::PLAN_TYPE_PHOTO: $plan_id = $v['plan_obj_id']; $v['plan_obj_id'] = 0; $row = $this->update($plan_id, $v); if (!$row) { E('【照片墙】:' . $v['plan_name'] . ' 添加失败', '2169112'); } // 更新照片表的培训ID $this->plan_pic_service->update_by_conds(['plan_id' => $plan_id], ['ed_id' => $ed_id]); break; // 线下课程 case self::PLAN_TYPE_UNDER_LINE_COURSE: // 保存线下课程 $v['plan_obj_id'] = $courseServ->save_course($v['course'], $ed_status, $v['plan_use_status']); // 保存培训安排 unset($v['course']); $insert_data[] = $v; break; default: $insert_data[] = $v; break; } } // 批量插入新增数据 if (!empty($insert_data)) { $row_plans = $this->insert_all($insert_data); if (!$row_plans) { E('培训计划添加失败', '2169114'); } } // 为所有线下课程绑定ed_id和plan_id $plan_list = $this->list_by_conds(['ed_id' => $ed_id, 'plan_type' => Constant::PLAN_TYPE_UNDER_LINE_COURSE]); if (!empty($plan_list)) { foreach ($plan_list as $plan) { $update_data = [ 'ed_id' => $plan['ed_id'], 'plan_id' => $plan['plan_id'], ]; $this->course_article_service->update($plan['plan_obj_id'], $update_data); } } return true; } /** * 编辑计划数据 * * @author houyingcai * @param int $ed_id 培训ID * @param int $stage_id 培训阶段ID * @param array $plans 计划数据数组 * @param array $plan_del_ids 需删除的培训安排id * @int int $ed_status 培训状态(1=草稿;2=发布;3=已终止) * * @return bool */ public function edit_plan($ed_id = 0, $stage_id = 0, $plans = [], $plan_del_ids = [], $ed_status = Constant::EDUCATION_PUBLISH_STATUS_PUBLISHED) { $courseServ = new CourseArticleService(); $insert_data = []; $plan_order = 0; foreach ($plans as &$v) { // 要删除的培训安排,不再更新 if (in_array($v['plan_id'], $plan_del_ids)) { continue; } $plan_order++; // 更新需要更新的数据 if (isset($v['plan_id']) && $v['plan_id'] > 0) { $update['ed_id'] = $ed_id; $update['stage_id'] = $stage_id; $update['plan_order'] = $plan_order; $update['plan_name'] = raddslashes($v['plan_name']); $update['plan_use_status'] = intval($v['plan_use_status']); $update['plan_use_time'] = $v['plan_use_time']; switch ($v['plan_type']) { // 签到 case self::PLAN_TYPE_SIGN: $update['plan_sign_begin'] = $v['plan_sign_begin']; $update['plan_sign_end'] = $v['plan_sign_end']; $update['plan_sign_comments'] = $v['plan_sign_comments']; break; // 照片墙 case self::PLAN_TYPE_PHOTO: $update['plan_allow_upload'] = intval($v['plan_allow_upload']); // 更新照片表的培训ID $this->plan_pic_service->update_by_conds(['plan_id' => $v['plan_id']], ['ed_id' => $ed_id]); break; // 线下课程 case self::PLAN_TYPE_UNDER_LINE_COURSE: if (isset($v['course']) && !empty($v['course'])) { // 修改线下课程详情 $courseServ->save_course($v['course'], $ed_status, $v['plan_use_status']); } break; } $row = $this->_d->update($v['plan_id'], $update); if (!$row) { E($v['plan_name'] . ' 更新失败', '2169112'); } } else { $v['ed_id'] = $ed_id; $v['stage_id'] = $stage_id; $v['plan_order'] = $plan_order; $v['plan_name'] = raddslashes($v['plan_name']); $v['plan_obj_id'] = $v['plan_obj_id'] ? intval($v['plan_obj_id']) : 0; $v['plan_sign_begin'] = !empty($v['plan_sign_begin']) ? $v['plan_sign_begin'] : ''; $v['plan_sign_end'] = !empty($v['plan_sign_end']) ? $v['plan_sign_end'] : ''; $v['plan_sign_comments'] = !empty($v['plan_sign_comments']) ? raddslashes($v['plan_sign_comments']) : ''; // 新增线下课程类型 if ($v['plan_type'] == Constant::PLAN_TYPE_UNDER_LINE_COURSE) { // 保存线下课程 $v['plan_obj_id'] = $courseServ->save_course($v['course'], $ed_status, $v['plan_use_status']); unset($v['course']); } // 保存培训安排 ksort($v); $insert_data[] = $v; } } // 批量插入新增数据 if (!empty($insert_data)) { $row_plans = $this->insert_all($insert_data); if (!$row_plans) { E('培训计划添加失败', '2169114'); } } // 为所有线下课程绑定ed_id和plan_id $plan_list = $this->list_by_conds(['ed_id' => $ed_id, 'plan_type' => Constant::PLAN_TYPE_UNDER_LINE_COURSE]); if (!empty($plan_list)) { foreach ($plan_list as $plan) { $update_data = [ 'ed_id' => $plan['ed_id'], 'plan_id' => $plan['plan_id'], ]; $this->course_article_service->update($plan['plan_obj_id'], $update_data); } } return true; } /** * 添加照片墙 * * @author 蔡建华 * @param $params array 表单数据 * * @return mixed */ public function add_pic_plan($params = []) { if (empty($params['plan_name'])) { // 照片墙名称不能把为空 E('_EMPTY_PLAN_PIC_NAME'); } if (strlen($params['plan_name']) > self::PLAN_NAME_MAX_LENGTH) { // 照片墙名称长度超过最大值 E('_EMPTY_PLAN_PIC_NAME_MORE'); } try { // 开始事务 $this->start_trans(); $data = [ 'plan_name' => $params['plan_name'], 'plan_type' => self::PLAN_TYPE_PHOTO, 'plan_allow_upload' => intval($params['plan_allow_upload']), 'plan_use_status' => self::PLAN_STATUS_OPEN ]; // 添加照片墙数据 $plan_id = $this->_d->insert($data); $pics = []; if ($plan_id) { // 照片墙添加成功 后台添加照片 $upload = $params['upload']; foreach ($upload as $val) { if (!empty($val['pic_at_id'])) { $value = $val; $value['plan_id'] = $plan_id; $value['pic_uid'] = ''; $value['pic_type'] = PlanPicService::PIC_UPLOAD_TYPE_ADMIN; $pics[] = $value; } } } if (!empty($pics)) { // 照片数据入库 $this->plan_pic_service->insert_all($pics); } // 提交事务 $this->commit(); } catch (\Exception $e) { \Think\Log::record($e); $this->_set_error($e->getMessage(), $e->getCode()); // 事务回滚 $this->rollback(); return false; } // 附件操作 if (!empty($upload)) { $attach_serv = new AttachOperation(); $attach_ids = array_column($upload, 'pic_at_id'); $attach_serv->insert_attach( APP_DIR, 'plan', $plan_id, ['attach_ids' => $attach_ids] ); } return $plan_id; } /** * 编辑照片墙 * * @author 蔡建华 * @param $params array 表单数据 * * @return bool */ public function edit_pic_plan($params = []) { if (empty($params['plan_id'])) { E('_EMPTY_PLAN_PIC_ID'); } if (empty($params['plan_name'])) { E('_EMPTY_PLAN_PIC_NAME'); } if (strlen($params['plan_name']) > self::PLAN_NAME_MAX_LENGTH) { // 照片墙名称长度超过最大值 E('_EMPTY_PLAN_PIC_NAME_MORE'); } $data = [ 'plan_name' => $params['plan_name'], 'plan_allow_upload' => intval($params['plan_allow_upload']), 'plan_use_status' => self::PLAN_STATUS_OPEN ]; $conds = [ 'plan_id' => $params['plan_id'], 'plan_type' => self::PLAN_TYPE_PHOTO ]; $this->_d->update_by_conds($conds, $data); return true; } /** * 获取被使用的应用id集合 * * @param int $plan_type 应用类型 * * @return array 被使用的id集合 */ public function get_obj_ids($plan_type = 0) { return $this->_d->get_obj_ids($plan_type); } }