| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- <?php
- namespace App\Http\Controllers\Api;
- use App\Http\Controllers\Controller;
- use App\Services\TextbookApiService;
- use Illuminate\Http\Request;
- use Illuminate\Http\JsonResponse;
- use Illuminate\Support\Facades\Log;
- class TextbookApiController extends Controller
- {
- protected TextbookApiService $textbookService;
- public function __construct(TextbookApiService $textbookService)
- {
- $this->textbookService = $textbookService;
- }
- /**
- * 获取教材列表(按年级排序)
- *
- * @param Request $request
- * @return JsonResponse
- */
- public function index(Request $request): JsonResponse
- {
- try {
- $params = [
- 'page' => $request->get('page', 1),
- 'per_page' => $request->get('per_page', 50),
- ];
- // 可选过滤参数
- if ($request->has('grade')) {
- $params['grade'] = $request->get('grade');
- }
- if ($request->has('stage')) {
- $params['stage'] = $this->convertStageToCode($request->get('stage'));
- }
- if ($request->has('semester')) {
- $params['semester'] = $this->convertSemesterToCode($request->get('semester'));
- }
- if ($request->has('series_id')) {
- $params['series_id'] = $request->get('series_id');
- }
- if ($request->has('status')) {
- $params['status'] = $request->get('status');
- }
- $result = $this->textbookService->getTextbooks($params);
- // 格式化返回数据
- $textbooks = $this->formatTextbookList($result['data'] ?? []);
- // 按年级排序
- usort($textbooks, function ($a, $b) {
- // 先按学段排序:小学 < 初中 < 高中
- $stageOrder = ['primary' => 1, 'junior' => 2, 'senior' => 3];
- $stageA = $stageOrder[$a['stage_code']] ?? 99;
- $stageB = $stageOrder[$b['stage_code']] ?? 99;
- if ($stageA !== $stageB) {
- return $stageA - $stageB;
- }
- // 再按年级排序
- $gradeA = $a['grade'] ?? 0;
- $gradeB = $b['grade'] ?? 0;
- if ($gradeA !== $gradeB) {
- return $gradeA - $gradeB;
- }
- // 最后按学期排序
- $semesterA = $a['semester_code'] ?? 0;
- $semesterB = $b['semester_code'] ?? 0;
- return $semesterA - $semesterB;
- });
- return response()->json([
- 'success' => true,
- 'data' => $textbooks,
- 'meta' => $result['meta'] ?? [
- 'page' => $params['page'],
- 'per_page' => $params['per_page'],
- 'total' => count($textbooks),
- ]
- ]);
- } catch (\Exception $e) {
- Log::error('获取教材列表失败', ['error' => $e->getMessage()]);
- return response()->json([
- 'success' => false,
- 'message' => '获取教材列表失败: ' . $e->getMessage()
- ], 500);
- }
- }
- /**
- * 根据年级获取教材
- *
- * @param int $grade 年级(1-12)
- * @param Request $request
- * @return JsonResponse
- */
- public function getByGrade(int $grade, Request $request): JsonResponse
- {
- try {
- $schoolingSystem = (string) $request->get('schooling_system', '');
- $stageParam = $request->get('stage');
- $params = [
- 'grade' => $grade,
- 'per_page' => 100,
- ];
- if ($stageParam) {
- $params['stage'] = $this->convertStageToCode((string) $stageParam);
- } elseif ($schoolingSystem === '5-4') {
- $params['stage'] = $this->getStageByGrade($grade, $schoolingSystem);
- }
- if ($request->has('semester')) {
- $params['semester'] = $this->convertSemesterToCode($request->get('semester'));
- }
- if ($request->has('series_id')) {
- $params['series_id'] = $request->get('series_id');
- }
- $result = $this->textbookService->getTextbooks($params);
- $textbooks = $this->formatTextbookList($result['data'] ?? []);
- // 按学期排序
- usort($textbooks, function ($a, $b) {
- return ($a['semester_code'] ?? 0) - ($b['semester_code'] ?? 0);
- });
- return response()->json([
- 'success' => true,
- 'data' => $textbooks,
- 'meta' => [
- 'grade' => $grade,
- 'stage' => $params['stage'] ?? null,
- 'stage_label' => isset($params['stage']) ? $this->getStageLabel($params['stage']) : null,
- 'total' => count($textbooks),
- ]
- ]);
- } catch (\Exception $e) {
- Log::error('根据年级获取教材失败', [
- 'grade' => $grade,
- 'error' => $e->getMessage()
- ]);
- return response()->json([
- 'success' => false,
- 'message' => '获取教材失败: ' . $e->getMessage()
- ], 500);
- }
- }
- /**
- * 获取单个教材详情
- *
- * @param int $id 教材ID
- * @return JsonResponse
- */
- public function show(int $id): JsonResponse
- {
- try {
- $textbook = $this->textbookService->getTextbook($id);
- if (!$textbook) {
- return response()->json([
- 'success' => false,
- 'message' => '教材不存在'
- ], 404);
- }
- return response()->json([
- 'success' => true,
- 'data' => $this->formatTextbook($textbook)
- ]);
- } catch (\Exception $e) {
- Log::error('获取教材详情失败', [
- 'id' => $id,
- 'error' => $e->getMessage()
- ]);
- return response()->json([
- 'success' => false,
- 'message' => '获取教材详情失败: ' . $e->getMessage()
- ], 500);
- }
- }
- /**
- * 获取教材系列列表
- *
- * @param Request $request
- * @return JsonResponse
- */
- public function getSeries(Request $request): JsonResponse
- {
- try {
- $params = [];
- if ($request->has('stage')) {
- $params['stage'] = $this->convertStageToCode($request->get('stage'));
- }
- $result = $this->textbookService->getTextbookSeries($params);
- $series = array_map(function ($item) {
- return [
- 'id' => $item['id'],
- 'name' => $item['name'],
- 'slug' => $item['slug'] ?? '',
- 'publisher' => $item['publisher'] ?? '',
- 'region' => $item['region'] ?? '全国',
- 'stages' => $this->formatStages($item['stages'] ?? '[]'),
- 'is_active' => $item['is_active'] ?? true,
- 'sort_order' => $item['sort_order'] ?? 0,
- ];
- }, $result['data'] ?? []);
- // 按排序字段排序
- usort($series, fn($a, $b) => ($a['sort_order'] ?? 0) - ($b['sort_order'] ?? 0));
- return response()->json([
- 'success' => true,
- 'data' => $series,
- 'meta' => [
- 'total' => count($series),
- ]
- ]);
- } catch (\Exception $e) {
- Log::error('获取教材系列失败', ['error' => $e->getMessage()]);
- return response()->json([
- 'success' => false,
- 'message' => '获取教材系列失败: ' . $e->getMessage()
- ], 500);
- }
- }
- /**
- * 年级枚举
- */
- public function getGradeEnums(): JsonResponse
- {
- $schoolingSystem = (string) request()->get('schooling_system', '');
- $grades = [];
- $primaryMax = $schoolingSystem === '5-4' ? 5 : 6;
- foreach (range(1, $primaryMax) as $grade) {
- $grades[] = [
- 'grade' => $grade,
- 'label' => $this->getGradeLabel($grade, 'primary'),
- 'stage' => 'primary',
- 'stage_label' => $this->getStageLabel('primary'),
- ];
- }
- $juniorStart = $schoolingSystem === '5-4' ? 6 : 7;
- foreach (range($juniorStart, 9) as $grade) {
- $grades[] = [
- 'grade' => $grade,
- 'label' => $this->getGradeLabel($grade, 'junior'),
- 'stage' => 'junior',
- 'stage_label' => $this->getStageLabel('junior'),
- ];
- }
- foreach (range(10, 12) as $grade) {
- $grades[] = [
- 'grade' => $grade,
- 'label' => $this->getGradeLabel($grade, 'senior'),
- 'stage' => 'senior',
- 'stage_label' => $this->getStageLabel('senior'),
- ];
- }
- return response()->json([
- 'success' => true,
- 'data' => $grades,
- ]);
- }
- /**
- * 获取教材目录
- *
- * @param int $textbookId 教材ID
- * @param Request $request
- * @return JsonResponse
- */
- public function getCatalog(int $textbookId, Request $request): JsonResponse
- {
- try {
- $format = $request->get('format', 'tree'); // tree 或 flat
- $catalog = $this->textbookService->getTextbookCatalog($textbookId, $format);
- return response()->json([
- 'success' => true,
- 'data' => $catalog,
- 'meta' => [
- 'textbook_id' => $textbookId,
- 'format' => $format,
- ]
- ]);
- } catch (\Exception $e) {
- Log::error('获取教材目录失败', [
- 'textbook_id' => $textbookId,
- 'error' => $e->getMessage()
- ]);
- return response()->json([
- 'success' => false,
- 'message' => '获取教材目录失败: ' . $e->getMessage()
- ], 500);
- }
- }
- /**
- * 格式化教材列表
- */
- private function formatTextbookList(array $textbooks): array
- {
- return array_map(fn($item) => $this->formatTextbook($item), $textbooks);
- }
- /**
- * 格式化单个教材
- */
- private function formatTextbook(array $textbook): array
- {
- $stage = $textbook['stage'] ?? '';
- $semester = $textbook['semester'] ?? null;
- return [
- 'id' => $textbook['id'],
- 'name' => $textbook['official_title'] ?? '',
- 'display_name' => $textbook['official_title'] ?? '',
- 'cover' => $this->formatCoverUrl($textbook['cover_path'] ?? ''),
- 'series_id' => $textbook['series_id'] ?? null,
- 'series_name' => $textbook['series']['name'] ?? '',
- 'publisher' => $textbook['series']['publisher'] ?? '',
- 'stage' => $this->getStageLabel($stage),
- 'stage_code' => $stage,
- 'grade' => $textbook['grade'] ?? null,
- 'grade_label' => $this->getGradeLabel($textbook['grade'] ?? null, $stage),
- 'semester' => $this->getSemesterLabel($semester),
- 'semester_code' => $semester,
- 'module_type' => $textbook['module_type'] ?? null,
- 'volume_no' => $textbook['volume_no'] ?? null,
- 'isbn' => $textbook['isbn'] ?? '',
- 'approval_year' => $textbook['approval_year'] ?? null,
- 'curriculum_standard_year' => $textbook['curriculum_standard_year'] ?? null,
- 'status' => $textbook['status'] ?? 'draft',
- 'sort_order' => $textbook['sort_order'] ?? 0,
- ];
- }
- /**
- * 格式化封面URL
- */
- private function formatCoverUrl(?string $coverPath): string
- {
- if (empty($coverPath)) {
- return '';
- }
- // 如果已经是完整URL,直接返回
- if (str_starts_with($coverPath, 'http://') || str_starts_with($coverPath, 'https://')) {
- return $coverPath;
- }
- // 本地存储路径,添加域名
- return url('/storage/' . ltrim($coverPath, '/'));
- }
- /**
- * 学段代码转中文
- */
- private function getStageLabel(string $stage): string
- {
- return match ($stage) {
- 'primary' => '小学',
- 'junior' => '初中',
- 'senior' => '高中',
- default => $stage,
- };
- }
- /**
- * 中文学段转代码
- */
- private function convertStageToCode(string $stage): string
- {
- return match ($stage) {
- '小学' => 'primary',
- '初中' => 'junior',
- '高中' => 'senior',
- default => $stage,
- };
- }
- /**
- * 学期代码转中文
- */
- private function getSemesterLabel(?int $semester): string
- {
- return match ($semester) {
- 1 => '上册',
- 2 => '下册',
- default => '',
- };
- }
- /**
- * 中文学期转代码
- */
- private function convertSemesterToCode(string $semester): ?int
- {
- return match ($semester) {
- '上册', '1' => 1,
- '下册', '2' => 2,
- default => null,
- };
- }
- /**
- * 年级标签
- */
- private function getGradeLabel(?int $grade, string $stage): string
- {
- if ($grade === null) {
- return '';
- }
- return match ($stage) {
- 'primary' => $grade . '年级',
- 'junior' => match ($grade) {
- 7 => '七年级',
- 8 => '八年级',
- 9 => '九年级',
- default => $grade . '年级',
- },
- 'senior' => match ($grade) {
- 10 => '高一',
- 11 => '高二',
- 12 => '高三',
- default => '高' . ($grade - 9),
- },
- default => $grade . '年级',
- };
- }
- /**
- * 根据年级判断学段
- */
- private function getStageByGrade(int $grade, string $schoolingSystem = ''): string
- {
- if ($schoolingSystem === '5-4') {
- if ($grade >= 1 && $grade <= 5) {
- return 'primary';
- }
- if ($grade >= 6 && $grade <= 9) {
- return 'junior';
- }
- }
- if ($grade >= 1 && $grade <= 6) {
- return 'primary';
- } elseif ($grade >= 7 && $grade <= 9) {
- return 'junior';
- } else {
- return 'senior';
- }
- }
- /**
- * 格式化学段数组
- */
- private function formatStages($stages): array
- {
- if (is_string($stages)) {
- $stages = json_decode($stages, true) ?? [];
- }
- if (!is_array($stages)) {
- return [];
- }
- return array_map(fn($s) => [
- 'code' => $s,
- 'label' => $this->getStageLabel($s),
- ], $stages);
- }
- }
|