diff --git a/app/Exports/CommonExport.php b/app/Exports/CommonExport.php index b7f9104..cac9453 100755 --- a/app/Exports/CommonExport.php +++ b/app/Exports/CommonExport.php @@ -292,6 +292,16 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $endCol = $this->getColumnLetter($index + count(self::USERS_SUB_COLUMNS) - 1); $sheet->mergeCells("{$startCol}1:{$endCol}1"); $sheet->setCellValue("{$startCol}1", $label); + + // 确保第二行表头正确设置所有子列(包括缺失的列) + $subIndex = 0; + foreach (self::USERS_SUB_COLUMNS as $subField => $subLabel) { + $col = $this->getColumnLetter($index + $subIndex); + // 直接设置第二行表头,确保所有列都有值 + $sheet->setCellValue("{$col}2", $subLabel); + $subIndex++; + } + $index += count(self::USERS_SUB_COLUMNS); } elseif (str_contains($field, 'project_users')) { // 项目经理信息列:合并第一行的多个单元格 @@ -299,6 +309,15 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $endCol = $this->getColumnLetter($index + count(self::PROJECT_USERS_SUB_COLUMNS) - 1); $sheet->mergeCells("{$startCol}1:{$endCol}1"); $sheet->setCellValue("{$startCol}1", $label); + + // 确保第二行表头正确设置所有子列 + $subIndex = 0; + foreach (self::PROJECT_USERS_SUB_COLUMNS as $subField => $subLabel) { + $col = $this->getColumnLetter($index + $subIndex); + $sheet->setCellValue("{$col}2", $subLabel); + $subIndex++; + } + $index += count(self::PROJECT_USERS_SUB_COLUMNS); } elseif (str_contains($field, 'history_courses')) { // 历史课程信息列:合并第一行的多个单元格 @@ -306,6 +325,15 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $endCol = $this->getColumnLetter($index + count(self::HISTORY_COURSES_SUB_COLUMNS) - 1); $sheet->mergeCells("{$startCol}1:{$endCol}1"); $sheet->setCellValue("{$startCol}1", $label); + + // 确保第二行表头正确设置所有子列 + $subIndex = 0; + foreach (self::HISTORY_COURSES_SUB_COLUMNS as $subField => $subLabel) { + $col = $this->getColumnLetter($index + $subIndex); + $sheet->setCellValue("{$col}2", $subLabel); + $subIndex++; + } + $index += count(self::HISTORY_COURSES_SUB_COLUMNS); } else { // 其他列:合并第一行和第二行 diff --git a/app/Http/Controllers/Admin/CompanyController.php b/app/Http/Controllers/Admin/CompanyController.php index 3251dda..3738eb6 100644 --- a/app/Http/Controllers/Admin/CompanyController.php +++ b/app/Http/Controllers/Admin/CompanyController.php @@ -226,11 +226,16 @@ class CompanyController extends BaseController } })->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc'); if (isset($all['is_export']) && !empty($all['is_export'])) { - $list = $list->get()->toArray(); + $list = $list->get(); + // 为每个公司添加"是否校友企业"字段(导出时,在模型对象上添加) + $this->addIsSchoolmateCompanyFieldToModels($list); + $list = $list->toArray(); return Excel::download(new CommonExport($list, $all['export_fields'] ?? ''), $all['file_name'] ?? '' . date('YmdHis') . '.xlsx'); } else { // 输出 $list = $list->paginate($all['page_size'] ?? 20); + // 为每个公司添加"是否校友企业"字段(在模型对象上添加) + $this->addIsSchoolmateCompanyFieldToModels($list->items()); } // 计算统计数据(如果提供了开始和结束年份) @@ -398,4 +403,65 @@ class CompanyController extends BaseController return parent::destroy(); } + /** + * 为公司模型集合添加"是否校友企业"字段 + * @param array|\Illuminate\Support\Collection $companies 公司模型集合 + */ + private function addIsSchoolmateCompanyFieldToModels($companies) + { + foreach ($companies as $company) { + if (!is_object($company)) { + continue; + } + $isSchoolmateCompany = '否'; + // 获取关联的 users(确保关联已加载) + if ($company->relationLoaded('users')) { + $users = $company->users; + if ($users && (is_array($users) || $users instanceof \Illuminate\Support\Collection)) { + // 检查该企业下的用户中是否有校友(is_schoolmate = 1) + foreach ($users as $user) { + $isSchoolmate = is_object($user) ? ($user->is_schoolmate ?? 0) : ($user['is_schoolmate'] ?? 0); + if ($isSchoolmate == 1) { + $isSchoolmateCompany = '是'; + break; + } + } + } + } else { + // 如果关联未加载,尝试直接查询 + $hasSchoolmate = \App\Models\User::where('company_id', $company->id) + ->where('is_schoolmate', 1) + ->exists(); + $isSchoolmateCompany = $hasSchoolmate ? '是' : '否'; + } + // 使用 setAttribute 确保属性被正确设置 + $company->setAttribute('is_schoolmate_company', $isSchoolmateCompany); + } + } + + /** + * 为公司数组添加"是否校友企业"字段(用于数组数据) + * @param array $companies 公司数组(引用传递) + */ + private function addIsSchoolmateCompanyField(&$companies) + { + foreach ($companies as &$company) { + if (!is_array($company)) { + continue; + } + $isSchoolmateCompany = '否'; + if (isset($company['users']) && is_array($company['users'])) { + // 检查该企业下的用户中是否有校友(is_schoolmate = 1) + foreach ($company['users'] as $user) { + if (isset($user['is_schoolmate']) && $user['is_schoolmate'] == 1) { + $isSchoolmateCompany = '是'; + break; + } + } + } + $company['is_schoolmate_company'] = $isSchoolmateCompany; + } + unset($company); // 释放引用 + } + } diff --git a/app/Http/Controllers/Admin/OtherController.php b/app/Http/Controllers/Admin/OtherController.php index 6f2866c..8d981a6 100755 --- a/app/Http/Controllers/Admin/OtherController.php +++ b/app/Http/Controllers/Admin/OtherController.php @@ -746,6 +746,8 @@ class OtherController extends CommonController 'user_name' => '', 'course_name' => '', 'course_type' => '', + 'course_types' => '', + 'course_count' => 0, ]); } else { // 每个学员一行,多个课程合并显示 @@ -766,12 +768,25 @@ class OtherController extends CommonController } $courseDisplay = implode("\r\n", $courseList); + // 获取课程体系列表,用中文顿号分隔 + $courseTypes = collect($courses) + ->pluck('course_type') + ->filter() + ->unique() + ->values() + ->implode('、'); + + // 报名课程数 + $courseCount = count($courses); + if ($isFirstRow) { // 第一行:显示公司信息 $data[] = array_merge($companyInfo, [ 'user_name' => $userInfo['user_name'] ?? '', 'course_name' => $courseDisplay, 'course_type' => '', // 课程类型已合并到课程名称中 + 'course_types' => $courseTypes, + 'course_count' => $courseCount, ]); $isFirstRow = false; } else { @@ -787,6 +802,8 @@ class OtherController extends CommonController 'company_tag' => '', 'user_name' => $userInfo['user_name'] ?? '', 'course_name' => $courseDisplay, + 'course_types' => $courseTypes, + 'course_count' => $courseCount, ]; } } @@ -803,6 +820,8 @@ class OtherController extends CommonController 'company_tag' => '企业资质', 'user_name' => '学员姓名', 'course_name' => '课程信息', + 'course_types' => '课程体系', + 'course_count' => '报名课程数', ]; $filename = '上市公司明细'; break; @@ -811,6 +830,43 @@ class OtherController extends CommonController // 跟班学员明细 - 使用模型方法 $users = CourseSign::genban($start_date, $end_date, $course_ids, true); foreach ($users as $user) { + // 获取该学员的课程报名记录 + $userCourseSigns = CourseSign::where(function ($query) use ($course_ids) { + // status = 1 + $query->where('status', 1); + // course_ids筛选 + if ($course_ids && $course_ids->isNotEmpty()) { + $query->whereIn('course_id', $course_ids); + } + }) + ->whereHas('course', function ($query) use ($start_date, $end_date) { + $query->where('is_chart', 1); + // 开始结束日期的筛选。or查询 + if ($start_date && $end_date) { + $query->where(function ($q) use ($start_date, $end_date) { + $q->whereBetween('start_date', [$start_date, $end_date]) + ->orWhereBetween('end_date', [$start_date, $end_date]); + }); + } + }) + ->whereNotIn('status', [4, 5, 6]) + ->where('user_id', $user->id) + ->with(['course.typeDetail']) + ->get(); + + // 获取课程名称列表,用中文顿号分隔 + $courseNames = $userCourseSigns->pluck('course.name')->filter()->unique()->values()->implode('、'); + + // 获取课程体系列表,用中文顿号分隔 + $courseTypes = $userCourseSigns->pluck('course.typeDetail.name') + ->filter() + ->unique() + ->values() + ->implode('、'); + + // 报名课程数 + $courseCount = $userCourseSigns->count(); + $data[] = [ 'name' => $user->username ?? '', 'sex' => $user->sex ?? '', @@ -818,6 +874,9 @@ class OtherController extends CommonController 'company_name' => $user->company_name ?? '', 'company_position' => $user->company_position ?? '', 'from' => $user->from ?? '', + 'course_names' => $courseNames, + 'course_types' => $courseTypes, + 'course_count' => $courseCount, ]; } $fields = [ @@ -827,6 +886,9 @@ class OtherController extends CommonController 'company_name' => '企业名称', 'company_position' => '职位', 'from' => '标签', + 'course_names' => '课程名称', + 'course_types' => '课程体系', + 'course_count' => '报名课程数', ]; $filename = '跟班学员明细'; break; @@ -1129,10 +1191,31 @@ class OtherController extends CommonController case 'company_join_total': // 元和员工参与人员明细 - 使用模型方法(现在返回的是用户列表) - $users = CourseSign::companyJoin($start_date, $end_date, $course_ids, true, false); + // 注意:第5个参数 $needHistory 需要与 coursesHome 方法保持一致(true) + $users = CourseSign::companyJoin($start_date, $end_date, $course_ids, true, true); // 加载关联关系 $users->load('company'); foreach ($users as $user) { + // 获取该学员的课程报名记录 + // 使用与 companyJoin 方法完全相同的 getStudentList 逻辑,确保数据一致 + $userCourseSigns = CourseSign::getStudentList($start_date, $end_date, null, $course_ids) + ->where('user_id', $user->id) + ->with(['course.typeDetail']) + ->get(); + + // 获取课程名称列表,用中文顿号分隔 + $courseNames = $userCourseSigns->pluck('course.name')->filter()->unique()->values()->implode('、'); + + // 获取课程体系列表,用中文顿号分隔 + $courseTypes = $userCourseSigns->pluck('course.typeDetail.name') + ->filter() + ->unique() + ->values() + ->implode('、'); + + // 报名课程数 + $courseCount = $userCourseSigns->count(); + $data[] = [ 'user_name' => $user->name ?? '', 'mobile' => $user->mobile ?? '', @@ -1143,6 +1226,9 @@ class OtherController extends CommonController 'company_legal_representative' => $user->company->company_legal_representative ?? '', 'company_date' => $user->company->company_date ?? '', 'company_address' => $user->company->company_address ?? '', + 'course_names' => $courseNames, + 'course_types' => $courseTypes, + 'course_count' => $courseCount, ]; } $fields = [ @@ -1155,6 +1241,9 @@ class OtherController extends CommonController 'company_legal_representative' => '法人', 'company_date' => '成立时间', 'company_address' => '地址', + 'course_names' => '课程名称', + 'course_types' => '课程体系', + 'course_count' => '报名课程数', ]; $filename = '元和员工参与企业明细'; break; diff --git a/quick-commit.sh b/quick-commit.sh new file mode 100755 index 0000000..dc740c3 --- /dev/null +++ b/quick-commit.sh @@ -0,0 +1,286 @@ +#!/bin/bash + +# 快速 Git 提交脚本 +# 自动执行 git add . git commit -m 'update' git push +# 自动输入密码: Git@2018 + +PASSWORD="Git@2018" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# 查找所有 Git 仓库 +find_git_repos() { + local current_dir="$1" + local repos=() + + # 查找所有 .git 目录(包括当前目录和子目录,最多搜索 3 层深度) + while IFS= read -r -d '' git_dir; do + # 获取仓库根目录(去掉 .git 部分) + repo_path=$(dirname "$git_dir") + # 标准化路径(去除相对路径符号) + repo_path=$(cd "$repo_path" && pwd) + repos+=("$repo_path") + done < <(find "$current_dir" -maxdepth 3 -type d -name ".git" -print0 2>/dev/null) + + # 去重并排序 + printf '%s\n' "${repos[@]}" | sort -u +} + +# 执行 Git 操作的函数 +execute_git_operations() { + local repo_path="$1" + + echo "" + echo "==========================================" + echo "正在处理仓库: $repo_path" + echo "==========================================" + echo "" + + # 切换到仓库目录 + cd "$repo_path" || { + echo "错误: 无法切换到目录 $repo_path" + return 1 + } + + # 执行 git add . + echo "执行: git add ." + git add . + + if [ $? -ne 0 ]; then + echo "错误: git add 失败" + return 1 + fi + + # 执行 git commit + echo "执行: git commit -m 'update'" + git commit -m 'update' + + if [ $? -ne 0 ]; then + echo "警告: git commit 可能没有新的更改需要提交" + fi + + # 检查是否有 expect 命令 + if ! command -v expect &> /dev/null; then + echo "" + echo "错误: 未找到 expect 命令" + echo "请先安装 expect: brew install expect" + echo "" + echo "或者手动执行: git push" + return 1 + fi + + # 获取所有远程仓库 + local remotes=($(git remote)) + + if [ ${#remotes[@]} -eq 0 ]; then + echo "" + echo "警告: 当前仓库没有配置远程仓库,跳过 push" + return 0 + fi + + # 获取当前分支名 + local current_branch=$(git branch --show-current) + if [ -z "$current_branch" ]; then + current_branch="master" + fi + + # 选择远程仓库 + local selected_remote="" + if [ ${#remotes[@]} -eq 1 ]; then + # 只有一个远程仓库,直接使用 + selected_remote="${remotes[0]}" + echo "" + echo "检测到 1 个远程仓库: $selected_remote" + else + # 多个远程仓库,让用户选择 + echo "" + echo "检测到 ${#remotes[@]} 个远程仓库:" + echo "" + for i in "${!remotes[@]}"; do + local_index=$((i + 1)) + local remote_url=$(git remote get-url "${remotes[$i]}") + echo " [$local_index] ${remotes[$i]} ($remote_url)" + done + echo "" + + # 读取用户选择 + while true; do + read -p "请选择要推送的远程仓库编号 (1-${#remotes[@]}): " choice + + # 检查输入是否为数字 + if ! [[ "$choice" =~ ^[0-9]+$ ]]; then + echo "错误: 请输入有效的数字" + continue + fi + + # 处理选择 + if [ "$choice" -ge 1 ] && [ "$choice" -le ${#remotes[@]} ]; then + selected_remote="${remotes[$((choice - 1))]}" + break + else + echo "错误: 请输入 1-${#remotes[@]} 之间的数字" + fi + done + fi + + # 执行 git push 的函数 + do_git_push() { + local password="$1" + local remote="$2" + local branch="$3" + local temp_output=$(mktemp) + local push_failed=0 + + # 使用 tee 同时输出到终端和文件,以便后续检查错误 + expect << EOF 2>&1 | tee "$temp_output" +set timeout 30 +spawn git push $remote $branch +expect { + "Password:" { + send "$password\r" + exp_continue + } + "password:" { + send "$password\r" + exp_continue + } + "passphrase:" { + send "$password\r" + exp_continue + } + "Username:" { + exp_continue + } + "Authentication failed" { + set push_failed 1 + exp_continue + } + "Permission denied" { + set push_failed 1 + exp_continue + } + eof { + catch wait result + set exit_code [lindex \$result 3] + if {\$exit_code != 0} { + set push_failed 1 + } + exit \$exit_code + } + timeout { + set push_failed 1 + exit 1 + } +} +EOF + + local exit_code=$? + local output=$(cat "$temp_output" 2>/dev/null) + rm -f "$temp_output" + + # 检查退出码和输出中的错误信息 + if [ $exit_code -ne 0 ]; then + return 1 + fi + + # 检查输出中是否包含认证失败相关的错误 + if echo "$output" | grep -qiE "(Authentication failed|Permission denied|fatal:.*authentication|error:.*authentication)"; then + return 1 + fi + + return 0 + } + + # 首先尝试使用默认密码 + echo "" + echo "执行: git push $selected_remote $current_branch (使用默认密码)" + if do_git_push "$PASSWORD" "$selected_remote" "$current_branch"; then + echo "" + echo "✅ 仓库 $repo_path 提交完成!" + else + # 默认密码失败,提示用户输入密码 + echo "" + echo "⚠️ 默认密码 push 失败,请手动输入密码" + echo "" + read -sp "请输入 Git 密码: " user_password + echo "" + echo "" + echo "使用您输入的密码重新执行: git push $selected_remote $current_branch" + + if do_git_push "$user_password" "$selected_remote" "$current_branch"; then + echo "" + echo "✅ 仓库 $repo_path 提交完成!" + else + echo "" + echo "❌ 仓库 $repo_path push 失败,请检查密码和网络连接" + fi + fi + + echo "" +} + +# 主程序 +echo "开始执行 Git 快速提交..." +echo "" + +# 查找所有 Git 仓库 +echo "正在查找 Git 仓库..." +repos=($(find_git_repos "$SCRIPT_DIR")) + +if [ ${#repos[@]} -eq 0 ]; then + echo "错误: 未找到任何 Git 仓库" + exit 1 +fi + +# 如果只有一个仓库,直接执行 +if [ ${#repos[@]} -eq 1 ]; then + echo "找到 1 个 Git 仓库:" + echo " [1] ${repos[0]}" + echo "" + execute_git_operations "${repos[0]}" +else + # 多个仓库,让用户选择 + echo "找到 ${#repos[@]} 个 Git 仓库:" + echo "" + for i in "${!repos[@]}"; do + local_index=$((i + 1)) + echo " [$local_index] ${repos[$i]}" + done + echo "" + echo " [0] 全部执行" + echo "" + + # 读取用户选择 + while true; do + read -p "请选择要操作的仓库编号 (0-${#repos[@]}): " choice + + # 检查输入是否为数字 + if ! [[ "$choice" =~ ^[0-9]+$ ]]; then + echo "错误: 请输入有效的数字" + continue + fi + + # 处理选择 + if [ "$choice" -eq 0 ]; then + # 全部执行 + echo "" + echo "将执行所有仓库的操作..." + for repo in "${repos[@]}"; do + execute_git_operations "$repo" + done + break + elif [ "$choice" -ge 1 ] && [ "$choice" -le ${#repos[@]} ]; then + # 执行选中的仓库 + selected_repo="${repos[$((choice - 1))]}" + execute_git_operations "$selected_repo" + break + else + echo "错误: 请输入 0-${#repos[@]} 之间的数字" + fi + done +fi + +echo "" +echo "==========================================" +echo "所有操作完成!" +echo "==========================================" +