EditTextbook.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. namespace App\Filament\Resources\TextbookResource\Pages;
  3. use App\Filament\Resources\TextbookResource;
  4. use App\Services\TextbookApiService;
  5. use App\Models\Textbook;
  6. use Filament\Forms;
  7. use Filament\Actions;
  8. use Filament\Resources\Pages\Page;
  9. use Illuminate\Http\Request;
  10. use Livewire\WithFileUploads;
  11. class EditTextbook extends Page implements Forms\Contracts\HasForms
  12. {
  13. use Forms\Concerns\InteractsWithForms;
  14. use WithFileUploads;
  15. protected static string $resource = TextbookResource::class;
  16. public array $data = [];
  17. public ?int $recordId = null;
  18. public function mount(Request $request): void
  19. {
  20. // 从路由参数获取教材ID,避免Livewire的隐式绑定
  21. $this->recordId = (int) $request->route('record');
  22. if (!$this->recordId) {
  23. abort(404);
  24. }
  25. // 从API获取教材数据
  26. $apiService = app(TextbookApiService::class);
  27. $textbookData = $apiService->getTextbook($this->recordId);
  28. if (!$textbookData) {
  29. abort(404);
  30. }
  31. // 初始化表单数据
  32. $this->data = $textbookData;
  33. $this->form->fill($this->data);
  34. }
  35. public function save(): void
  36. {
  37. // 验证数据
  38. $this->validate([
  39. 'data.series_id' => 'required|integer',
  40. 'data.stage' => 'required|string',
  41. 'data.grade' => 'nullable|integer',
  42. 'data.semester' => 'nullable|integer',
  43. 'data.official_title' => 'required|string|max:255',
  44. 'data.isbn' => 'nullable|string|max:255',
  45. 'data.status' => 'required|string|in:draft,published,archived',
  46. ]);
  47. // 只传递标量字段到API,跳过关系字段和嵌套对象
  48. $allowedFields = [
  49. 'series_id', 'stage', 'grade', 'semester', 'naming_scheme',
  50. 'track', 'module_type', 'volume_no', 'legacy_code',
  51. 'curriculum_standard_year', 'curriculum_revision_year',
  52. 'approval_authority', 'approval_year', 'edition_label',
  53. 'official_title', 'aliases', 'isbn',
  54. 'cover_path', 'status', 'sort_order', 'meta'
  55. ];
  56. $updateData = [];
  57. foreach ($allowedFields as $field) {
  58. if (isset($this->data[$field]) && !is_array($this->data[$field]) && !is_object($this->data[$field])) {
  59. $updateData[$field] = $this->data[$field];
  60. }
  61. }
  62. // 调用API更新
  63. $apiService = app(TextbookApiService::class);
  64. $updatedData = $apiService->updateTextbook($this->recordId, $updateData);
  65. // 更新本地数据
  66. $this->data = array_merge($this->data, $updatedData);
  67. // 显示成功消息
  68. \Filament\Notifications\Notification::make()
  69. ->title('教材更新成功')
  70. ->success()
  71. ->send();
  72. }
  73. protected function getHeaderActions(): array
  74. {
  75. return [
  76. Actions\Action::make('back')
  77. ->label('返回列表')
  78. ->url(static::$resource::getUrl('index'))
  79. ->color('gray'),
  80. ];
  81. }
  82. public function getTitle(): string
  83. {
  84. return '编辑教材';
  85. }
  86. public function getView(): string
  87. {
  88. return 'filament.resources.textbook-resource.edit';
  89. }
  90. public function form(\Filament\Forms\Form $form): \Filament\Forms\Form
  91. {
  92. return $form
  93. ->schema([
  94. Forms\Components\Section::make('基本信息')
  95. ->schema([
  96. Forms\Components\Select::make('data.series_id')
  97. ->label('教材系列')
  98. ->options(function () {
  99. $apiService = app(TextbookApiService::class);
  100. $series = $apiService->getTextbookSeries();
  101. $options = [];
  102. foreach ($series['data'] as $s) {
  103. $options[$s['id']] = $s['name'];
  104. }
  105. return $options;
  106. })
  107. ->required()
  108. ->searchable(),
  109. Forms\Components\Select::make('data.stage')
  110. ->label('学段')
  111. ->options([
  112. 'primary' => '小学',
  113. 'junior' => '初中',
  114. 'senior' => '高中',
  115. ])
  116. ->required()
  117. ->reactive(),
  118. Forms\Components\TextInput::make('data.grade')
  119. ->label('年级')
  120. ->numeric()
  121. ->helperText('例如:7表示七年级'),
  122. Forms\Components\Select::make('data.semester')
  123. ->label('学期')
  124. ->options([
  125. 1 => '上学期',
  126. 2 => '下学期',
  127. ])
  128. ->helperText('选择学期'),
  129. Forms\Components\TextInput::make('data.official_title')
  130. ->label('教材名称')
  131. ->required()
  132. ->maxLength(255),
  133. Forms\Components\TextInput::make('data.isbn')
  134. ->label('ISBN')
  135. ->maxLength(255),
  136. Forms\Components\Select::make('data.status')
  137. ->label('状态')
  138. ->options([
  139. 'draft' => '草稿',
  140. 'published' => '已发布',
  141. 'archived' => '已归档',
  142. ])
  143. ->required(),
  144. ])
  145. ->columns(2),
  146. Forms\Components\Section::make('版本与系列')
  147. ->schema([
  148. Forms\Components\Select::make('data.naming_scheme')
  149. ->label('命名体系')
  150. ->options([
  151. 'new' => '新体系',
  152. 'old' => '旧体系',
  153. ]),
  154. Forms\Components\Select::make('data.track')
  155. ->label('方向')
  156. ->options([
  157. 'science' => '理科',
  158. 'liberal_arts' => '文科',
  159. ]),
  160. Forms\Components\Select::make('data.module_type')
  161. ->label('模块类型')
  162. ->options([
  163. 'compulsory' => '必修',
  164. 'selective_compulsory' => '选择性必修',
  165. 'elective' => '选修',
  166. ]),
  167. Forms\Components\TextInput::make('data.volume_no')
  168. ->label('册次')
  169. ->numeric(),
  170. Forms\Components\TextInput::make('data.legacy_code')
  171. ->label('旧版代号'),
  172. Forms\Components\TextInput::make('data.edition_label')
  173. ->label('版本标识'),
  174. ])
  175. ->columns(2),
  176. Forms\Components\Section::make('封面上传')
  177. ->schema([
  178. Forms\Components\FileUpload::make('data.cover_path')
  179. ->label('封面图片')
  180. ->image()
  181. ->directory('textbook-covers')
  182. ->helperText('建议尺寸 600x800,JPG/PNG'),
  183. ])
  184. ->extraAttributes(['id' => 'cover']),
  185. ])
  186. ->statePath('data');
  187. }
  188. }