mirror of
http://124.126.16.154:8888/singularity/hyperf-admin.git
synced 2026-01-15 05:55:08 +08:00
perf: add remote scaffold
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.png"> <!-- 使用CDN的CSS文件 --> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="external nofollow" rel="external nofollow" rel="preload" as="style"> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <% } %> <!-- 使用CDN的JS文件 --> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="external nofollow" rel="preload" as="script"> <% } %> <title>上海比户</title> </head> <body> <noscript> <strong></strong> </noscript> <div id="app"></div> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script> <% } %> </body> </html>
|
||||
|
||||
`hyperf-admin`是前后端分离的后台管理系统, 前端基于`vue`的 `vue-admin-template`, 针对后台业务`列表`, `表单`等场景封装了大量业务组件, 后端基于`hyperf`实现, 整体思路是后端定义页面渲染规则, 前端页面渲染时首先拉取配置, 然后组件根据具体配置完成页面渲染, 方便开发者仅做少量的配置工作就能完成常见的`CRUD`工作, 同时支持自定义组件和自定义页面, 以开发更为复杂的页面.
|
||||
|
||||

|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* [按钮详解](backend/super-button.md)
|
||||
* [脚手架实体](backend/scaffold_entity.md)
|
||||
* [多模块模式](backend/remote_module.md)
|
||||
* [远程脚手架](backend/remote_scaffold.md)
|
||||
* [通用配置](backend/common-config.md)
|
||||
* [辅助函数](backend/functions.md)
|
||||
* 业务组件
|
||||
|
||||
147
docs/backend/remote_scaffold.md
Normal file
147
docs/backend/remote_scaffold.md
Normal file
@@ -0,0 +1,147 @@
|
||||
远程脚手架配置 与 [远程模块](https://hyperf-admin.github.io/hyperf-admin/#/backend/remote_module) 的作用类似, 但又有不同, 远程模块的作用是 为 `hyperf-admin` 接入另外一个用`hyperf-admin` 实现的项目, 但在实际开发中, 后台页面可能需要为其他业务团队搭建页面, 而对于后端的实现可能 不是 `hyperf-admin` 甚至不是 `php`, 这是我可以使用 `远程脚手架的模式` 为第三方业务提供后台页面的管理功能, 三方业务使用实现对于 `api` 即可
|
||||
|
||||
我们已 `用户管理` 这个页面功能为例, 讲解如何使用此功能.
|
||||
|
||||
先上效果图
|
||||

|
||||
|
||||

|
||||
|
||||
此时我们只用配置好脚手架配置,即可为第三方服务提供后台页面的管理功能
|
||||
```json
|
||||
{
|
||||
"getApi": "http://127.0.0.1:9511/user/{id}",
|
||||
"saveApi": "http://127.0.0.1:9511/user/{id}",
|
||||
"listApi": "http://127.0.0.1:9511/user/list",
|
||||
"createAble": false,
|
||||
"deleteAble": true,
|
||||
"defaultList": true,
|
||||
"filter": [
|
||||
"realname%",
|
||||
"username%",
|
||||
"create_at"
|
||||
],
|
||||
"form": {
|
||||
"id": "int",
|
||||
"username|登录账号": {
|
||||
"rule": "required",
|
||||
"readonly": true
|
||||
},
|
||||
"avatar|头像": {
|
||||
"type": "image",
|
||||
"rule": "string"
|
||||
},
|
||||
"realname|昵称": "",
|
||||
"mobile|手机": "",
|
||||
"email|邮箱": "email",
|
||||
"sign|签名": "",
|
||||
"pwd|密码": {
|
||||
"virtual_field": true,
|
||||
"default": "",
|
||||
"props": {
|
||||
"size": "small",
|
||||
"maxlength": 20
|
||||
},
|
||||
"info": "若设置, 将会更新用户密码"
|
||||
},
|
||||
"status|状态": {
|
||||
"rule": "required",
|
||||
"type": "radio",
|
||||
"options": [
|
||||
"禁用",
|
||||
"启用"
|
||||
],
|
||||
"default": 0
|
||||
},
|
||||
"is_admin|类型": {
|
||||
"rule": "int",
|
||||
"type": "radio",
|
||||
"options": [
|
||||
"普通管理员",
|
||||
"超级管理员"
|
||||
],
|
||||
"info": "普通管理员需要分配角色才能访问角色对应的资源;超级管理员可以访问全部资源",
|
||||
"default": 0,
|
||||
"render": []
|
||||
},
|
||||
"role_ids|角色": {
|
||||
"rule": "array",
|
||||
"type": "el-cascader-panel",
|
||||
"virtual_field": true,
|
||||
"props": {
|
||||
"props": {
|
||||
"multiple": true,
|
||||
"leaf": "leaf",
|
||||
"emitPath": false,
|
||||
"checkStrictly": true
|
||||
}
|
||||
},
|
||||
"render": []
|
||||
},
|
||||
"create_at|创建时间": {
|
||||
"form": false,
|
||||
"type": "date_range"
|
||||
}
|
||||
},
|
||||
"hasOne": [],
|
||||
"table": {
|
||||
"columns": [
|
||||
"id",
|
||||
"realname",
|
||||
"username",
|
||||
{
|
||||
"field": "mobile",
|
||||
"render": []
|
||||
},
|
||||
{
|
||||
"field": "avatar",
|
||||
"render": "avatarRender"
|
||||
},
|
||||
"email",
|
||||
{
|
||||
"field": "status",
|
||||
"enum": [
|
||||
"info",
|
||||
"success"
|
||||
]
|
||||
},
|
||||
{
|
||||
"field": "role_id",
|
||||
"title": "权限",
|
||||
"virtual_field": true
|
||||
}
|
||||
],
|
||||
"rowActions": [
|
||||
{
|
||||
"type": "form",
|
||||
"target": "/system/form/89/{id}",
|
||||
"text": "编辑"
|
||||
},
|
||||
{
|
||||
"type": "form",
|
||||
"target": "_proxy@http://127.0.0.1:9511/user/form",
|
||||
"text": "编辑2"
|
||||
}
|
||||
],
|
||||
"topActions": [
|
||||
{
|
||||
"type": "form",
|
||||
"target": "/system/form/89/form",
|
||||
"text": "新建"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
熟系 [脚手架](https://hyperf-admin.github.io/hyperf-admin/#/backend/scaffold)这节的朋友会发现, 这个配置和 脚手架中 `public function scaffoldOptions()` 方法的配置几乎是一样的, 是的, 当前这个功能吧 `脚手架配置` 抽离到的数据库中, 不在依赖代码生成, 极大的提高的易用性.
|
||||
|
||||
有几个特殊的配置项
|
||||
- `getApi` 当前管理对象单一对象的获取接口, form表单复现数据时使用
|
||||
- `saveApi` 当前管理对象单一对象保存接口, form表单提交时使用
|
||||
- `listApi` 当前对象的列表数据接口
|
||||
|
||||
按钮的 `target` 里还有如下写法 `_proxy@http://127.0.0.1:9511/user/form`, 操作按钮后 系统会自动重写到 `/system/proxy?proxy_url=http%3A%2F%2F127.0.0.1%3A9511%2Fuser%2Fform` 接口, 又 `hyperf-admin` 后端代码 完成代理请求.
|
||||
|
||||
此功能的具体实现代码在 `src/admin/src/Controller/SystemController.php` 感兴趣的朋友可以看下源码, 十分简单.
|
||||
|
||||
@@ -60,7 +60,7 @@ class MenuController extends AdminAbstractController
|
||||
'when' => ['=', 1],
|
||||
'set' => [
|
||||
'path' => [
|
||||
'rule' => 'required',
|
||||
'rule' => 'requir渲染方式ed',
|
||||
],
|
||||
'label' => [
|
||||
'title' => '菜单标题',
|
||||
@@ -148,6 +148,7 @@ class MenuController extends AdminAbstractController
|
||||
'options' => [
|
||||
1 => '脚手架',
|
||||
0 => '自定义',
|
||||
2 => '配置化脚手架',
|
||||
],
|
||||
'default' => 1,
|
||||
'col' => [
|
||||
@@ -162,6 +163,13 @@ class MenuController extends AdminAbstractController
|
||||
],
|
||||
],
|
||||
],
|
||||
'config|脚手架配置' => [
|
||||
"type" => 'json',
|
||||
'depend' => [
|
||||
'field' => 'is_scaffold',
|
||||
'value' => 2
|
||||
]
|
||||
],
|
||||
'view|组件路径' => [
|
||||
'rule' => 'string|max:50',
|
||||
'default' => '',
|
||||
@@ -395,7 +403,9 @@ class MenuController extends AdminAbstractController
|
||||
$data['path'] = '#';
|
||||
}
|
||||
$data['is_menu'] = $data['type'] == 2 ? 0 : $data['is_menu'];
|
||||
$data['permission'] = implode(',', $data['permission'] ?? []);
|
||||
if ($data['permission']) {
|
||||
$data['permission'] = implode(',', $data['permission'] ?? []);
|
||||
}
|
||||
$pid = array_pop($data['pid']);
|
||||
if ($pid == $id) {
|
||||
$pid = array_pop($data['pid']);
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
namespace HyperfAdmin\Admin\Controller;
|
||||
|
||||
use Hyperf\Utils\Str;
|
||||
use HyperfAdmin\Admin\Model\FrontRoutes;
|
||||
use HyperfAdmin\Admin\Service\CommonConfig;
|
||||
use HyperfAdmin\Admin\Service\ModuleProxy;
|
||||
use HyperfAdmin\BaseUtils\Constants\ErrorCode;
|
||||
use HyperfAdmin\BaseUtils\Guzzle;
|
||||
|
||||
class SystemController extends AdminAbstractController
|
||||
{
|
||||
@@ -40,4 +43,81 @@ class SystemController extends AdminAbstractController
|
||||
});
|
||||
return $this->success(array_values($routes));
|
||||
}
|
||||
|
||||
public function listInfo(int $id)
|
||||
{
|
||||
$config = FrontRoutes::query()->find($id)->getAttributeValue("config");
|
||||
$this->options = $config;
|
||||
return $this->info();
|
||||
}
|
||||
|
||||
public function listDetail(int $id)
|
||||
{
|
||||
$config = FrontRoutes::query()->find($id)->getAttributeValue("config");
|
||||
$listApi = $config['listApi'] ?? '';
|
||||
if (!$listApi) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '脚手架配置错误, 缺少列表接口');
|
||||
}
|
||||
try {
|
||||
return Guzzle::proxy($listApi, $this->request);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '外部接口转发失败 ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function formInfo($route_id, $id)
|
||||
{
|
||||
$config = FrontRoutes::query()->find($route_id)->getAttributeValue("config");
|
||||
try {
|
||||
$this->options = $config;
|
||||
$form = $this->form();
|
||||
if ($id) {
|
||||
// todo token or aksk
|
||||
$getApi = str_var_replace($config['getApi'] ?? '', ['id' => $id]);
|
||||
$result = Guzzle::proxy($getApi, $this->request);
|
||||
if ($result['code'] !== 0) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '外部接口转发失败 ' . $result['message'] ?? '');
|
||||
}
|
||||
foreach ($form['payload']['form'] as &$item) {
|
||||
$item['value'] = $result['payload'][$item['field']] ?? null;
|
||||
unset($item);
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '外部接口转发失败 ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function formSave($route_id, $id)
|
||||
{
|
||||
$config = FrontRoutes::query()->find($route_id)->getAttributeValue("config");
|
||||
$saveApi = str_var_replace($config['saveApi'] ?? '', ['id' => $id]);
|
||||
if (!$saveApi) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '脚手架配置错误, 缺少列表接口');
|
||||
}
|
||||
try {
|
||||
return Guzzle::post($saveApi, $this->request);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '外部接口转发失败 ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
}
|
||||
|
||||
public function proxy()
|
||||
{
|
||||
$proxyUrl = $this->request->query('proxy_url');
|
||||
|
||||
if (!$proxyUrl) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '脚手架配置错误, 缺少列表接口');
|
||||
}
|
||||
try {
|
||||
return Guzzle::proxy($proxyUrl, $this->request);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail(ErrorCode::CODE_ERR_SYSTEM, '外部接口转发失败 ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class UpdateCommand extends HyperfCommand
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$version = $input->getArgument('version');
|
||||
$version = $this->input->getArgument('version');
|
||||
$db_conf = config('databases.hyperf_admin');
|
||||
if (!$db_conf || !$db_conf['host']) {
|
||||
$this->output->error('place set hyperf_admin db config in env');
|
||||
|
||||
@@ -54,8 +54,9 @@ CREATE TABLE `front_routes` (
|
||||
`type` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '菜单类型 0 目录 1 菜单 2 其他',
|
||||
`page_type` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '页面类型: 0 列表 1 表单',
|
||||
`scaffold_action` varchar(255) NOT NULL DEFAULT '' COMMENT '脚手架预置权限',
|
||||
`config` text COMMENT '配置化脚手架',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=90 DEFAULT CHARSET=utf8mb4 COMMENT='前端路由(菜单)';;
|
||||
|
||||
CREATE TABLE `global_config` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
@@ -37,6 +37,7 @@ class FrontRoutes extends BaseModel
|
||||
'permission',
|
||||
'http_method',
|
||||
'page_type',
|
||||
'config'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -48,6 +49,7 @@ class FrontRoutes extends BaseModel
|
||||
'is_scaffold' => 'integer',
|
||||
'page_type' => 'integer',
|
||||
'sort' => 'integer',
|
||||
'config' => 'json',
|
||||
];
|
||||
|
||||
const HTTP_METHOD_ANY = 0;
|
||||
|
||||
@@ -39,3 +39,9 @@ register_route('/cconf', CommonConfigController::class, function ($controller) {
|
||||
|
||||
Router::get('/system/config', [SystemController::class, 'config']);
|
||||
Router::get('/system/routes', [SystemController::class, 'routes']);
|
||||
Router::get('/system/proxy', [SystemController::class, 'proxy']);
|
||||
Router::get('/system/list_info/{id:\d+}', [SystemController::class, 'listInfo']);
|
||||
Router::get('/system/list/{id:\d+}', [SystemController::class, 'listDetail']);
|
||||
Router::get('/system/form/{route_id:\d+}/form', [SystemController::class, 'formInfo']);
|
||||
Router::get('/system/form/{route_id:\d+}/{id:\d+}', [SystemController::class, 'formInfo']);
|
||||
Router::post('/system/form/{route_id:\d+}/{id:\d+}', [SystemController::class, 'formSave']);
|
||||
|
||||
@@ -107,7 +107,6 @@ class ConfigProvider
|
||||
'exceptions' => [
|
||||
'handler' => [
|
||||
'http' => [
|
||||
HyperfHttpExceptionHandler::class,
|
||||
HttpExceptionHandler::class,
|
||||
],
|
||||
],
|
||||
|
||||
@@ -39,6 +39,9 @@ class CrontabDispatcherProcess extends ProcessCrontabDispatcherProcess
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
if (!config('cron_center.enable', false)) {
|
||||
return;
|
||||
}
|
||||
$this->event->dispatch(new CrontabDispatcherStarted());
|
||||
while (true) {
|
||||
$this->cron_manager->createOrUpdateNode();
|
||||
|
||||
Reference in New Issue
Block a user