question-review.blade.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <x-filament::page>
  2. @php
  3. $mineruBlocks = $mineru['blocks'] ?? [];
  4. $builderQuestions = $builder['questions'] ?? [];
  5. @endphp
  6. <div class="space-y-4">
  7. <x-filament::section>
  8. {{ $this->form }}
  9. @if($message)
  10. <div class="text-sm text-gray-600 mt-2">{{ $message }}</div>
  11. @endif
  12. </x-filament::section>
  13. <x-filament::section key="page-{{ $book }}-{{ $page }}">
  14. <div class="grid grid-cols-1 lg:grid-cols-2 gap-4 items-start">
  15. <div class="space-y-2 sticky top-4">
  16. <div class="flex items-center justify-between">
  17. <div>
  18. <h3 class="text-lg font-semibold">整页预览 (page {{ $page }})</h3>
  19. @if(!empty($paths))
  20. <div class="text-[11px] text-gray-500">builder: {{ $paths['builder_page'] ?? '' }}</div>
  21. @endif
  22. </div>
  23. <div class="text-xs text-gray-500">点击页码自动加载</div>
  24. </div>
  25. @if(!empty($pagePngBase64))
  26. @php
  27. $width = $mineru['width'] ?? 0;
  28. $height = $mineru['height'] ?? 0;
  29. $targetHeight = 820;
  30. $scale = ($height > 0) ? ($targetHeight / $height) : 0.28;
  31. $showWidth = $width ? $width * $scale : 520;
  32. $showHeight = $targetHeight;
  33. @endphp
  34. <div class="relative border rounded overflow-hidden bg-gray-100" style="max-width: 100%; height: {{ $showHeight }}px; width: {{ $showWidth }}px;">
  35. <img loading="lazy" src="data:image/png;base64,{{ $pagePngBase64 }}" style="height: 100%; width: auto; max-width: 100%; object-fit: contain;" />
  36. @if($showOverlay)
  37. @foreach($mineruBlocks as $b)
  38. @php
  39. $bbox = $b['bbox'] ?? [0,0,0,0];
  40. $x = $bbox[0] * $scale; $y = $bbox[1] * $scale;
  41. $w = ($bbox[2]-$bbox[0]) * $scale; $h = ($bbox[3]-$bbox[1]) * $scale;
  42. if ($w < 4 && $h < 4) continue;
  43. $color = 'rgba(59,130,246,0.25)';
  44. $type = strtolower($b['type'] ?? 'text');
  45. if($type === 'figure') $color = 'rgba(16,185,129,0.25)';
  46. if($type === 'table') $color = 'rgba(234,179,8,0.25)';
  47. if($type === 'formula') $color = 'rgba(239,68,68,0.25)';
  48. @endphp
  49. <div class="absolute border border-blue-500"
  50. style="pointer-events: none; left: {{ $x }}px; top: {{ $y }}px; width: {{ $w }}px; height: {{ $h }}px; background: {{ $color }};"
  51. title="{{ $b['type'] ?? '' }}">
  52. </div>
  53. @endforeach
  54. @endif
  55. </div>
  56. @else
  57. <div class="text-sm text-gray-500">无页面图片</div>
  58. @endif
  59. </div>
  60. <div class="space-y-2">
  61. <h3 class="text-lg font-semibold">生成题目({{ count($builderQuestions) }})</h3>
  62. <div class="h-[820px] overflow-auto text-sm bg-gray-50 rounded p-3 space-y-3">
  63. @foreach($builderQuestions as $idx => $q)
  64. <div class="border border-gray-200 rounded p-2 space-y-2">
  65. <div class="flex items-center justify-between">
  66. <div class="font-semibold">Q{{ $q['index'] ?? ($idx+1) }} ({{ $q['type'] ?? '' }})</div>
  67. <div class="flex items-center gap-2">
  68. @if(!empty($q['qa_flags']))
  69. <span class="text-xs text-amber-600">QA: {{ implode(',', $q['qa_flags']) }}</span>
  70. @endif
  71. <x-filament::button wire:click="saveQuestion({{ $idx }})" color="success" size="sm">加入草稿</x-filament::button>
  72. </div>
  73. </div>
  74. <div class="text-gray-800 text-sm">{{ $q['stem'] ?? '' }}</div>
  75. @if(!empty($q['options']))
  76. <div class="text-xs text-gray-700 space-y-1">
  77. @foreach($q['options'] as $k=>$v)
  78. <div>{{ $k }}. {{ $v }}</div>
  79. @endforeach
  80. </div>
  81. @endif
  82. @if(!empty($q['images']))
  83. <div class="flex flex-wrap gap-2">
  84. @foreach($q['images'] as $img)
  85. <div class="border rounded bg-white p-1 text-xs text-blue-700">
  86. {{ $img['path'] ?? 'img' }}
  87. </div>
  88. @endforeach
  89. </div>
  90. @endif
  91. <div class="text-[11px] text-gray-500">
  92. raw_blocks: {{ isset($q['raw_blocks']) ? json_encode($q['raw_blocks']) : '' }}
  93. </div>
  94. </div>
  95. @endforeach
  96. </div>
  97. </div>
  98. </div>
  99. </x-filament::section>
  100. @if($mineruBlocks)
  101. <x-filament::section>
  102. <details>
  103. <summary class="cursor-pointer font-semibold">MinerU Blocks({{ count($mineruBlocks) }})点击展开</summary>
  104. <div class="mt-2 max-h-[360px] overflow-auto text-xs bg-gray-50 rounded p-3 space-y-2">
  105. @foreach($mineruBlocks as $b)
  106. <div class="border border-gray-200 rounded p-2">
  107. <div class="font-semibold">{{ $b['type'] ?? 'text' }} / cat: {{ $b['category_id'] ?? '' }}</div>
  108. <div class="text-gray-600">bbox: {{ json_encode($b['bbox'] ?? []) }}</div>
  109. <div class="text-gray-600 truncate">text: {{ $b['text'] ?? ($b['content'] ?? '') }}</div>
  110. </div>
  111. @endforeach
  112. </div>
  113. </details>
  114. </x-filament::section>
  115. @endif
  116. @if($builder)
  117. <x-filament::section>
  118. <h3 class="text-lg font-semibold mb-2">整页题目 JSON(编辑后可“保存到草稿”)</h3>
  119. <textarea wire:model.defer="builderJson" class="w-full h-[720px] min-h-[720px] text-xs font-mono border rounded p-2 resize-y">{{ $builderJson }}</textarea>
  120. </x-filament::section>
  121. @endif
  122. </div>
  123. </x-filament::page>