2
0

ProgressService.php 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. <?php
  2. namespace App\Services\V3;
  3. use App\Models\ProgressChapter;
  4. use Illuminate\Contracts\Pagination\LengthAwarePaginator;
  5. /**
  6. * 章节翻译进度的查询。
  7. *
  8. * v2 的 `ProgressChapterController` 另有一套实现(还带着 view= 开关),两边不共用——
  9. * 见 CLAUDE.md 铁律 2:契约相关的逻辑 v3 重写,不为共享去改 v2。
  10. */
  11. class ProgressService
  12. {
  13. /**
  14. * 取出的列。progress_chapters 还有 summary / uid / completed_chapters 等,
  15. * 接口不返回就不查。
  16. *
  17. * @var list<string>
  18. */
  19. private const COLUMNS = [
  20. 'progress_chapters.book',
  21. 'progress_chapters.para',
  22. 'progress_chapters.lang',
  23. 'progress_chapters.progress',
  24. 'progress_chapters.channel_id',
  25. 'progress_chapters.title',
  26. 'progress_chapters.last_chapter_completed_at',
  27. 'progress_chapters.completed_at',
  28. 'progress_chapters.updated_at',
  29. ];
  30. /**
  31. * 按 channel 列出章节进度。
  32. *
  33. * @param array<string, mixed> $filters 已经过 FormRequest 校验的查询参数
  34. * @return LengthAwarePaginator<int, ProgressChapter>
  35. */
  36. public function chapters(array $filters): LengthAwarePaginator
  37. {
  38. $query = ProgressChapter::query()
  39. ->select(self::COLUMNS)
  40. // channels 是下划线分隔的 uid 列表,既有契约
  41. ->whereIn('progress_chapters.channel_id', explode('_', (string) $filters['channels']));
  42. if (isset($filters['level'])) {
  43. // 只要该层级及以上的章节,层级在 pali_texts 上
  44. $query->join('pali_texts', function ($join) {
  45. $join->on('progress_chapters.book', '=', 'pali_texts.book')
  46. ->on('progress_chapters.para', '=', 'pali_texts.paragraph');
  47. })->where('pali_texts.level', '<=', (int) $filters['level']);
  48. }
  49. if (isset($filters['lang'])) {
  50. $query->where('progress_chapters.lang', $filters['lang']);
  51. }
  52. if (isset($filters['book'])) {
  53. $query->where('progress_chapters.book', $filters['book']);
  54. }
  55. // order 已由 FormRequest 的白名单校验过,拼进列名是安全的
  56. $query->orderBy(
  57. 'progress_chapters.'.($filters['order'] ?? 'completed_at'),
  58. $filters['dir'] ?? 'desc'
  59. );
  60. return $query->paginate($filters['per_page'] ?? 10);
  61. }
  62. }