|
@@ -4,19 +4,15 @@ namespace App\Filament\Resources\TextbookResource\Pages;
|
|
|
|
|
|
|
|
use App\Filament\Resources\TextbookResource;
|
|
use App\Filament\Resources\TextbookResource;
|
|
|
use App\Services\TextbookApiService;
|
|
use App\Services\TextbookApiService;
|
|
|
-use App\Services\TextbookCoverStorageService;
|
|
|
|
|
-use App\Models\Textbook;
|
|
|
|
|
use Filament\Forms;
|
|
use Filament\Forms;
|
|
|
use Filament\Actions;
|
|
use Filament\Actions;
|
|
|
use Filament\Schemas\Components\Section;
|
|
use Filament\Schemas\Components\Section;
|
|
|
use Filament\Resources\Pages\Page;
|
|
use Filament\Resources\Pages\Page;
|
|
|
-use Illuminate\Http\Request;
|
|
|
|
|
-use Livewire\WithFileUploads;
|
|
|
|
|
|
|
+use Throwable;
|
|
|
|
|
|
|
|
class EditTextbook extends Page implements Forms\Contracts\HasForms
|
|
class EditTextbook extends Page implements Forms\Contracts\HasForms
|
|
|
{
|
|
{
|
|
|
use Forms\Concerns\InteractsWithForms;
|
|
use Forms\Concerns\InteractsWithForms;
|
|
|
- use WithFileUploads;
|
|
|
|
|
|
|
|
|
|
protected static string $resource = TextbookResource::class;
|
|
protected static string $resource = TextbookResource::class;
|
|
|
|
|
|
|
@@ -24,12 +20,11 @@ class EditTextbook extends Page implements Forms\Contracts\HasForms
|
|
|
|
|
|
|
|
public ?int $recordId = null;
|
|
public ?int $recordId = null;
|
|
|
|
|
|
|
|
- public function mount(Request $request): void
|
|
|
|
|
|
|
+ public function mount(int|string $record): void
|
|
|
{
|
|
{
|
|
|
- // 从路由参数获取教材ID,避免Livewire的隐式绑定
|
|
|
|
|
- $this->recordId = (int) $request->route('record');
|
|
|
|
|
|
|
+ $this->recordId = (int) $record;
|
|
|
|
|
|
|
|
- if (!$this->recordId) {
|
|
|
|
|
|
|
+ if ($this->recordId <= 0) {
|
|
|
abort(404);
|
|
abort(404);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -41,49 +36,58 @@ class EditTextbook extends Page implements Forms\Contracts\HasForms
|
|
|
abort(404);
|
|
abort(404);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 初始化表单数据
|
|
|
|
|
$this->data = $textbookData;
|
|
$this->data = $textbookData;
|
|
|
$this->form->fill($this->data);
|
|
$this->form->fill($this->data);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function save(): void
|
|
public function save(): void
|
|
|
{
|
|
{
|
|
|
- // 验证数据
|
|
|
|
|
- $this->validate([
|
|
|
|
|
- 'data.series_id' => 'required|integer',
|
|
|
|
|
- 'data.stage' => 'required|string',
|
|
|
|
|
- 'data.grade' => 'nullable|integer',
|
|
|
|
|
- 'data.semester' => 'nullable|integer',
|
|
|
|
|
- 'data.official_title' => 'required|string|max:255',
|
|
|
|
|
- 'data.isbn' => 'nullable|string|max:255',
|
|
|
|
|
- 'data.status' => 'required|string|in:draft,published,archived',
|
|
|
|
|
- ]);
|
|
|
|
|
-
|
|
|
|
|
- // 只传递标量字段到API,跳过关系字段和嵌套对象
|
|
|
|
|
|
|
+ // 必须用 form->getState():会触发临时文件落盘/春笋 URL、再执行 dehydrateStateUsing 得到逗号串。
|
|
|
|
|
+ // 直接读 $this->data 会跳过上述步骤,导致「保存无效」且新图不会上传。
|
|
|
|
|
+ $data = $this->form->getState();
|
|
|
|
|
+
|
|
|
$allowedFields = [
|
|
$allowedFields = [
|
|
|
'series_id', 'stage', 'grade', 'semester', 'naming_scheme',
|
|
'series_id', 'stage', 'grade', 'semester', 'naming_scheme',
|
|
|
'track', 'module_type', 'volume_no', 'legacy_code',
|
|
'track', 'module_type', 'volume_no', 'legacy_code',
|
|
|
'curriculum_standard_year', 'curriculum_revision_year',
|
|
'curriculum_standard_year', 'curriculum_revision_year',
|
|
|
'approval_authority', 'approval_year', 'edition_label',
|
|
'approval_authority', 'approval_year', 'edition_label',
|
|
|
'official_title', 'aliases', 'isbn',
|
|
'official_title', 'aliases', 'isbn',
|
|
|
- 'cover_path', 'status', 'sort_order', 'meta'
|
|
|
|
|
|
|
+ 'status', 'sort_order', 'meta',
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
$updateData = [];
|
|
$updateData = [];
|
|
|
foreach ($allowedFields as $field) {
|
|
foreach ($allowedFields as $field) {
|
|
|
- if (isset($this->data[$field]) && !is_array($this->data[$field]) && !is_object($this->data[$field])) {
|
|
|
|
|
- $updateData[$field] = $this->data[$field];
|
|
|
|
|
|
|
+ if (! array_key_exists($field, $data)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $value = $data[$field];
|
|
|
|
|
+ if (is_array($value) || is_object($value)) {
|
|
|
|
|
+ continue;
|
|
|
}
|
|
}
|
|
|
|
|
+ $updateData[$field] = $value;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 调用API更新
|
|
|
|
|
- $apiService = app(TextbookApiService::class);
|
|
|
|
|
- $updatedData = $apiService->updateTextbook($this->recordId, $updateData);
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ $apiService = app(TextbookApiService::class);
|
|
|
|
|
+ $response = $apiService->updateTextbook($this->recordId, $updateData);
|
|
|
|
|
+ } catch (Throwable $e) {
|
|
|
|
|
+ \Filament\Notifications\Notification::make()
|
|
|
|
|
+ ->title('保存失败')
|
|
|
|
|
+ ->body($e->getMessage())
|
|
|
|
|
+ ->danger()
|
|
|
|
|
+ ->send();
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 更新本地数据
|
|
|
|
|
- $this->data = array_merge($this->data, $updatedData);
|
|
|
|
|
|
|
+ $row = $response['data'] ?? $response;
|
|
|
|
|
+ if (! is_array($row)) {
|
|
|
|
|
+ $row = [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $this->data = array_merge($this->data, $row);
|
|
|
|
|
+ $this->form->fill($this->data);
|
|
|
|
|
|
|
|
- // 显示成功消息
|
|
|
|
|
\Filament\Notifications\Notification::make()
|
|
\Filament\Notifications\Notification::make()
|
|
|
->title('教材更新成功')
|
|
->title('教材更新成功')
|
|
|
->success()
|
|
->success()
|
|
@@ -93,6 +97,10 @@ class EditTextbook extends Page implements Forms\Contracts\HasForms
|
|
|
protected function getHeaderActions(): array
|
|
protected function getHeaderActions(): array
|
|
|
{
|
|
{
|
|
|
return [
|
|
return [
|
|
|
|
|
+ Actions\Action::make('covers')
|
|
|
|
|
+ ->label('管理配图')
|
|
|
|
|
+ ->icon('heroicon-o-photo')
|
|
|
|
|
+ ->url(fn (): string => static::$resource::getUrl('covers', ['record' => $this->recordId])),
|
|
|
Actions\Action::make('back')
|
|
Actions\Action::make('back')
|
|
|
->label('返回列表')
|
|
->label('返回列表')
|
|
|
->url(static::$resource::getUrl('index'))
|
|
->url(static::$resource::getUrl('index'))
|
|
@@ -172,27 +180,6 @@ class EditTextbook extends Page implements Forms\Contracts\HasForms
|
|
|
->required(),
|
|
->required(),
|
|
|
])
|
|
])
|
|
|
->columns(2),
|
|
->columns(2),
|
|
|
- Section::make('封面上传')
|
|
|
|
|
- ->schema([
|
|
|
|
|
- Forms\Components\FileUpload::make('cover_path')
|
|
|
|
|
- ->label('封面图片')
|
|
|
|
|
- ->image()
|
|
|
|
|
- ->directory('textbook-covers')
|
|
|
|
|
- ->saveUploadedFileUsing(function ($component, $file) {
|
|
|
|
|
- $uploader = app(TextbookCoverStorageService::class);
|
|
|
|
|
- $url = $uploader->uploadCover($file, $this->recordId ? (string) $this->recordId : null);
|
|
|
|
|
- if ($url) {
|
|
|
|
|
- return $url;
|
|
|
|
|
- }
|
|
|
|
|
- return $file->storePubliclyAs(
|
|
|
|
|
- $component->getDirectory(),
|
|
|
|
|
- $component->getUploadedFileNameForStorage($file),
|
|
|
|
|
- $component->getDiskName(),
|
|
|
|
|
- );
|
|
|
|
|
- })
|
|
|
|
|
- ->helperText('建议尺寸 600x800,JPG/PNG'),
|
|
|
|
|
- ])
|
|
|
|
|
- ->extraAttributes(['id' => 'cover']),
|
|
|
|
|
])
|
|
])
|
|
|
->statePath('data');
|
|
->statePath('data');
|
|
|
}
|
|
}
|