| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- <x-filament::page>
- <div class="space-y-4">
- @if(!$this->importRecord())
- <x-filament::section>
- @include('filament.partials.empty-state', [
- 'title' => '未选择导入记录',
- 'description' => '请先从 Markdown 导入列表进入工作台。',
- 'action' => new \Illuminate\Support\HtmlString('<a class="btn btn-primary btn-sm" href="' . route('filament.admin.resources.markdown-imports.index') . '">返回导入列表</a>'),
- ])
- </x-filament::section>
- @elseif(!$this->filenameValid)
- <x-filament::section>
- <div class="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
- 文件名解析失败:{{ $this->filenameWarning }}
- </div>
- <div class="mt-3 text-sm text-slate-600">
- 请在导入列表中修改文件名并重新导入后再进入工作台。
- </div>
- </x-filament::section>
- @else
- <div class="flex flex-wrap items-center gap-3">
- <x-filament::input.wrapper class="w-64">
- <x-filament::input wire:model.debounce.400ms="search" placeholder="搜索卷子标题/编码" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper class="w-44">
- <x-filament::input.select wire:model="groupBy">
- <option value="bundle">按套卷分组</option>
- <option value="paper">按卷子分组</option>
- <option value="grade">按年级分组</option>
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::button color="gray" wire:click="autoInfer">自动推断</x-filament::button>
- <x-filament::button color="gray" wire:click="autoInferSelected">批量推断</x-filament::button>
- <x-filament::button color="gray" wire:click="autoBundleKey">生成套卷标识</x-filament::button>
- <x-filament::button color="gray" wire:click="autoBundleKeySelected">批量生成套卷标识</x-filament::button>
- <x-filament::button color="primary" wire:click="savePaper">保存当前</x-filament::button>
- <x-filament::button color="gray" wire:click="$set('dense', ! $wire.dense)">密度切换</x-filament::button>
- </div>
- <div class="grid grid-cols-12 gap-6">
- <div class="col-span-8 space-y-4">
- <x-filament::section heading="导入信息">
- <div class="grid grid-cols-3 gap-4 text-sm text-slate-600">
- <div class="rounded-lg border border-slate-200 p-3">
- <div class="text-xs text-slate-500">导入文件</div>
- <div class="font-medium text-slate-800">{{ $this->importRecord()?->file_name ?? '未选择导入记录' }}</div>
- </div>
- <div class="rounded-lg border border-slate-200 p-3">
- <div class="text-xs text-slate-500">解析状态</div>
- <div class="font-medium text-slate-800">{{ $this->importRecord()?->status_label ?? '—' }}</div>
- </div>
- <div class="rounded-lg border border-slate-200 p-3">
- <div class="text-xs text-slate-500">候选题数</div>
- <div class="font-medium text-slate-800">{{ $this->importRecord()?->parsed_count ?? 0 }}</div>
- </div>
- </div>
- @if(!empty($this->filenameParsed))
- <div class="mt-3 flex flex-wrap gap-2 text-xs text-slate-500">
- <span class="ui-tag">系列:{{ $this->filenameParsed['series'] ?? '-' }}</span>
- <span class="ui-tag">年级:{{ $this->filenameParsed['grade'] ?? '-' }}</span>
- <span class="ui-tag">学期:{{ $this->filenameParsed['term'] ?? '-' }}</span>
- <span class="ui-tag">学科:{{ $this->filenameParsed['subject'] ?? '-' }}</span>
- <span class="ui-tag">名称:{{ $this->filenameParsed['name'] ?? '-' }}</span>
- </div>
- @endif
- </x-filament::section>
- <x-filament::section heading="卷子列表(选择后批量覆盖)">
- <div class="mb-2 flex flex-wrap gap-2">
- <x-filament::button color="gray" wire:click="selectAllVisible">全选当前列表</x-filament::button>
- <x-filament::button color="gray" wire:click="clearSelection">清空选择</x-filament::button>
- </div>
- <div class="max-h-72 overflow-y-auto divide-y divide-gray-100">
- @foreach($this->groupedPapers() as $group => $items)
- <div class="px-3 py-2 text-xs font-semibold text-slate-500 bg-slate-50">{{ $group }}</div>
- @foreach($items as $paper)
- @php
- $meta = $paper['meta'] ?? [];
- $expected = $meta['expected_count'] ?? null;
- $candidateCount = $paper['candidates_count'] ?? 0;
- @endphp
- <label class="flex items-start gap-3 {{ $dense ? 'py-1' : 'py-2' }}">
- <input type="checkbox" wire:model="selectedIds" value="{{ $paper['id'] }}" class="mt-1 rounded border-gray-300">
- <button type="button" wire:click="selectPaper({{ $paper['id'] }})" class="text-left flex-1">
- <div class="text-sm font-medium text-gray-900">{{ $paper['title'] ?? $paper['full_title'] ?? '未命名' }}</div>
- <div class="text-xs text-gray-500 flex flex-wrap gap-2 items-center">
- <span>年级 {{ $paper['grade'] ?? '-' }} · 学期 {{ $paper['term'] ?? '-' }}</span>
- <span>候选题数 {{ $candidateCount }}</span>
- @if($expected)
- <span class="{{ ((int) $expected) === (int) $candidateCount ? 'text-emerald-700 bg-emerald-50' : 'text-amber-700 bg-amber-50' }} px-2 py-0.5 rounded">
- 预期 {{ $expected }}
- </span>
- @endif
- @if(empty($paper['textbook_id']))
- <span class="px-2 py-0.5 rounded bg-rose-50 text-rose-700">未关联教材</span>
- @endif
- @if(empty($meta['catalog_node_id'] ?? null))
- <span class="px-2 py-0.5 rounded bg-rose-50 text-rose-700">未关联目录</span>
- @endif
- </div>
- </button>
- </label>
- @endforeach
- @endforeach
- @if($this->papers()->isEmpty())
- <div class="py-6 text-center text-sm text-gray-500">暂无卷子数据</div>
- @endif
- </div>
- </x-filament::section>
- <x-filament::section heading="卷子原始 Markdown">
- <div class="prose prose-sm max-w-none bg-gray-50 p-4 rounded-lg min-h-[240px]">
- @if($this->selectedPaper())
- {!! \App\Services\MathFormulaProcessor::processFormulas($this->selectedPaper()?->raw_markdown ?? '') !!}
- @else
- <div class="text-sm text-gray-400">暂无选中卷子</div>
- @endif
- </div>
- </x-filament::section>
- </div>
- <div class="col-span-4 space-y-4">
- <x-filament::section heading="卷子归属信息">
- @php
- $textbookSuggestions = $this->textbookSuggestions();
- $catalogSuggestions = $this->catalogSuggestions();
- $coverageSummary = $this->catalogCoverageSummary();
- $missingCatalogNodes = $this->missingCatalogNodes();
- @endphp
- <div class="space-y-3">
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.title" placeholder="卷子标题" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.bundle_key" placeholder="套卷标识(如:九年级上册·同步卷)" />
- </x-filament::input.wrapper>
- @if(!empty($textbookSuggestions))
- <div class="rounded-lg border border-slate-200 bg-slate-50 p-3 text-xs">
- <div class="font-semibold text-slate-600 mb-2">教材推荐</div>
- <div class="flex flex-col gap-2">
- @foreach($textbookSuggestions as $suggest)
- <button type="button" wire:click="applyTextbookSuggestion({{ $suggest['id'] }})" class="text-left rounded-md border border-slate-200 bg-white px-3 py-2 hover:border-primary-400">
- <div class="text-slate-800 font-medium">{{ $suggest['title'] }}</div>
- <div class="text-slate-500 mt-1">系列:{{ $suggest['series'] }} · 年级 {{ $suggest['grade'] ?? '-' }} · 学期 {{ $suggest['semester'] ?? '-' }}</div>
- </button>
- @endforeach
- </div>
- </div>
- @endif
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="form.grade">
- <option value="">年级</option>
- @foreach($this->gradeOptions() as $value => $label)
- <option value="{{ $value }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="form.term">
- <option value="">学期</option>
- @foreach($this->termOptions() as $value => $label)
- <option value="{{ $value }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.chapter" placeholder="章节" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="form.source_type">
- <option value="">卷子类型</option>
- @foreach($this->sourceTypeOptions() as $value => $label)
- <option value="{{ $value }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.source_year" placeholder="来源年份" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="form.textbook_id">
- <option value="">匹配教材</option>
- @foreach($this->textbookOptions() as $id => $title)
- <option value="{{ $id }}">{{ $title }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.textbook_series" placeholder="教材系列" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="form.catalog_node_id">
- <option value="">关联目录</option>
- @foreach($this->catalogOptions() as $id => $label)
- <option value="{{ $id }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- @if(!empty($catalogSuggestions))
- <div class="rounded-lg border border-slate-200 bg-slate-50 p-3 text-xs">
- <div class="font-semibold text-slate-600 mb-2">目录推荐</div>
- <div class="flex flex-col gap-2">
- @foreach($catalogSuggestions as $suggest)
- <button type="button" wire:click="applyCatalogSuggestion({{ $suggest['id'] }})" class="text-left rounded-md border border-slate-200 bg-white px-3 py-2 hover:border-primary-400">
- <div class="text-slate-800 font-medium">{{ $suggest['title'] }}</div>
- </button>
- @endforeach
- </div>
- </div>
- @endif
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.expected_count" placeholder="预期题量(如 24)" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.source_name" placeholder="来源名称" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.source_page" placeholder="页码范围" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="form.tags" placeholder="标签(逗号分隔)" />
- </x-filament::input.wrapper>
- </div>
- </x-filament::section>
- <x-filament::section heading="批量覆盖">
- <div class="text-xs text-gray-500 mb-2">对勾选卷子批量应用非空字段</div>
- <div class="space-y-2">
- <x-filament::input.wrapper>
- <x-filament::input wire:model="batch.bundle_key" placeholder="套卷标识" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="batch.grade">
- <option value="">年级</option>
- @foreach($this->gradeOptions() as $value => $label)
- <option value="{{ $value }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="batch.term">
- <option value="">学期</option>
- @foreach($this->termOptions() as $value => $label)
- <option value="{{ $value }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="batch.source_type">
- <option value="">卷子类型</option>
- @foreach($this->sourceTypeOptions() as $value => $label)
- <option value="{{ $value }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="batch.textbook_id">
- <option value="">匹配教材</option>
- @foreach($this->textbookOptions() as $id => $title)
- <option value="{{ $id }}">{{ $title }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input.select wire:model="batch.catalog_node_id">
- <option value="">关联目录</option>
- @foreach($this->catalogOptions() as $id => $label)
- <option value="{{ $id }}">{{ $label }}</option>
- @endforeach
- </x-filament::input.select>
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="batch.expected_count" placeholder="预期题量" />
- </x-filament::input.wrapper>
- <x-filament::input.wrapper>
- <x-filament::input wire:model="batch.tags" placeholder="标签(逗号分隔)" />
- </x-filament::input.wrapper>
- <x-filament::button color="gray" wire:click="seedBatchFromCurrent">以当前卷为默认</x-filament::button>
- <x-filament::button color="warning" x-on:click.prevent="if(confirm('确认对勾选卷子批量覆盖?')) { $wire.applyBatch() }">
- 批量覆盖
- </x-filament::button>
- </div>
- </x-filament::section>
- @if(!empty($coverageSummary))
- <x-filament::section heading="目录覆盖提示">
- <div class="text-xs text-slate-500 mb-2">
- 目录总数 {{ $coverageSummary['total'] }} · 已关联 {{ $coverageSummary['linked'] }} · 缺卷子目录 {{ $coverageSummary['missing'] }}
- </div>
- @if(!empty($missingCatalogNodes))
- <div class="space-y-2">
- @foreach($missingCatalogNodes as $node)
- <button type="button" wire:click="applyCatalogSuggestion({{ $node['id'] }})" class="text-left w-full rounded-lg border border-slate-200 bg-white px-3 py-2 hover:border-primary-400">
- <div class="text-sm text-slate-800">{{ $node['title'] }}</div>
- <div class="text-xs text-slate-500">点击绑定到当前卷子</div>
- </button>
- @endforeach
- </div>
- @else
- <div class="text-xs text-slate-500">暂无缺口目录</div>
- @endif
- </x-filament::section>
- @endif
- </div>
- </div>
- @endif
- </div>
- </x-filament::page>
|