lion 4 months ago
commit 79d783a7df

@ -23,7 +23,7 @@ class UpdateUserNo extends Command
*
* @var string
*/
protected $description = '批量更新学号';
protected $description = '批量更新学号/打元和同事标签';
/**
* Create a new command instance.
@ -42,6 +42,21 @@ class UpdateUserNo extends Command
*/
public function handle()
{
// 1. 批量更新学号
$this->updateUserNo();
// 2. 给元和同事打标签
$this->tagYuanheColleague();
return $this->info('更新完成');
}
/**
* 批量更新学号
*/
protected function updateUserNo()
{
$this->info('开始更新学号...');
// 已经开始的课程日期(所有历史数据处理)
// $dateList = Course::whereNotNull('start_date')
// ->where('start_date', '<=', date('Y-m-d'))
@ -52,9 +67,11 @@ class UpdateUserNo extends Command
// 当日数据处理(日常定时任务)
$dateList = [date('Y-m-d')];
foreach ($dateList as $date) {
$courses = Course::with(['courseSigns' => function ($query) {
$query->where('status', 1);
}])->where('start_date', $date)
$courses = Course::with([
'courseSigns' => function ($query) {
$query->where('status', 1);
}
])->where('start_date', $date)
->whereNotNull('student_prefix')
->orderBy('start_date')
->get();
@ -70,12 +87,50 @@ class UpdateUserNo extends Command
// 更新用户编号
$user->no = $no;
$user->save();
$this->info($no);
$this->info('学号: ' . $no);
$i++;
}
}
}
return $this->info('更新完成');
$this->info('学号更新完成');
}
/**
* 给元和同事打标签
*/
protected function tagYuanheColleague()
{
$this->info('开始给元和同事打标签...');
$tag = '元禾同事';
// 获取元和员工用户列表
$users = CourseSign::companyJoin(null, null, null, true);
$count = 0;
foreach ($users as $user) {
// 获取当前的 from 字段
$from = $user->from ?? '';
// 将 from 字段按逗号分隔成数组
$fromArray = array_filter(array_map('trim', explode(',', $from)));
// 检查是否已存在该标签
if (in_array($tag, $fromArray)) {
continue;
}
// 追加标签
$fromArray[] = $tag;
// 更新 from 字段
$user->from = implode(',', $fromArray);
$user->save();
$this->info('已为用户 ' . $user->name . '(' . $user->mobile . ') 添加标签: ' . $tag);
$count++;
}
$this->info('元和同事标签更新完成,共更新 ' . $count . ' 人');
}
}

@ -8,11 +8,34 @@ namespace App\Exports;
use App\Exceptions\ErrorException;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class CommonExport implements FromCollection
class CommonExport implements FromCollection, WithStyles, WithColumnWidths, WithEvents
{
public $fields;
public $data;
public $hasUsersField = false;
public $usersColumnStartIndex = null;
public $totalColumns = 0;
public $totalRows = 0;
public $expandedFields = [];
// 学员信息子列定义
const USERS_SUB_COLUMNS = [
'user_index' => '序号',
'user_no' => '学号',
'user_name' => '姓名',
'user_schoolmate' => '校友',
'user_position' => '职位',
'user_mobile' => '手机',
'user_course' => '报名课程',
'user_sign_date' => '报名时间',
];
public function __construct($data, $exportFields)
{
@ -20,8 +43,206 @@ class CommonExport implements FromCollection
$this->fields = $exportFields;
// 数据
$this->data = $data;
// 构建扩展后的字段列表
$this->buildExpandedFields();
}
/**
* 构建扩展后的字段列表将users字段展开成多列
*/
private function buildExpandedFields()
{
if (!is_array($this->fields)) {
return;
}
$index = 1;
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
$this->hasUsersField = true;
$this->usersColumnStartIndex = $index;
// 展开学员信息为多列
foreach (self::USERS_SUB_COLUMNS as $subField => $subLabel) {
$this->expandedFields[$subField] = $subLabel;
$index++;
}
} else {
$this->expandedFields[$field] = $label;
$index++;
}
}
$this->totalColumns = count($this->expandedFields);
}
/**
* 获取列字母
*/
private function getColumnLetter($columnNumber)
{
$letter = '';
while ($columnNumber > 0) {
$columnNumber--;
$letter = chr(65 + ($columnNumber % 26)) . $letter;
$columnNumber = intval($columnNumber / 26);
}
return $letter;
}
/**
* 设置列宽
*/
public function columnWidths(): array
{
$widths = [];
$index = 1;
foreach (array_keys($this->expandedFields) as $field) {
$letter = $this->getColumnLetter($index);
if (in_array($field, ['user_course', 'user_name'])) {
$widths[$letter] = 25;
} elseif (in_array($field, ['user_mobile', 'user_sign_date'])) {
$widths[$letter] = 15;
} elseif (in_array($field, ['user_index', 'user_schoolmate'])) {
$widths[$letter] = 8;
} elseif (str_contains($field, 'partners') || str_contains($field, 'project_users')) {
$widths[$letter] = 50;
} elseif (str_contains($field, 'all_course')) {
$widths[$letter] = 40;
} elseif (str_contains($field, 'company_name') || str_contains($field, 'address')) {
$widths[$letter] = 30;
} else {
$widths[$letter] = 15;
}
$index++;
}
return $widths;
}
/**
* 设置样式
*/
public function styles(Worksheet $sheet): array
{
$lastCol = $this->getColumnLetter($this->totalColumns);
$dataStartRow = $this->hasUsersField ? 3 : 2;
$styles = [];
if ($this->hasUsersField) {
// 二级表头样式 - 第一行
$styles[1] = [
'font' => ['bold' => true, 'size' => 12],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['rgb' => 'D0D0D0'],
],
];
// 二级表头样式 - 第二行
$styles[2] = [
'font' => ['bold' => true, 'size' => 11],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['rgb' => 'E8E8E8'],
],
];
} else {
// 单行表头样式
$styles[1] = [
'font' => ['bold' => true, 'size' => 12],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['rgb' => 'E0E0E0'],
],
];
}
// 所有数据区域样式
$styles["A1:{$lastCol}" . ($this->totalRows + $dataStartRow - 1)] = [
'alignment' => [
'vertical' => Alignment::VERTICAL_CENTER,
'wrapText' => true,
],
'borders' => [
'allBorders' => [
'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
'color' => ['rgb' => 'CCCCCC'],
],
],
];
return $styles;
}
/**
* 注册事件
*/
public function registerEvents(): array
{
return [
AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
if ($this->hasUsersField) {
// 处理二级表头的单元格合并
$this->mergeHeaderCells($sheet);
// 设置表头行高
$sheet->getRowDimension(1)->setRowHeight(25);
$sheet->getRowDimension(2)->setRowHeight(22);
// 冻结前两行
$sheet->freezePane('A3');
} else {
$sheet->getRowDimension(1)->setRowHeight(25);
$sheet->freezePane('A2');
}
// 设置数据行高
$dataStartRow = $this->hasUsersField ? 3 : 2;
for ($row = $dataStartRow; $row <= $this->totalRows + $dataStartRow - 1; $row++) {
$sheet->getRowDimension($row)->setRowHeight(22);
}
},
];
}
/**
* 合并表头单元格
*/
private function mergeHeaderCells(Worksheet $sheet)
{
$index = 1;
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
// 学员信息列:合并第一行的多个单元格
$startCol = $this->getColumnLetter($index);
$endCol = $this->getColumnLetter($index + count(self::USERS_SUB_COLUMNS) - 1);
$sheet->mergeCells("{$startCol}1:{$endCol}1");
$sheet->setCellValue("{$startCol}1", $label);
// 学员信息子表头不需要合并
$index += count(self::USERS_SUB_COLUMNS);
} else {
// 非学员信息列:合并第一行和第二行
$col = $this->getColumnLetter($index);
$sheet->mergeCells("{$col}1:{$col}2");
$sheet->setCellValue("{$col}1", $label);
$index++;
}
}
}
/**
* 数组转集合
@ -36,65 +257,172 @@ class CommonExport implements FromCollection
if (!is_array($this->fields)) {
throw new ErrorException('导出字段必须是数组');
}
// 获取表头
$header = array_values($this->fields);
$moreFileds = [];
if (empty($clear)) {
// 表头追加附属数据
if (isset($this->data[0]['data']) && is_array($this->data[0]['data'])) {
$moreHeader = array_column($this->data[0]['data'], 'name');
// 获取头信息
$header = array_merge($header, $moreHeader);
// 获取字段信息
$moreFileds = array_column($this->data[0]['data'], 'field');
}
}
// 获取字段指向
$fields = array_keys($this->fields);
$newList = [];
foreach ($this->data as $info) {
$temp = [];
foreach ($fields as $field) {
if (str_contains($field, 'idcard')) {
// 身份证
$temp[$field] = ' ' . $this->getDotValue($info, $field);
} elseif (str_contains($field, 'all_course')) {
// 所有课程
$temp[$field] = $this->allCourse($info);
} elseif (str_contains($field, 'partners')) {
// 股东信息
$temp[$field] = $this->partners($info);
} elseif (str_contains($field, 'project_users')) {
// 项目经理
$temp[$field] = $this->projectManager($info);
} elseif (str_contains($field, 'users')) {
// 学员信息
$temp[$field] = $this->getUsers($info);
if ($this->hasUsersField) {
// 有学员字段:创建二级表头
// 第一行表头(主表头)- 在 mergeHeaderCells 中处理
$header1 = [];
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
// 学员信息占用多列,第一行只需要占位
foreach (self::USERS_SUB_COLUMNS as $subLabel) {
$header1[] = '';
}
} else {
$header1[] = '';
}
}
$newList[] = $header1;
// 第二行表头(子表头)
$header2 = [];
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
foreach (self::USERS_SUB_COLUMNS as $subLabel) {
$header2[] = $subLabel;
}
} else {
$temp[$field] = $this->getDotValue($info, $field);
$header2[] = '';
}
}
// 如果有自定义数据,全部附件上去
$t2 = [];
$newList[] = $header2;
// 数据行:每个学员的每条课程记录占一行
foreach ($this->data as $info) {
$usersData = $this->getUsersExpanded($info);
if (empty($usersData)) {
// 没有学员数据,输出一行空数据
$row = $this->buildRowWithoutUsers($info, []);
$newList[] = $row;
} else {
// 每个学员记录一行
foreach ($usersData as $userData) {
$row = $this->buildRowWithoutUsers($info, $userData);
$newList[] = $row;
}
}
}
} else {
// 没有学员字段:使用原有逻辑
$header = array_values($this->fields);
$moreFileds = [];
if (empty($clear)) {
if (isset($info['data']) && $info['data'] && !empty($moreFileds)) {
$dataCollect = collect($info['data']);
foreach ($moreFileds as $moreFiled) {
$value = ($dataCollect->where('field', $moreFiled)->first()['value']) ?? '';
if (str_contains($moreFiled, 'idcard')) {
$t2[$moreFiled] = ' ' . $value;
} else {
$t2[$moreFiled] = $value;
if (isset($this->data[0]['data']) && is_array($this->data[0]['data'])) {
$moreHeader = array_column($this->data[0]['data'], 'name');
$header = array_merge($header, $moreHeader);
$moreFileds = array_column($this->data[0]['data'], 'field');
}
}
$newList[] = $header;
foreach ($this->data as $info) {
$temp = [];
foreach (array_keys($this->fields) as $field) {
if (str_contains($field, 'idcard')) {
$temp[$field] = ' ' . $this->getDotValue($info, $field);
} elseif (str_contains($field, 'all_course')) {
$temp[$field] = $this->allCourse($info);
} elseif (str_contains($field, 'partners')) {
$temp[$field] = $this->partners($info);
} elseif (str_contains($field, 'project_users')) {
$temp[$field] = $this->projectManager($info);
} else {
$temp[$field] = $this->getDotValue($info, $field);
}
}
$t2 = [];
if (empty($clear)) {
if (isset($info['data']) && $info['data'] && !empty($moreFileds)) {
$dataCollect = collect($info['data']);
foreach ($moreFileds as $moreFiled) {
$value = ($dataCollect->where('field', $moreFiled)->first()['value']) ?? '';
if (str_contains($moreFiled, 'idcard')) {
$t2[$moreFiled] = ' ' . $value;
} else {
$t2[$moreFiled] = $value;
}
}
}
}
$newList[] = array_values($temp + $t2);
}
$newList[] = $temp + $t2;
}
array_unshift($newList, $header); //插入表头
$this->totalRows = count($newList) - ($this->hasUsersField ? 2 : 1);
return new Collection($newList);
}
/**
* 获取展开的学员数据(每个学员每条课程一行)
*/
private function getUsersExpanded($info)
{
if (empty($info['users'])) {
return [];
}
$result = [];
$userIndex = 1;
foreach ($info['users'] as $user) {
if (!empty($user['course_signs'])) {
foreach ($user['course_signs'] as $signIndex => $sign) {
$result[] = [
'user_index' => $signIndex === 0 ? $userIndex : '',
'user_no' => $signIndex === 0 ? ($user['no'] ?? '-') : '',
'user_name' => $signIndex === 0 ? ($user['username'] ?? '-') : '',
'user_schoolmate' => $signIndex === 0 ? ($user['is_schoolmate_text'] ?? '-') : '',
'user_position' => $signIndex === 0 ? ($user['company_position'] ?? '-') : '',
'user_mobile' => $signIndex === 0 ? ($user['mobile'] ?? '-') : '',
'user_course' => $sign['course']['name'] ?? '-',
'user_sign_date' => isset($sign['created_at']) ? substr($sign['created_at'], 0, 10) : '-',
];
}
} else {
$result[] = [
'user_index' => $userIndex,
'user_no' => $user['no'] ?? '-',
'user_name' => $user['username'] ?? '-',
'user_schoolmate' => $user['is_schoolmate_text'] ?? '-',
'user_position' => $user['company_position'] ?? '-',
'user_mobile' => $user['mobile'] ?? '-',
'user_course' => '-',
'user_sign_date' => '-',
];
}
$userIndex++;
}
return $result;
}
/**
* 构建包含学员数据的行
*/
private function buildRowWithoutUsers($info, $userData)
{
$row = [];
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
// 填充学员信息列
foreach (array_keys(self::USERS_SUB_COLUMNS) as $subField) {
$row[] = $userData[$subField] ?? '';
}
} elseif (str_contains($field, 'idcard')) {
$row[] = ' ' . $this->getDotValue($info, $field);
} elseif (str_contains($field, 'all_course')) {
$row[] = $this->allCourse($info);
} elseif (str_contains($field, 'partners')) {
$row[] = $this->partners($info);
} elseif (str_contains($field, 'project_users')) {
$row[] = $this->projectManager($info);
} else {
$row[] = $this->getDotValue($info, $field);
}
}
return $row;
}
/**
* .号转数组层级并返回对应的值
* @param $key
@ -161,21 +489,4 @@ class CommonExport implements FromCollection
return implode("、\r\n", $list);
}
/**
* 获取手机号
* @param $data
*/
function getUsers($data)
{
$list = [];
foreach ($data['users'] as $item) {
$base = $item['no'] . '-' . $item['username'] . '-' . $item['is_schoolmate_text'] . '-' . $item['company_position'] . '-' . ($item['mobile'] ?? '');
foreach ($item['course_signs'] as $i) {
$base .= '-' . $i['course']['name'] . '-' . ($i['created_at'] ?? '');
}
$list[] = $base;
}
return implode("、\r\n", $list);
}
}

@ -12,6 +12,7 @@ use App\Models\CourseContentEvaluationAsk;
use App\Models\CourseContentEvaluationForm;
use App\Models\CustomForm;
use App\Models\CustomFormField;
use App\Models\HistoryCourse;
use App\Models\SupplyDemand;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
@ -49,7 +50,7 @@ class CalendarsController extends BaseController
public function index()
{
$all = \request()->all();
$list = Calendar::with('course', 'courseContent')
$list = Calendar::with('course', 'courseContent','historyCourses')
->where(function ($query) use ($all) {
if (isset($all['month'])) {
$query->where('start_time', 'like', $all['month'] . '%');
@ -90,7 +91,7 @@ class CalendarsController extends BaseController
if ($validator->fails()) {
return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
}
$detail = $this->model->with('courseContent')->find($all['id']);
$detail = $this->model->with(['courseContent', 'historyCourses'])->find($all['id']);
return $this->success($detail);
}
@ -113,6 +114,7 @@ class CalendarsController extends BaseController
* @OA\Parameter(name="is_publish", in="query", @OA\Schema(type="string"), required=true, description="是否向用户发布0否1是"),
* @OA\Parameter(name="address", in="query", @OA\Schema(type="string"), required=true, description="地址"),
* @OA\Parameter(name="days", in="query", @OA\Schema(type="string"), required=true, description="天数"),
* @OA\Parameter(name="history_courses", in="query", @OA\Schema(type="array", @OA\Items(type="object")), required=false, description="历史课程数组每项包含type(课程体系ID), course_name(课程名称), course_type_signs_pass(培养人数未去重), course_type_signs_pass_unique(培养人数去重), course_signs_pass(课程培养人数), start_time(开始时间), end_time(结束时间)"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="认证token"),
* @OA\Response(
* response="200",
@ -122,7 +124,39 @@ class CalendarsController extends BaseController
*/
public function save()
{
return parent::save();
$all = \request()->all();
DB::beginTransaction();
try {
if (isset($all['id'])) {
$model = $this->model->find($all['id']);
if (empty($model)) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '数据不存在']);
}
} else {
$model = $this->model;
$all['admin_id'] = $this->getUserId();
$all['department_id'] = $this->getUser()->department_id;
}
$original = $model->getOriginal();
$model->fill($all);
$model->save();
// 处理历史课程数据
if (isset($all['history_courses']) && is_array($all['history_courses'])) {
// 删除原有的历史课程数据
$model->historyCourses()->delete();
$model->historyCourses()->createMany($all['history_courses']);
}
DB::commit();
// 记录日志
$this->saveLogs($original, $model);
// 返回带有历史课程的数据
$model->load('historyCourses');
return $this->success($model);
} catch (\Exception $exception) {
DB::rollBack();
return $this->fail([$exception->getCode(), $exception->getMessage()]);
}
}
/**
@ -141,7 +175,33 @@ class CalendarsController extends BaseController
*/
public function destroy()
{
return parent::destroy();
$all = \request()->all();
$messages = [
'id.required' => 'Id必填',
];
$validator = Validator::make($all, [
'id' => 'required'
], $messages);
if ($validator->fails()) {
return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
}
DB::beginTransaction();
try {
$model = $this->model->find($all['id']);
if (empty($model)) {
return $this->fail([ResponseCode::ERROR_BUSINESS, '数据不存在']);
}
// 删除关联的历史课程数据
$model->historyCourses()->delete();
// 删除日历
$model->delete();
DB::commit();
return $this->success([]);
} catch (\Exception $exception) {
DB::rollBack();
return $this->fail([$exception->getCode(), $exception->getMessage()]);
}
}
}

@ -86,7 +86,9 @@ class CourseSignController extends BaseController
$query->where('is_vip', $all['is_vip']);
}
if (isset($all['company_name'])) {
$query->where('company_name', 'like', '%' . $all['company_name'] . '%');
$query->whereHas('company', function ($query) use ($all) {
$query->where('company_name', 'like', '%' . $all['company_name'] . '%');
});
}
if (isset($all['company_position'])) {
$query->where('company_position', $all['company_position']);

@ -128,7 +128,7 @@ class OtherController extends CommonController
$list['schoolmate_year'] = User::where('is_schoolmate', 1)->where('created_at', 'like', '%' . date('Y') . '%')->count();
// 投后企业
$list['company_invested_total'] = CourseSign::yhInvested();
// 元和员工参与企业
// 元和员工参与人数
$list['company_join_total'] = CourseSign::companyJoin();
// 全市干部参与企业
$list['company_ganbu_total'] = CourseSign::ganbu();
@ -236,7 +236,7 @@ class OtherController extends CommonController
})->whereIn('course_id', $courses->pluck('id'));
$list['course_total'] = (clone $calendar)->count();
// 开课天数
$list['course_day_total'] = (clone $calendar)->sum('days');
$list['course_day_total'] = (clone $calendar)->where('is_count_days', 1)->sum('days');
// 上市公司数(所有上市公司)
$list['company_market_total'] = Company::companyMarket($start_date, $end_date);
@ -251,7 +251,10 @@ class OtherController extends CommonController
// 入学后上市公司数量(在指定时间范围内报名的学员所在公司中,在入学后上市的公司数量)
$list['company_market_after_enrollment_total'] = CourseSign::companyMarketAfterEnrollment($start_date, $end_date, $course_ids);
// 元和员工参与企业
// 入学后被投企业数量(在指定时间范围内报名的学员所在公司中,在入学后被投的公司数量)
$list['company_invested_after_enrollment_total'] = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date, $course_ids);
// 元和员工参与人数
$list['company_join_total'] = CourseSign::companyJoin($start_date, $end_date, $course_ids);
// 全市干部参与企业
$list['company_ganbu_total'] = CourseSign::ganbu($start_date, $end_date, $course_ids);
@ -268,7 +271,14 @@ class OtherController extends CommonController
$courseTypes = CourseType::whereIn('id', $course_type_id)->get();
foreach ($courseTypes as $courseType) {
// 获取课程
$courses2 = Course::where('type', $courseType->id)->orderBy('start_date', 'asc')->get();
$courses2 = Course::where('type', $courseType->id)
->where(function ($query) use ($start_date, $end_date) {
// 开始结束日期的筛选。or查询
if ($start_date && $end_date) {
$query->whereBetween('start_date', [$start_date, $end_date])
->orWhereBetween('end_date', [$start_date, $end_date]);
}
})->orderBy('start_date', 'asc')->get();
foreach ($courses2 as $course) {
$courseTypesSum[] = [
'course_type' => $courseType->name,
@ -282,7 +292,9 @@ class OtherController extends CommonController
}
}
// 附加历史课程数据
$historyCourses = HistoryCourse::where(function ($query) use ($start_date, $end_date) {
$historyCourses = HistoryCourse::whereHas('calendar', function ($query) {
$query->where('is_count_people', 1);
})->where(function ($query) use ($start_date, $end_date) {
// 开始结束日期的筛选。or查询
$query->whereBetween('start_time', [$start_date, $end_date])
->orWhereBetween('end_time', [$start_date, $end_date]);
@ -310,7 +322,7 @@ class OtherController extends CommonController
* tags={"其他"},
* summary="课程统计明细导出",
* description="导出课程统计数据的明细",
* @OA\Parameter(name="export_type", in="query", @OA\Schema(type="string"), required=true, description="导出类型course_signs_invested-被投企业明细, course_signs_total-报名人数明细, course_signs_pass-审核通过人数明细, course_signs_pass_unique-审核通过人数去重明细, courseTypesSum-课程分类明细, areas-区域明细, company_market_total-上市公司明细, ganbu_total-跟班学员明细, company_market_year_total-今年上市公司明细, company_market_after_enrollment_total-入学后上市公司明细, course_total-开课场次明细, course_day_total-开课天数明细, company_join_total-元和员工参与企业明细, company_ganbu_total-全市干部参与企业明细, cover_head_total-苏州头部企业明细, cover_rencai_total-高层次人才明细, cover_stock_total-重点上市公司明细"),
* @OA\Parameter(name="export_type", in="query", @OA\Schema(type="string"), required=true, description="导出类型course_signs_invested-被投企业明细, course_signs_total-报名人数明细, course_signs_pass-审核通过人数明细, course_signs_pass_unique-审核通过人数去重明细, courseTypesSum-课程分类明细, areas-区域明细, company_market_total-上市公司明细, ganbu_total-跟班学员明细, company_market_year_total-今年上市公司明细, company_market_after_enrollment_total-入学后上市公司明细, company_invested_after_enrollment_total-入学后被投企业明细, course_total-开课场次明细, course_day_total-开课天数明细, company_join_total-元和员工参与企业明细, company_ganbu_total-全市干部参与企业明细, cover_head_total-苏州头部企业明细, cover_rencai_total-高层次人才明细, cover_stock_total-重点上市公司明细"),
* @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string"), required=false, description="开始日期"),
* @OA\Parameter(name="end_date", in="query", @OA\Schema(type="string"), required=false, description="结束日期"),
* @OA\Parameter(name="course_type_id", in="query", @OA\Schema(type="string"), required=false, description="课程体系id多个英文逗号"),
@ -632,6 +644,39 @@ class OtherController extends CommonController
$filename = '入学后上市公司明细';
break;
case 'company_invested_after_enrollment_total':
// 入学后被投企业明细 - 使用模型方法
$companiesAfterEnrollment = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date, $course_ids, true);
foreach ($companiesAfterEnrollment as $item) {
$company = $item['company'];
$userNames = collect($item['users'])->pluck('name')->filter()->unique()->implode("\n\r");
$data[] = [
'company_name' => $company->company_name,
'company_legal_representative' => $company->company_legal_representative ?? '',
'company_date' => $company->company_date ?? '',
'invest_date' => $item['invest_date'] ?? '',
'first_sign_date' => $item['first_sign_date'],
'user_names' => $userNames,
'company_address' => $company->company_address ?? '',
'company_city' => $company->company_city ?? '',
'company_area' => $company->company_area ?? '',
];
}
$fields = [
'company_name' => '企业名称',
'company_legal_representative' => '法人',
'company_date' => '成立时间',
'invest_date' => '被投日期',
'first_sign_date' => '首次报名时间',
'user_names' => '学员姓名',
'company_address' => '地址',
'company_city' => '所在城市',
'company_area' => '所在区域',
];
$filename = '入学后被投企业明细';
break;
case 'course_total':
// 开课场次明细 - 与coursesHome算法一致
$calendars = Calendar::whereIn('course_id', $course_ids)
@ -691,35 +736,33 @@ class OtherController extends CommonController
break;
case 'company_join_total':
// 元和员工参与企业明细 - 使用模型方法
$companies = CourseSign::companyJoin($start_date, $end_date, $course_ids, true);
foreach ($companies as $company) {
// 元和员工参与人员明细 - 使用模型方法(现在返回的是用户列表)
$users = CourseSign::companyJoin($start_date, $end_date, $course_ids, true);
// 加载关联关系
$users->load('company');
foreach ($users as $user) {
$data[] = [
'company_name' => $company->company_name,
'company_legal_representative' => $company->company_legal_representative ?? '',
'company_date' => $company->company_date ?? '',
'company_address' => $company->company_address ?? '',
'company_city' => $company->company_city ?? '',
'company_area' => $company->company_area ?? '',
'business_scope' => $company->business_scope ?? '',
'contact_phone' => $company->contact_phone ?? '',
'contact_mail' => $company->contact_mail ?? '',
'company_tag' => $company->company_tag ?? '',
'credit_code' => ' ' . $company->credit_code ?? '',
'user_name' => $user->name ?? '',
'mobile' => $user->mobile ?? '',
'company_name' => $user->company->company_name ?? '',
'company_position' => $user->company_position ?? '',
'company_city' => $user->company->company_city ?? '',
'company_area' => $user->company->company_area ?? '',
'company_legal_representative' => $user->company->company_legal_representative ?? '',
'company_date' => $user->company->company_date ?? '',
'company_address' => $user->company->company_address ?? '',
];
}
$fields = [
'user_name' => '学员姓名',
'mobile' => '手机号',
'company_name' => '企业名称',
'company_position' => '职位',
'company_city' => '所在城市',
'company_area' => '所在区域',
'company_legal_representative' => '法人',
'company_date' => '成立时间',
'company_address' => '地址',
'company_city' => '所在城市',
'company_area' => '所在区域',
'business_scope' => '营业范围',
'contact_phone' => '联系电话',
'contact_mail' => '联系邮箱',
'company_tag' => '企业资质',
'credit_code' => '统一社会信用代码',
];
$filename = '元和员工参与企业明细';
break;

@ -291,7 +291,9 @@ class UserController extends BaseController
$query->where('name', 'like', '%' . $all['name'] . '%');
}
if (isset($all['company_name'])) {
$query->where('company_name', 'like', '%' . $all['company_name'] . '%');
$query->whereHas('company', function ($query) use ($all) {
$query->where('company_name', 'like', '%' . $all['company_name'] . '%');
});
}
if (isset($all['company_position'])) {
$query->where('company_position', $all['company_position']);

@ -9,7 +9,7 @@ use Illuminate\Support\Facades\Cache;
class Calendar extends SoftDeletesModel
{
protected $appends = ['is_publish_text','type_text'];
protected $appends = ['is_publish_text', 'type_text', 'is_count_days_text', 'is_count_people_text'];
public function getIsPublishTextAttribute()
{
@ -22,6 +22,16 @@ class Calendar extends SoftDeletesModel
return $array[$this->attributes['type']] ?? '';
}
public function getIsCountDaysTextAttribute()
{
return ($this->attributes['is_count_days'] ?? 1) == 1 ? '是' : '否';
}
public function getIsCountPeopleTextAttribute()
{
return ($this->attributes['is_count_people'] ?? 1) == 1 ? '是' : '否';
}
public function course()
{
return $this->hasOne(Course::class, 'id', 'course_id');
@ -32,5 +42,10 @@ class Calendar extends SoftDeletesModel
return $this->hasMany(CourseContent::class, 'id', 'course_content_id');
}
public function historyCourses()
{
return $this->hasMany(HistoryCourse::class, 'calendar_id', 'id');
}
}

@ -110,7 +110,9 @@ class CourseSign extends SoftDeletesModel
// 基础数据
$baseTotal = $totalQuery->count();
// 历史数据
$historyTotal = HistoryCourse::where(function ($query) use ($start_date, $end_date) {
$historyTotal = HistoryCourse::whereHas('calendar', function ($query) {
$query->where('is_count_people', 1);
})->where(function ($query) use ($start_date, $end_date) {
// 开始结束日期的筛选。or查询
$query->whereBetween('start_time', [$start_date, $end_date])
->orWhereBetween('end_time', [$start_date, $end_date]);
@ -133,7 +135,9 @@ class CourseSign extends SoftDeletesModel
} else {
$baseTotal = $user->count();
// 历史数据
$historyTotal = HistoryCourse::where(function ($query) use ($start_date, $end_date) {
$historyTotal = HistoryCourse::whereHas('calendar', function ($query) {
$query->where('is_count_people', 1);
})->where(function ($query) use ($start_date, $end_date) {
// 开始结束日期的筛选。or查询
$query->whereBetween('start_time', [$start_date, $end_date])
->orWhereBetween('end_time', [$start_date, $end_date]);
@ -173,7 +177,7 @@ class CourseSign extends SoftDeletesModel
{
$courseSignsQuery = self::getStudentList($start_date, $end_date, 1, $course_ids);
$courseSigns = $courseSignsQuery->whereHas('user', function ($query) {
$query->where('from', '跟班学员');
$query->where('from', 'like', '%跟班学员%');
})->get();
if ($retList) {
@ -223,6 +227,59 @@ class CourseSign extends SoftDeletesModel
}
}
/**
* 入学后被投企业数量(在指定时间范围内报名的学员所在公司中,在入学后被投的公司数量)
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @param array|null $course_ids 课程ID数组不传则统计所有课程
* @param bool $retList 是否返回列表false返回数量true返回列表
* @return int|array
*/
public static function companyInvestedAfterEnrollment($start_date, $end_date, $course_ids = null, $retList = false)
{
$courseSignsQuery = self::getStudentList($start_date, $end_date, 1, $course_ids);
$courseSignsForInvest = $courseSignsQuery->with('user.company')->get();
$companiesAfterEnrollment = [];
foreach ($courseSignsForInvest as $sign) {
if ($sign->user && $sign->user->company && $sign->user->company->is_yh_invested == 1) {
$signDate = \Carbon\Carbon::parse($sign->created_at)->format('Y-m-d');
// 从 project_users 中获取最早的被投时间
$projectUsers = $sign->user->company->project_users;
$investDate = null;
if (!empty($projectUsers) && is_array($projectUsers)) {
foreach ($projectUsers as $projectUser) {
if (!empty($projectUser['investDate'])) {
if ($investDate === null || $projectUser['investDate'] < $investDate) {
$investDate = $projectUser['investDate'];
}
}
}
}
// 被投时间 >= 报名时间,说明是入学后被投
if ($investDate && $investDate >= $signDate) {
$companyId = $sign->user->company->id;
if (!isset($companiesAfterEnrollment[$companyId])) {
$companiesAfterEnrollment[$companyId] = [
'company' => $sign->user->company,
'first_sign_date' => $signDate,
'invest_date' => $investDate,
'users' => [],
];
}
if ($retList) {
$companiesAfterEnrollment[$companyId]['users'][] = $sign->user;
}
}
}
}
if ($retList) {
return $companiesAfterEnrollment;
} else {
return count($companiesAfterEnrollment);
}
}
/**
* 区域统计
* @param string $start_date 开始日期
@ -275,11 +332,11 @@ class CourseSign extends SoftDeletesModel
}
/**
* 元和员工参与企业
* 元和员工参人员
*/
public static function companyJoin($start_date = null, $end_date = null, $course_ids = null, $retList = false)
{
$courseSignsQuery = self::getStudentList($start_date, $end_date, 1, $course_ids);
$courseSignsQuery = self::getStudentList($start_date, $end_date, null, $course_ids);
$courseSignByType = $courseSignsQuery->get();
// 检测关键词
@ -289,13 +346,15 @@ class CourseSign extends SoftDeletesModel
'禾裕集团', '苏州科服', '信诚管理咨询',
'集成电路公司', '常州团队', '国企元禾'
];
$list = Company::whereHas('users', function ($query) use ($courseSignByType, $companyNameKeyword) {
$query->whereIn('id', $courseSignByType->pluck('user_id'));
})->where(function ($query) use ($companyNameKeyword) {
$company = Company::where(function ($query) use ($companyNameKeyword) {
foreach ($companyNameKeyword as $item) {
$query->orWhere('company_name', 'like', '%' . $item . '%');
}
})->get();
$list = User::whereIn('id', $courseSignByType->pluck('user_id'))
->whereIn('company_id', $company->pluck('id'))
->get();
if ($retList) {
// 返回列表
return $list;
@ -317,7 +376,7 @@ class CourseSign extends SoftDeletesModel
{
$courseSignsQuery = self::getStudentList($start_date, $end_date, 1, $course_ids);
$courseSigns = $courseSignsQuery->whereHas('user', function ($query) {
$query->where('from', '跟班学员');
$query->where('from', 'like', '%跟班学员%');
})->get();
if ($retList) {
return User::with('company')->whereIn('id', $courseSigns->pluck('user_id'))->get();

@ -9,5 +9,10 @@ class HistoryCourse extends SoftDeletesModel
{
return $this->hasOne(CourseType::class, 'id', 'type');
}
public function calendar()
{
return $this->belongsTo(Calendar::class, 'calendar_id', 'id');
}
}

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('history_courses', function (Blueprint $table) {
$table->unsignedBigInteger('calendar_id')->nullable()->after('id')->comment('日历ID');
$table->index('calendar_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('history_courses', function (Blueprint $table) {
$table->dropIndex(['calendar_id']);
$table->dropColumn('calendar_id');
});
}
};

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('calendars', function (Blueprint $table) {
$table->tinyInteger('is_count_days')->nullable()->comment('是否统计天数 0否 1是');
$table->tinyInteger('is_count_people')->nullable()->comment('是否统计人数 0否 1是');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('calendars', function (Blueprint $table) {
$table->dropColumn(['is_count_days', 'is_count_people']);
});
}
};
Loading…
Cancel
Save