Skip to content

Commit 08f239c

Browse files
myxiaoaoclaude
andcommitted
feat: AdminController 支持自定义页面视图
子类通过实现 custom* 方法即可替代默认的 Grid/Form/Show 组件, 支持 customIndex、customShow、customCreate、customEdit、 customStore、customUpdate、customDestroy 七个方法, 未实现的方法仍走原有逻辑,完全向后兼容。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 25e0c6a commit 08f239c

File tree

3 files changed

+280
-4
lines changed

3 files changed

+280
-4
lines changed

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,5 @@
128128
- [自定义登录认证](advanced/custom-authentication.md)
129129
- [自定义头部导航](advanced/custom-navbar.md)
130130
- [自定义图表](advanced/custom-chart.md)
131+
- [自定义页面视图](advanced/custom-view.md)
131132
- [多语言](advanced/trans.md)

docs/advanced/custom-view.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# 自定义页面视图
2+
3+
`AdminController` 默认使用 `Grid``Form``Show` 组件来构建列表、新建/编辑、详情页面。如果你需要完全自定义某个页面的 HTML,可以通过实现 `custom*` 方法来替代默认行为,无需重写整个控制器方法。
4+
5+
## 基本用法
6+
7+
在子类控制器中,实现以下任意 `custom*` 方法即可接管对应页面,未实现的方法仍走原有的 `grid()``form()``detail()` 逻辑。
8+
9+
### 可用方法
10+
11+
| 方法 | 作用 | 替代原来的 |
12+
|------|------|-----------|
13+
| `customIndex()` | 自定义列表页内容 | `grid()` |
14+
| `customShow($id)` | 自定义详情页内容 | `detail($id)` |
15+
| `customCreate()` | 自定义新建页内容 | `form()` |
16+
| `customEdit($id)` | 自定义编辑页内容 | `form()->edit($id)` |
17+
| `customStore()` | 自定义新建提交处理 | `form()->store()` |
18+
| `customUpdate($id)` | 自定义更新提交处理 | `form()->update($id)` |
19+
| `customDestroy($id)` | 自定义删除处理 | `form()->destroy($id)` |
20+
21+
### 返回值约定
22+
23+
**展示方法** (`customIndex``customShow``customCreate``customEdit`):
24+
25+
返回值会传给 `Content::body()`,支持以下类型:
26+
- `string` — 直接输出 HTML 字符串
27+
- `Renderable` — 如 `view()` 返回的视图、自定义 Widget
28+
- `Closure` — 回调接收 `Row` 对象,用于 Row/Column 栅格布局
29+
- `Htmlable` — Laravel 的 `Htmlable` 接口实现
30+
31+
**提交方法** (`customStore``customUpdate``customDestroy`):
32+
33+
返回 `JsonResponse` 对象以对接前端 AJAX 响应机制,在控制器中使用时需要加上 `send` 方法:
34+
35+
```php
36+
use Dcat\Admin\Http\JsonResponse;
37+
38+
return JsonResponse::make()->success('操作成功')->redirect('orders')->send();
39+
```
40+
41+
更多 `JsonResponse` 用法请参考[动作以及表单响应](response.md)
42+
43+
## 完整示例
44+
45+
### 所有页面自定义
46+
47+
```php
48+
<?php
49+
50+
namespace App\Admin\Controllers;
51+
52+
use App\Models\Order;
53+
use Dcat\Admin\Http\Controllers\AdminController;
54+
use Dcat\Admin\Http\JsonResponse;
55+
56+
class OrderController extends AdminController
57+
{
58+
protected $title = '订单管理';
59+
60+
// 自定义列表页
61+
protected function customIndex()
62+
{
63+
return view('admin.order.index', [
64+
'orders' => Order::paginate(20),
65+
]);
66+
}
67+
68+
// 自定义详情页
69+
protected function customShow($id)
70+
{
71+
return view('admin.order.show', [
72+
'order' => Order::findOrFail($id),
73+
]);
74+
}
75+
76+
// 自定义新建页
77+
protected function customCreate()
78+
{
79+
return view('admin.order.create');
80+
}
81+
82+
// 自定义编辑页
83+
protected function customEdit($id)
84+
{
85+
return view('admin.order.edit', [
86+
'order' => Order::findOrFail($id),
87+
]);
88+
}
89+
90+
// 自定义新建提交
91+
protected function customStore()
92+
{
93+
$data = request()->validate([
94+
'title' => 'required|string|max:255',
95+
'amount' => 'required|numeric|min:0',
96+
]);
97+
98+
$order = Order::create($data);
99+
100+
return JsonResponse::make()
101+
->success('创建成功')
102+
->redirect('orders/' . $order->id)
103+
->send();
104+
}
105+
106+
// 自定义更新提交
107+
protected function customUpdate($id)
108+
{
109+
$data = request()->validate([
110+
'title' => 'required|string|max:255',
111+
'amount' => 'required|numeric|min:0',
112+
]);
113+
114+
Order::findOrFail($id)->update($data);
115+
116+
return JsonResponse::make()
117+
->success('更新成功')
118+
->redirect('orders')
119+
->send();
120+
}
121+
122+
// 自定义删除
123+
protected function customDestroy($id)
124+
{
125+
Order::destroy(explode(',', $id));
126+
127+
return JsonResponse::make()
128+
->success('删除成功')
129+
->send();
130+
}
131+
}
132+
```
133+
134+
### 混合模式
135+
136+
可以只对部分页面使用自定义视图,其余继续使用默认组件:
137+
138+
```php
139+
class ProductController extends AdminController
140+
{
141+
// 列表页继续使用 Grid
142+
protected function grid()
143+
{
144+
return Grid::make(new Product(), function (Grid $grid) {
145+
$grid->column('id')->sortable();
146+
$grid->column('name');
147+
$grid->column('price');
148+
});
149+
}
150+
151+
// 详情页继续使用 Show
152+
protected function detail($id)
153+
{
154+
return Show::make($id, new Product(), function (Show $show) {
155+
$show->field('id');
156+
$show->field('name');
157+
$show->field('price');
158+
});
159+
}
160+
161+
// 只有新建和编辑页使用自定义视图
162+
protected function customCreate()
163+
{
164+
return view('admin.product.create');
165+
}
166+
167+
protected function customEdit($id)
168+
{
169+
return view('admin.product.edit', [
170+
'product' => Product::findOrFail($id),
171+
]);
172+
}
173+
174+
protected function customStore()
175+
{
176+
// 自定义新建逻辑...
177+
}
178+
179+
protected function customUpdate($id)
180+
{
181+
// 自定义更新逻辑...
182+
}
183+
184+
// form() 仍然需要定义,因为 destroy 默认使用它
185+
protected function form()
186+
{
187+
return Form::make(new Product(), function (Form $form) {
188+
$form->text('name');
189+
$form->currency('price');
190+
});
191+
}
192+
}
193+
```
194+
195+
## 自定义样式和JS
196+
197+
`custom*` 方法中,可以通过 `Admin::style()``Admin::css()``Admin::js()``Admin::script()` 注入页面资源:
198+
199+
```php
200+
use Dcat\Admin\Admin;
201+
202+
protected function customEdit($id)
203+
{
204+
// 注入 CSS 文件
205+
Admin::css('vendor/order/edit.css');
206+
207+
// 注入内联样式
208+
Admin::style('.order-form .amount { font-weight: bold; color: #e74c3c; }');
209+
210+
// 注入 JS 文件
211+
Admin::js('vendor/order/edit.js');
212+
213+
// 注入 JS 代码
214+
Admin::script(
215+
<<<JS
216+
$('.order-form').on('submit', function(e) {
217+
// ...
218+
});
219+
JS
220+
);
221+
222+
return view('admin.order.edit', [
223+
'order' => Order::findOrFail($id),
224+
]);
225+
}
226+
```
227+
228+
也可以在 Blade 视图中使用 `admin_view` 来组织 HTML、CSS、JS,参考[视图与自定义页面](../getting-started/custom-page.md)
229+
230+
## 使用 Row/Column 布局
231+
232+
展示方法支持传入闭包来使用栅格布局:
233+
234+
```php
235+
use Dcat\Admin\Layout\Row;
236+
use Dcat\Admin\Layout\Column;
237+
238+
protected function customShow($id)
239+
{
240+
$order = Order::findOrFail($id);
241+
242+
return function (Row $row) use ($order) {
243+
$row->column(8, view('admin.order.detail', compact('order')));
244+
$row->column(4, view('admin.order.sidebar', compact('order')));
245+
};
246+
}
247+
```

src/Http/Controllers/AdminController.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ public function index(Content $content)
7474
->translation($this->translation())
7575
->title($this->title())
7676
->description($this->description()['index'] ?? trans('admin.list'))
77-
->body($this->grid());
77+
->body(
78+
method_exists($this, 'customIndex')
79+
? $this->customIndex()
80+
: $this->grid()
81+
);
7882
}
7983

8084
/**
@@ -89,7 +93,11 @@ public function show($id, Content $content)
8993
->translation($this->translation())
9094
->title($this->title())
9195
->description($this->description()['show'] ?? trans('admin.show'))
92-
->body($this->detail($id));
96+
->body(
97+
method_exists($this, 'customShow')
98+
? $this->customShow($id)
99+
: $this->detail($id)
100+
);
93101
}
94102

95103
/**
@@ -104,7 +112,11 @@ public function edit($id, Content $content)
104112
->translation($this->translation())
105113
->title($this->title())
106114
->description($this->description()['edit'] ?? trans('admin.edit'))
107-
->body($this->form()->edit($id));
115+
->body(
116+
method_exists($this, 'customEdit')
117+
? $this->customEdit($id)
118+
: $this->form()->edit($id)
119+
);
108120
}
109121

110122
/**
@@ -118,7 +130,11 @@ public function create(Content $content)
118130
->translation($this->translation())
119131
->title($this->title())
120132
->description($this->description()['create'] ?? trans('admin.create'))
121-
->body($this->form());
133+
->body(
134+
method_exists($this, 'customCreate')
135+
? $this->customCreate()
136+
: $this->form()
137+
);
122138
}
123139

124140
/**
@@ -129,6 +145,10 @@ public function create(Content $content)
129145
*/
130146
public function update($id)
131147
{
148+
if (method_exists($this, 'customUpdate')) {
149+
return $this->customUpdate($id);
150+
}
151+
132152
return $this->form()->update($id);
133153
}
134154

@@ -139,6 +159,10 @@ public function update($id)
139159
*/
140160
public function store()
141161
{
162+
if (method_exists($this, 'customStore')) {
163+
return $this->customStore();
164+
}
165+
142166
return $this->form()->store();
143167
}
144168

@@ -150,6 +174,10 @@ public function store()
150174
*/
151175
public function destroy($id)
152176
{
177+
if (method_exists($this, 'customDestroy')) {
178+
return $this->customDestroy($id);
179+
}
180+
153181
return $this->form()->destroy($id);
154182
}
155183
}

0 commit comments

Comments
 (0)