EditTextbook.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace App\Filament\Resources\TextbookResource\Pages;
  3. use App\Filament\Resources\TextbookResource;
  4. use App\Services\TextbookApiService;
  5. use Filament\Forms;
  6. use Filament\Actions;
  7. use Filament\Schemas\Components\Section;
  8. use Filament\Resources\Pages\Page;
  9. use Throwable;
  10. class EditTextbook extends Page implements Forms\Contracts\HasForms
  11. {
  12. use Forms\Concerns\InteractsWithForms;
  13. protected static string $resource = TextbookResource::class;
  14. public array $data = [];
  15. public ?int $recordId = null;
  16. public function mount(int|string $record): void
  17. {
  18. $this->recordId = (int) $record;
  19. if ($this->recordId <= 0) {
  20. abort(404);
  21. }
  22. // 从API获取教材数据
  23. $apiService = app(TextbookApiService::class);
  24. $textbookData = $apiService->getTextbook($this->recordId);
  25. if (!$textbookData) {
  26. abort(404);
  27. }
  28. $this->data = $textbookData;
  29. $this->form->fill($this->data);
  30. }
  31. public function save(): void
  32. {
  33. // 必须用 form->getState():会触发临时文件落盘/春笋 URL、再执行 dehydrateStateUsing 得到逗号串。
  34. // 直接读 $this->data 会跳过上述步骤,导致「保存无效」且新图不会上传。
  35. $data = $this->form->getState();
  36. $allowedFields = [
  37. 'series_id', 'stage', 'grade', 'semester', 'naming_scheme',
  38. 'track', 'module_type', 'volume_no', 'legacy_code',
  39. 'curriculum_standard_year', 'curriculum_revision_year',
  40. 'approval_authority', 'approval_year', 'edition_label',
  41. 'official_title', 'aliases', 'isbn',
  42. 'status', 'sort_order', 'meta',
  43. ];
  44. $updateData = [];
  45. foreach ($allowedFields as $field) {
  46. if (! array_key_exists($field, $data)) {
  47. continue;
  48. }
  49. $value = $data[$field];
  50. if (is_array($value) || is_object($value)) {
  51. continue;
  52. }
  53. $updateData[$field] = $value;
  54. }
  55. try {
  56. $apiService = app(TextbookApiService::class);
  57. $response = $apiService->updateTextbook($this->recordId, $updateData);
  58. } catch (Throwable $e) {
  59. \Filament\Notifications\Notification::make()
  60. ->title('保存失败')
  61. ->body($e->getMessage())
  62. ->danger()
  63. ->send();
  64. return;
  65. }
  66. $row = $response['data'] ?? $response;
  67. if (! is_array($row)) {
  68. $row = [];
  69. }
  70. $this->data = array_merge($this->data, $row);
  71. $this->form->fill($this->data);
  72. \Filament\Notifications\Notification::make()
  73. ->title('教材更新成功')
  74. ->success()
  75. ->send();
  76. }
  77. protected function getHeaderActions(): array
  78. {
  79. return [
  80. Actions\Action::make('covers')
  81. ->label('管理配图')
  82. ->icon('heroicon-o-photo')
  83. ->url(fn (): string => static::$resource::getUrl('covers', ['record' => $this->recordId])),
  84. Actions\Action::make('back')
  85. ->label('返回列表')
  86. ->url(static::$resource::getUrl('index'))
  87. ->color('gray'),
  88. ];
  89. }
  90. public function getTitle(): string
  91. {
  92. return '编辑教材';
  93. }
  94. public function getView(): string
  95. {
  96. return 'filament.resources.textbook-resource.edit';
  97. }
  98. public function form(\Filament\Schemas\Schema $schema): \Filament\Schemas\Schema
  99. {
  100. return $schema
  101. ->schema([
  102. Section::make('基本信息')
  103. ->schema([
  104. Forms\Components\Select::make('series_id')
  105. ->label('教材系列')
  106. ->options(function () {
  107. $apiService = app(TextbookApiService::class);
  108. $series = $apiService->getTextbookSeries();
  109. $options = [];
  110. foreach ($series['data'] as $s) {
  111. $options[$s['id']] = $s['name'] ?? '未命名系列';
  112. }
  113. return $options;
  114. })
  115. ->required()
  116. ->searchable(),
  117. Forms\Components\Select::make('stage')
  118. ->label('学段')
  119. ->options([
  120. 'primary' => '小学',
  121. 'junior' => '初中',
  122. 'senior' => '高中',
  123. ])
  124. ->required()
  125. ->reactive(),
  126. Forms\Components\TextInput::make('grade')
  127. ->label('年级')
  128. ->numeric()
  129. ->helperText('例如:7表示七年级'),
  130. Forms\Components\Select::make('semester')
  131. ->label('学期')
  132. ->options([
  133. 1 => '上学期',
  134. 2 => '下学期',
  135. ])
  136. ->helperText('选择学期'),
  137. Forms\Components\TextInput::make('official_title')
  138. ->label('教材名称')
  139. ->required()
  140. ->maxLength(255),
  141. Forms\Components\TextInput::make('isbn')
  142. ->label('ISBN')
  143. ->maxLength(255),
  144. Forms\Components\Select::make('status')
  145. ->label('状态')
  146. ->options([
  147. 'draft' => '草稿',
  148. 'published' => '已发布',
  149. 'archived' => '已归档',
  150. ])
  151. ->required(),
  152. ])
  153. ->columns(2),
  154. ])
  155. ->statePath('data');
  156. }
  157. }