安装插件后的基础文件
This commit is contained in:
804
app/admin/controller/developer/Curd.php
Normal file
804
app/admin/controller/developer/Curd.php
Normal file
@@ -0,0 +1,804 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin 极速开发框架 [基于WebMan开发]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin.net High Speed Development Framework
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\admin\controller\developer;
|
||||
|
||||
use app\admin\model\developer\Generate;
|
||||
use app\AdminController;
|
||||
use app\common\model\system\AdminRules;
|
||||
use system\Form;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\facade\Db;
|
||||
use think\helper\Str;
|
||||
|
||||
/**
|
||||
* 一键CURD管理
|
||||
* <!--Developer-->
|
||||
* Class Curd
|
||||
* @package app\admin\controller\developer
|
||||
*/
|
||||
class Curd extends AdminController
|
||||
{
|
||||
/**
|
||||
* 数据表前缀
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public mixed $prefix = 'sa_';
|
||||
|
||||
/**
|
||||
* 获取菜单
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $menus = [];
|
||||
|
||||
/**
|
||||
* 关联表信息
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $relation = [];
|
||||
|
||||
/**
|
||||
* 函数体
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $methods = [];
|
||||
|
||||
/**
|
||||
* 模板路径
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $templatePath = '';
|
||||
|
||||
/**
|
||||
* 模板文件
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $templateFiles = [];
|
||||
|
||||
/**
|
||||
* 添加时间字段
|
||||
* @var string
|
||||
*/
|
||||
protected string $createTimeField = 'create_time';
|
||||
|
||||
/**
|
||||
* 更新时间字段
|
||||
* @var string
|
||||
*/
|
||||
protected string $updateTimeField = 'update_time';
|
||||
|
||||
/**
|
||||
* 软删除时间字段
|
||||
* @var string
|
||||
*/
|
||||
protected string $deleteTimeField = 'delete_time';
|
||||
|
||||
/**
|
||||
* 过滤默认模板
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $filterMethod = ['index', 'add', 'edit', 'del', 'status'];
|
||||
|
||||
/**
|
||||
* 限定特定组件
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $mustbeComponent = ['set', 'text', 'json'];
|
||||
|
||||
/**
|
||||
* 修改器字段
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $modifyFieldAttr = ['set', 'text', 'json'];
|
||||
|
||||
/**
|
||||
* 保留字段
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $keepField = 'status';
|
||||
|
||||
/**
|
||||
* 查询字段[SELECT]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $dropdown = ['radio', 'checkbox', 'select'];
|
||||
|
||||
/**
|
||||
* COLS换行符
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $commaEol = ',' . PHP_EOL;
|
||||
|
||||
/**
|
||||
* 受保护的表
|
||||
* 禁止CURD操作
|
||||
* @var array
|
||||
*/
|
||||
protected array $protectTable = [
|
||||
"admin", "admin_access", "admin_group", "admin_rules", "company", "department",
|
||||
"dictionary", "generate", "jobs", "user", "user_group", "user_third", "user_validate"
|
||||
];
|
||||
|
||||
/**
|
||||
* 类保留关键字
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $internalKeywords = [
|
||||
'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch',
|
||||
'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else',
|
||||
'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile',
|
||||
'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements',
|
||||
'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new',
|
||||
'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch',
|
||||
'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor', 'yield', 'readonly', 'match', 'fn'
|
||||
];
|
||||
|
||||
// 初始化操作
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new Generate();
|
||||
$this->prefix = function_exists('get_env') ? get_env('DATABASE_PREFIX') : getenv('DATABASE_PREFIX');
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成CURD代码
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function build(): \support\Response
|
||||
{
|
||||
$id = input('id');
|
||||
$data = $this->model->find($id);
|
||||
|
||||
if ($data['status'] && !$data['force']) {
|
||||
return $this->error('该表已经生成过了');
|
||||
}
|
||||
|
||||
$table = str_replace($this->prefix, '', $data['table']);
|
||||
if ($this->filterSystemTable($table)) {
|
||||
return $this->error('禁止操作系统表');
|
||||
}
|
||||
|
||||
// 命名空间
|
||||
$replaces = [];
|
||||
$controller = $data['controller'];
|
||||
$module = $data['global'] ? 'common' : 'admin';
|
||||
$element = ['controller', 'model', 'validate'];
|
||||
|
||||
try {
|
||||
|
||||
foreach ($element as $key => $item) {
|
||||
$result = $this->parseNameData($item == 'controller' ? 'admin' : $module, $controller, $key ? $table : '', $item);
|
||||
list($replaces[$item . 'Name'], $replaces[$item . 'Namespace'], $replaces[$item . 'File']) = $result;
|
||||
}
|
||||
|
||||
$this->getTemplatePath($controller);
|
||||
list($this->menus, $this->methods, $this->templateFiles) = $this->getMenuMethods($data->toArray());
|
||||
|
||||
// 获取字段
|
||||
$adviceField = [];
|
||||
$adviceSearch = [];
|
||||
$everySearch = [];
|
||||
|
||||
// 字段属性值
|
||||
$colsFields = [];
|
||||
$fieldAttrArr = [];
|
||||
|
||||
// 表单设计
|
||||
$formDesign = [];
|
||||
$formItem = [];
|
||||
$formType = $data['formType'];
|
||||
if (!empty($data['formDesign'])) {
|
||||
$formDesign = json_decode($data['formDesign'], true);
|
||||
}
|
||||
|
||||
$this->tableFields = Db::name($table)->getFields();
|
||||
$listFields = explode(',', $data['listField']);
|
||||
foreach ($this->tableFields as $key => $value) {
|
||||
$field = $value['name'];
|
||||
$comment = str_replace(':', ';', $value['comment']);
|
||||
if (empty($comment)) {
|
||||
return $this->error($field . " 字段注释不能为空");
|
||||
}
|
||||
|
||||
$this->tableFields[$key]['title'] = explode(';', $comment)[0];
|
||||
|
||||
// 是否存在状态字段
|
||||
if ($field == $this->keepField) {
|
||||
$adviceSearch[] = $field;
|
||||
}
|
||||
|
||||
// 获取字段类型
|
||||
$everySearch[] = $field;
|
||||
$type = explode('(', $value['type'])[0];
|
||||
|
||||
// 限定组件类型
|
||||
if (in_array($type, $this->mustbeComponent)) {
|
||||
$this->validComponent($field, $type, $formDesign);
|
||||
}
|
||||
|
||||
if (in_array($type, $this->modifyFieldAttr)) {
|
||||
$fieldAttrArr[] = $this->getFieldAttrArr($field, $type);
|
||||
}
|
||||
|
||||
if (empty($adviceField)
|
||||
|| ($adviceField['type'] != 'varchar' && $type == 'varchar')) {
|
||||
$adviceField = [
|
||||
'field' => $field,
|
||||
'type' => $type,
|
||||
];
|
||||
}
|
||||
|
||||
if (in_array($field, $listFields)) {
|
||||
$colsFields[] = [
|
||||
'field' => $field,
|
||||
'title' => '{:__("' . $this->tableFields[$key]['title'] . '")}',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 推荐搜索片段
|
||||
$adviceSearch[] = $adviceField['field'];
|
||||
$adviceSearchHtml = $this->getAdviceSearch($adviceSearch, $formDesign);
|
||||
|
||||
// 获取全部搜索字段
|
||||
$everySearch = array_diff($everySearch, $adviceSearch);
|
||||
$everySearchHtml = $this->getAdviceSearch($everySearch, $formDesign);
|
||||
$controller = substr($controller, 0, (strrpos($controller, '/') + 1));
|
||||
$colsListArr = $this->getColsListFields($colsFields, $formDesign);
|
||||
|
||||
$replaces['table'] = $table;
|
||||
$replaces['title'] = $data['title'];
|
||||
$replaces['pluginClass'] = $data['plugin'];
|
||||
$replaces['controller'] = $controller;
|
||||
$replaces['controllerDiy'] = $this->getMethodString($this->methods);
|
||||
$replaces['colsListArr'] = $colsListArr;
|
||||
$replaces['fieldAttrArr'] = implode(PHP_EOL . PHP_EOL, $fieldAttrArr);
|
||||
$replaces['adviceSearchHtml'] = $adviceSearchHtml;
|
||||
$replaces['everySearchHtml'] = $everySearchHtml;
|
||||
$replaces['relationMethodList'] = $this->getRelationMethodList($data['relation']);
|
||||
$replaces['FormArea'] = $data['width'] . ',' . $data['height'];
|
||||
$replaces['softDelete'] = array_key_exists($this->deleteTimeField, $this->tableFields) ? "use SoftDelete;" : '';
|
||||
$replaces['softDeleteClassPath'] = array_key_exists($this->deleteTimeField, $this->tableFields) ? "use think\model\concern\SoftDelete;" : '';
|
||||
$replaces['createTime'] = array_key_exists($this->createTimeField, $this->tableFields) ? "'$this->createTimeField'" : 'false';
|
||||
$replaces['updateTime'] = array_key_exists($this->updateTimeField, $this->tableFields) ? "'$this->updateTimeField'" : 'false';
|
||||
$replaces['deleteTime'] = array_key_exists($this->deleteTimeField, $this->tableFields) ? "'$this->deleteTimeField'" : 'false';
|
||||
|
||||
// 生成控制器/模型/验证器规则
|
||||
foreach ($element as $index => $item) {
|
||||
if ($index == 0
|
||||
&& (!$data['create'] || !$data['listField'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$code = read_file($this->getStubTpl($item));
|
||||
foreach ($replaces as $key => $value) {
|
||||
$code = str_replace("{%$key%}", $value, $code);
|
||||
}
|
||||
|
||||
write_file($replaces[$item . 'File'], $code);
|
||||
}
|
||||
|
||||
// 生成表单元素
|
||||
$template = $formType ? 'add' : 'inside';
|
||||
$formHtml = read_file($this->getStubTpl($template));
|
||||
if (!empty($formDesign) && $data['listField']) {
|
||||
|
||||
foreach ($formDesign as $key => $value) {
|
||||
$formItem[$key] = Form::itemElem($value, $formType);
|
||||
}
|
||||
|
||||
$formItem = implode(PHP_EOL, $formItem);
|
||||
$formHtml = str_replace(['{formItems}', '{pluginClass}'], [$formItem, $replaces['pluginClass']], $formHtml);
|
||||
$formType && write_file($this->templatePath . 'add.html', $formHtml);
|
||||
}
|
||||
|
||||
// 生成首页模板
|
||||
$indexHtml = read_file($this->getStubTpl($formType ? 'index' : 'index_inside'));
|
||||
if (!empty($data['listField'])) {
|
||||
$replaces['editforms'] = $formType ? '' : $formHtml;
|
||||
foreach ($replaces as $key => $value) {
|
||||
$indexHtml = str_replace("{%$key%}", $value, $indexHtml);
|
||||
}
|
||||
if (empty($formDesign)) {
|
||||
$indexHtml = preg_replace('/<!--formBegin-->(.*)<!--formEnd-->/isU', '', $indexHtml);
|
||||
}
|
||||
write_file($this->templatePath . 'index.html', str_replace('{pluginClass}', $replaces['pluginClass'], $indexHtml));
|
||||
}
|
||||
|
||||
// 生成扩展模板
|
||||
$extendHtml = read_file($this->getStubTpl('extend'));
|
||||
$extendHtml = str_replace('{pluginClass}', $replaces['pluginClass'], $extendHtml);
|
||||
foreach ($this->methods as $method) {
|
||||
write_file($this->templatePath . Str::snake($method) . '.html', $extendHtml);
|
||||
}
|
||||
|
||||
// 生成CURD菜单
|
||||
if ($data['create'] && !empty($data['listField'])) {
|
||||
AdminRules::createMenu([$this->menus], $replaces['pluginClass'] ?: $table, $data['pid']);
|
||||
}
|
||||
|
||||
// 更新生成状态
|
||||
$data->save(['status' => 1]);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('生成成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理内容
|
||||
* @return mixed|void
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$id = input('id');
|
||||
if (request()->isAjax()) {
|
||||
|
||||
$data = $this->model->find($id);
|
||||
$table = str_replace($this->prefix, '', $data['table']);
|
||||
$controller = $data['controller'];
|
||||
try {
|
||||
|
||||
$module = $data['global'] ? 'common' : 'admin';
|
||||
$element = ['controller', 'model', 'validate'];
|
||||
foreach ($element as $key => $item) {
|
||||
$result = $this->parseNameData($item == 'controller' ? 'admin' : $module, $controller, $key ? $table : '', $item);
|
||||
$file = end($result);
|
||||
if (file_exists($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
// 删除空文件夹
|
||||
remove_empty_dir(dirname($file));
|
||||
}
|
||||
|
||||
list($this->menus, $this->methods, $this->templateFiles) = $this->getMenuMethods($data->toArray());
|
||||
recursive_delete($this->getTemplatePath($controller));
|
||||
AdminRules::disabled($table, true);
|
||||
$data->save(['status' => 0]);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('删除成功');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表字段
|
||||
* @param array $colsFields
|
||||
* @param array $formDesign
|
||||
* @return string
|
||||
*/
|
||||
public function getColsListFields(array $colsFields = [], array $formDesign = []): string
|
||||
{
|
||||
$colsListArr = [];
|
||||
foreach ($colsFields as $key => $value) {
|
||||
|
||||
// 过滤删除字段
|
||||
$colsLine = [];
|
||||
$colsField = $value['field'];
|
||||
$colsTitle = $value['title'];
|
||||
if ($colsField == $this->deleteTimeField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取每一列参数合集
|
||||
$colsLine[] = "field:'$colsField'";
|
||||
if ($colsField == $this->keepField) {
|
||||
$colsLine[] = "templet: '#columnStatus'";
|
||||
}
|
||||
|
||||
$item = $this->recursiveComponent($colsField, $formDesign);
|
||||
if (!empty($item) && is_array($item)) {
|
||||
$colsArr = '';
|
||||
$colsTag = $item['tag'];
|
||||
if (in_array($colsTag, $this->dropdown)) {
|
||||
$colsArr = $item['options'];
|
||||
foreach ($colsArr as $index => $elem) {
|
||||
$colsArr[$index]['title'] = "{:__('" . $elem['title'] . "')}";
|
||||
}
|
||||
$colsArr = json_encode($colsArr, JSON_UNESCAPED_UNICODE);
|
||||
$colsTpl = read_file($this->getStubTpl('list/' . $colsTag));
|
||||
} else if ($colsTag == 'upload') {
|
||||
$colsTpl = read_file($this->getStubTpl('list/' . $item['uploadtype']));
|
||||
} else {
|
||||
$colsTpl = read_file($this->getStubTpl('list/' . $colsTag));
|
||||
}
|
||||
if (!empty($colsTpl)) {
|
||||
$colsLine[] = str_replace(['{colsArr}', '{field}'], [$colsArr, $colsField], $colsTpl);
|
||||
}
|
||||
}
|
||||
|
||||
$colsLine[] = "title:'$colsTitle'";
|
||||
$colsListArr[$key] = '{' . implode(',', $colsLine) . '}';
|
||||
}
|
||||
|
||||
$colsListArr = implode($this->commaEol, $colsListArr);
|
||||
return $colsListArr ? $colsListArr . ',' : $colsListArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取修改器
|
||||
* @param string|null $field
|
||||
* @param string|null $type
|
||||
* @param string $subTpl
|
||||
* @return array|false|string|string[]
|
||||
*/
|
||||
public function getFieldAttrArr(string $field = null, string $type = null, string $subTpl = 'change')
|
||||
{
|
||||
$tplPath = $subTpl . '/' . $type;
|
||||
$methods = read_file($this->getStubTpl($tplPath));
|
||||
|
||||
if (!empty($methods)) {
|
||||
$methods = str_replace('{%field%}', ucfirst($field), $methods);
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证组件
|
||||
* @param string|null $field
|
||||
* @param string|null $type
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function validComponent(string $field, string $type, array $data = [])
|
||||
{
|
||||
if (!$field || !$data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->recursiveComponent($field, $data);
|
||||
|
||||
if (!empty($result)) {
|
||||
|
||||
$tag = strtolower($result['tag']);
|
||||
switch ($type) {
|
||||
case 'set':
|
||||
if ($tag != 'checkbox') {
|
||||
return $this->error($field . ' 组件类型限定为checkbox');
|
||||
}
|
||||
break;
|
||||
case 'json':
|
||||
if ($tag != 'json') {
|
||||
return $this->error($field . ' 组件类型限定为json');
|
||||
}
|
||||
break;
|
||||
case 'text': // 限定TEXT字段类型必须为多文件上传
|
||||
if ($tag != 'upload' || $result['uploadtype'] != 'multiple') {
|
||||
return $this->error($field . ' 字段类型为text时,组件类型限定为多文件上传');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找组件
|
||||
* @param string $field
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function recursiveComponent(string $field = '', array $data = [])
|
||||
{
|
||||
foreach ($data as $value) {
|
||||
|
||||
if ($field == $value['name']) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (isset($value['children']) && $value['children']) {
|
||||
$subElem = $value['children'];
|
||||
foreach ($subElem as $child) {
|
||||
$item = $this->recursiveComponent($field, $child['children']);
|
||||
if (!empty($item)) {
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索模板
|
||||
* @param array $searchArr
|
||||
* @param array $formArr
|
||||
* @return false|string
|
||||
*/
|
||||
public function getAdviceSearch(array $searchArr = [], array $formArr = [])
|
||||
{
|
||||
if (!$searchArr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$varData = '';
|
||||
$searchHtml = [];
|
||||
foreach ($searchArr as $searchField) {
|
||||
|
||||
if ($searchField == $this->deleteTimeField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($searchField == $this->keepField) {
|
||||
$rhtml = read_file($this->getStubTpl('search/status'));
|
||||
} else if (in_array($searchField, [$this->createTimeField, $this->updateTimeField])) {
|
||||
$rhtml = read_file($this->getStubTpl('search/datetime'));
|
||||
} else {
|
||||
|
||||
$result = $this->recursiveComponent($searchField, $formArr);
|
||||
if ($result && in_array($result['tag'], $this->dropdown)) {
|
||||
$varData = Form::validOptions($result['options']);
|
||||
$rhtml = read_file($this->getStubTpl('search/select'));
|
||||
} else if ($result && in_array($result['tag'], ['slider'])) {
|
||||
$rhtml = read_file($this->getStubTpl('search/slider'));
|
||||
$rhtml = str_replace(
|
||||
['{default}', '{theme}', '{step}', '{max}', '{min}'],
|
||||
[$result['data_default'], $result['data_theme'], $result['data_step'], $result['data_max'], $result['data_min']],
|
||||
$rhtml
|
||||
);
|
||||
} else if ($result && $result['tag'] == 'cascader') {
|
||||
$rhtml = read_file($this->getStubTpl('search/cascader'));
|
||||
} else if ($result && $result['tag'] == 'date') {
|
||||
$rhtml = read_file($this->getStubTpl('search/datetime'));
|
||||
} else if ($result && $result['tag'] == 'rate') {
|
||||
$rhtml = read_file($this->getStubTpl('search/rate'));
|
||||
$rhtml = str_replace(['{theme}', '{length}'], [$result['data_theme'], $result['data_length']], $rhtml);
|
||||
} else {
|
||||
$rhtml = read_file($this->getStubTpl('search/input'));
|
||||
}
|
||||
}
|
||||
|
||||
$replace = [
|
||||
'field' => $searchField,
|
||||
'title' => $this->tableFields[$searchField]['title'],
|
||||
'varlist' => ucfirst($searchField) . '_list',
|
||||
'vardata' => $varData,
|
||||
];
|
||||
|
||||
foreach ($replace as $key => $value) {
|
||||
$rhtml = str_replace("{%$key%}", $value, $rhtml);
|
||||
}
|
||||
|
||||
$searchHtml[] = $rhtml;
|
||||
}
|
||||
|
||||
return implode(PHP_EOL . PHP_EOL, $searchHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单函数
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getMenuMethods(array $data = []): array
|
||||
{
|
||||
if (empty($data) || !is_array($data)) {
|
||||
throw new \Exception("Error Params Request", 1);
|
||||
}
|
||||
|
||||
if (!is_array($data['menus'])) {
|
||||
$data['menus'] = unserialize($data['menus']);
|
||||
}
|
||||
|
||||
$MenuRules = [
|
||||
'title' => $data['title'],
|
||||
'router' => $data['controller'],
|
||||
'icon' => $data['icon'] ?: '',
|
||||
'pid' => $data['pid'],
|
||||
'auth' => $data['auth'],
|
||||
];
|
||||
|
||||
foreach ($data['menus'] as $key => $value) {
|
||||
$MenuRules['children'][$key] = [
|
||||
'title' => $value['title'],
|
||||
'router' => $value['router'],
|
||||
'auth' => $value['auth'],
|
||||
'type' => $value['type'],
|
||||
];
|
||||
$parse = explode(':', $value['route']);
|
||||
$parse = end($parse);
|
||||
if (!in_array($parse, $this->filterMethod)) {
|
||||
$this->methods[$key] = $parse;
|
||||
$this->templateFiles[$key] = Str::snake($parse);
|
||||
}
|
||||
}
|
||||
|
||||
return [$MenuRules, $this->methods, $this->templateFiles];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取其他函数
|
||||
* @param array $methods
|
||||
* @return string
|
||||
*/
|
||||
protected function getMethodString(array $methods = []): string
|
||||
{
|
||||
$outsMethod = PHP_EOL;
|
||||
foreach ($methods as $method) {
|
||||
if (!in_array($method, $this->filterMethod)) {
|
||||
$outsMethod .= str_replace('method', $method, read_file($this->getStubTpl('method')));
|
||||
}
|
||||
}
|
||||
return $outsMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联表信息
|
||||
* id style KEY
|
||||
* @param $relation
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getRelationMethodList($relation): string
|
||||
{
|
||||
$relationString = PHP_EOL;
|
||||
if (!empty($relation) && !is_array($relation)) {
|
||||
|
||||
$relation = unserialize($relation);
|
||||
foreach ($relation as $value) {
|
||||
|
||||
if (!$value) {
|
||||
continue;
|
||||
}
|
||||
$table = str_replace($this->prefix, '', $value['table']);
|
||||
$schema = Db::query("SHOW TABLE STATUS LIKE '$table'");
|
||||
$studly = Str::studly($table);
|
||||
|
||||
// 直接判断是否存在
|
||||
// 可提交遍历命名空间PR
|
||||
if (in_array($table,$this->protectTable)) {
|
||||
$studly = '\\app\\common\\model\\system\\' . $studly;
|
||||
} else {
|
||||
$namespace = '\\app\\admin\\model\\'.$studly;
|
||||
if (class_exists($namespace)) {
|
||||
$studly = $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
// 拼接关联语句
|
||||
$localKey = $value['localKey'];
|
||||
$foreignKey = $value['foreignKey'];
|
||||
$str_relation = '$this->' . $value['style'] . '(' . $studly . '::Class,' . "'$foreignKey','$localKey')";
|
||||
|
||||
$bindField = [];
|
||||
if ($value['relationField']) {
|
||||
$bindField = explode(',', $value['relationField']);
|
||||
$bindField = array_unique(array_filter($bindField));
|
||||
$str_relation .= '->bind(' . str_replace('"', '\'', json_encode($bindField)) . ')';
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$Comment = $schema[0]['Comment'] ?? $value['table'];
|
||||
$table = Str::camel($table);
|
||||
$relationString .= ' /**';
|
||||
$relationString .= PHP_EOL . ' * 定义 ' . $Comment . ' 关联模型';
|
||||
$relationString .= PHP_EOL . ' * @localKey ' . $localKey;
|
||||
$relationString .= PHP_EOL . ' * @bind ' . implode(',', $bindField);
|
||||
$relationString .= PHP_EOL . ' */';
|
||||
$relationString .= PHP_EOL . ' public function ' . $table . '()';
|
||||
$relationString .= PHP_EOL . ' {';
|
||||
$relationString .= PHP_EOL . ' return ' . $str_relation . ';';
|
||||
$relationString .= PHP_EOL . ' }';
|
||||
$relationString .= PHP_EOL;
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $relationString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
* @param string $module
|
||||
* @param string $name
|
||||
* @param string $table
|
||||
* @param string $type
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function parseNameData(string $module, string $name, string $table = '', string $type = 'controller'): array
|
||||
{
|
||||
$array = str_replace(['.', '/', '\\'], '/', $name);
|
||||
$array = array_filter(explode('/', $array));
|
||||
if (substr($name, 0 - strlen('/')) != '/') {
|
||||
array_pop($array);
|
||||
}
|
||||
|
||||
$parseName = $type == 'controller' ? ucfirst(end($array)) : Str::studly($table);
|
||||
if (in_array(strtolower($parseName), $this->internalKeywords)) {
|
||||
throw new \Exception('类名称不能使用内置关键字' . $parseName);
|
||||
}
|
||||
|
||||
array_pop($array);
|
||||
$appNamespace = "app\\{$module}\\$type" . ($array ? "\\" . implode("\\", $array) : "");
|
||||
$parseFile = root_path() . $appNamespace . DIRECTORY_SEPARATOR . $parseName . '.php';
|
||||
$parseFile = str_replace('\\', '/', $parseFile);
|
||||
return [$parseName, $appNamespace, $parseFile];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @return bool
|
||||
*/
|
||||
protected function filterSystemTable($table): bool
|
||||
{
|
||||
if (in_array($table, $this->protectTable)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板文件
|
||||
* @param [type] $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getStubTpl($name): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . $name . '.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取代码模板
|
||||
* @param [type] $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getTemplatePath($name): string
|
||||
{
|
||||
$this->templatePath = root_path('app/admin/view');
|
||||
$array = str_replace(['.', '/', '\\'], '/', $name);
|
||||
$array = array_filter(explode('/', $array));
|
||||
if (substr($name, 0 - strlen('/')) != '/') {
|
||||
array_pop($array);
|
||||
}
|
||||
|
||||
foreach ($array as $value) {
|
||||
$value = Str::snake($value);
|
||||
$this->templatePath .= $value . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
return $this->templatePath;
|
||||
}
|
||||
}
|
||||
88
app/admin/controller/developer/Example.php
Normal file
88
app/admin/controller/developer/Example.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin 极速开发框架 [基于WebMan开发]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin.net High Speed Development Framework
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\admin\controller\developer;
|
||||
|
||||
use app\AdminController;
|
||||
use Webman\Http\Request;
|
||||
|
||||
/**
|
||||
* 开发示例
|
||||
* <!--Developer-->
|
||||
* Class Example
|
||||
* @package app\admin\controller\developer
|
||||
*/
|
||||
class Example extends AdminController
|
||||
{
|
||||
/**
|
||||
* 首页
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function index():\support\Response
|
||||
{
|
||||
return parent::index(); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
/**
|
||||
* echarts图标
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function echarts() : \support\Response
|
||||
{
|
||||
return view('/developer/example/echarts');
|
||||
}
|
||||
|
||||
/**
|
||||
* echarts图标
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function table(): \support\Response
|
||||
{
|
||||
return view('/developer/example/table');
|
||||
}
|
||||
|
||||
/**
|
||||
* echarts图标
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function card(): \support\Response
|
||||
{
|
||||
return view('/developer/example/card');
|
||||
}
|
||||
|
||||
/**
|
||||
* echarts图标
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function component(): \support\Response
|
||||
{
|
||||
return view('/developer/example/component');
|
||||
}
|
||||
|
||||
/**
|
||||
* echarts图标
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function editor(): \support\Response
|
||||
{
|
||||
return view('/developer/example/editor');
|
||||
}
|
||||
|
||||
/**
|
||||
* 常规辅助元素
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function auxiliar(): \support\Response
|
||||
{
|
||||
return view('/developer/example/auxiliar');
|
||||
}
|
||||
|
||||
}
|
||||
274
app/admin/controller/developer/Generate.php
Normal file
274
app/admin/controller/developer/Generate.php
Normal file
@@ -0,0 +1,274 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\admin\controller\developer;
|
||||
|
||||
use app\AdminController;
|
||||
use support\Response;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 代码生成器
|
||||
* <!--Developer-->
|
||||
* Class Generate
|
||||
* @package app\admin\controller\developer
|
||||
*/
|
||||
class Generate extends AdminController
|
||||
{
|
||||
/**
|
||||
* 数据表前缀
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public mixed $prefix = 'sa_';
|
||||
|
||||
/**
|
||||
* 插件列表
|
||||
* @var mixed
|
||||
*/
|
||||
public mixed $pluginList = [];
|
||||
|
||||
/**
|
||||
* 过滤字段
|
||||
* @var array
|
||||
*/
|
||||
public array $filterField = ['id', 'update_time', 'create_time', 'delete_time'];
|
||||
|
||||
// 初始化操作
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new \app\admin\model\developer\Generate();
|
||||
$this->prefix = function_exists('get_env') ? get_env('DATABASE_PREFIX') : getenv('DATABASE_PREFIX');
|
||||
$this->pluginList = \app\admin\model\developer\Plugin::select();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示列表
|
||||
*
|
||||
* @return Response
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function index(): Response
|
||||
{
|
||||
if (request()->isAjax()) {
|
||||
|
||||
$param = \request()->all();
|
||||
$param['page'] = (int)input('page');
|
||||
$param['limit'] = (int)input('limit');
|
||||
// 查询条件
|
||||
$where = array();
|
||||
if (!empty($param['title'])) {
|
||||
$where[] = ['title', 'like', '%' . $param['title'] . '%'];
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
$count = $this->model->where($where)->count();
|
||||
$limit = is_empty($param['limit']) ? 10 : $param['limit'];
|
||||
$page = ($count <= $limit) ? 1 : $param['page'];
|
||||
$list = $this->model->where($where)->order("id desc")->limit($limit)->page($page)->select()->toArray();
|
||||
return $this->success('查询成功', null, $list, $count);
|
||||
}
|
||||
|
||||
return view('/developer/generate/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加生成数据
|
||||
*
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function add(): \support\Response
|
||||
{
|
||||
if (request()->isPost()) {
|
||||
|
||||
$post = $this->insert_before(\request()->post());
|
||||
|
||||
if ($this->model->create($post)) {
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
return $this->error();
|
||||
}
|
||||
|
||||
return view('/developer/generate/add', [
|
||||
'data' => $this->getTableFields(),
|
||||
'tables' => Db::getTables(),
|
||||
'pluginList' => $this->pluginList,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑生成数据
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function edit(): \support\Response
|
||||
{
|
||||
|
||||
if (request()->isPost()) {
|
||||
|
||||
$post = $this->insert_before(\request()->post());
|
||||
$post = request_validate_rules($post, get_class($this->model));
|
||||
if (empty($post) || !is_array($post)) {
|
||||
return $this->error($post);
|
||||
}
|
||||
$variable = ['force', 'create', 'auth', 'global', 'delete'];
|
||||
foreach ($variable as $value) {
|
||||
if (!isset($post[$value])) {
|
||||
$post[$value] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->model->update($post)) {
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
return $this->error();
|
||||
}
|
||||
|
||||
$id = input('id');
|
||||
$data = $this->model->find($id);
|
||||
if (!$data) {
|
||||
return $this->error('not found');
|
||||
}
|
||||
|
||||
// 查询当前表
|
||||
$table = str_replace($this->prefix, '', $data['table']);
|
||||
$data['localFields'] = $this->queryFields($table);
|
||||
$data['listField'] = $data['listField'] ? json_encode(explode(',', $data['listField'])) : json_encode([]);
|
||||
|
||||
if ($data['relation']) {
|
||||
$data['relation'] = unserialize($data['relation']);
|
||||
}
|
||||
if ($data['menus']) {
|
||||
$data['menus'] = unserialize($data['menus']);
|
||||
}
|
||||
|
||||
// 渲染模板
|
||||
return view('/developer/generate/edit', [
|
||||
'data' => $data,
|
||||
'tables' => Db::getTables(),
|
||||
'pluginList' => $this->pluginList,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据预处理
|
||||
*
|
||||
* @param array $post
|
||||
* @return array
|
||||
*/
|
||||
public function insert_before(array $post = []): array
|
||||
{
|
||||
// 是否存在关联表
|
||||
if (isset($post['relation_table'])) {
|
||||
|
||||
foreach ($post['relation_table'] as $key => $value) {
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
$post['relation'][$key]['table'] = $value;
|
||||
$post['relation'][$key]['style'] = $post['relation_style'][$key];
|
||||
$post['relation'][$key]['foreignKey'] = $post['foreignKey'][$key];
|
||||
$post['relation'][$key]['localKey'] = $post['localKey'][$key];
|
||||
$post['relation'][$key]['relationField'] = $post['relationField'][$key];
|
||||
}
|
||||
|
||||
if (!empty($post['relation'])) {
|
||||
$post['relation'] = serialize($post['relation']);
|
||||
}
|
||||
} else {
|
||||
$post['relation'] = '';
|
||||
}
|
||||
|
||||
// 处理菜单项
|
||||
$menuParams = [];
|
||||
foreach ($post['menus']['title'] as $key => $value) {
|
||||
$menuParams[$key]['title'] = $value;
|
||||
$menuParams[$key]['route'] = $post['menus']['route'][$key];
|
||||
$menuParams[$key]['router'] = $post['menus']['router'][$key];
|
||||
$menuParams[$key]['template'] = $post['menus']['template'][$key];
|
||||
$menuParams[$key]['auth'] = $post['menus']['auth'][$key];
|
||||
$menuParams[$key]['type'] = $post['menus']['type'][$key];
|
||||
}
|
||||
|
||||
$post['menus'] = $menuParams ? serialize($menuParams) : '';
|
||||
return $post ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单设计器
|
||||
* @return Response
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function formDesign(): \support\Response
|
||||
{
|
||||
$id = input('id');
|
||||
|
||||
if (request()->isPost()) {
|
||||
$post['id'] = $id;
|
||||
$post['formName'] = input('formName');
|
||||
$post['width'] = input('width');
|
||||
$post['height'] = input('height');
|
||||
$post['formType'] = input('formType');
|
||||
$post['formDesign'] = input('formDesign');
|
||||
if ($this->model->update($post)) {
|
||||
return $this->success();
|
||||
}
|
||||
return $this->error();
|
||||
}
|
||||
|
||||
$data = $this->model->find($id);
|
||||
if (!$data) {
|
||||
return $this->error('not found');
|
||||
}
|
||||
|
||||
$tableInfo = [];
|
||||
$table = str_replace($this->prefix, '', $data['table']);
|
||||
$tableFields = Db::name($table)->getFields();
|
||||
foreach ($tableFields as $key => $value) {
|
||||
if (!in_array($key, $this->filterField)) {
|
||||
$info = explode(';', $value['comment']);
|
||||
if ($info) {
|
||||
$tableInfo[$key] = current($info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('/developer/generate/form_design', [
|
||||
'data' => $data,
|
||||
'table' => json_encode($tableInfo, JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询表字段
|
||||
* @param string $name
|
||||
* @return false|string
|
||||
*/
|
||||
public function queryFields(string $name = '')
|
||||
{
|
||||
$list = [];
|
||||
$table = input('table');
|
||||
if (empty($table)) {
|
||||
$table = $name;
|
||||
}
|
||||
|
||||
$field = Db::name($table)->getTableFields();
|
||||
var_dump($field);
|
||||
foreach ($field as $key => $value) {
|
||||
$list[$key]['value'] = $value;
|
||||
$list[$key]['name'] = $value;
|
||||
}
|
||||
|
||||
return json_encode($list ?: []);
|
||||
}
|
||||
}
|
||||
431
app/admin/controller/developer/Plugin.php
Normal file
431
app/admin/controller/developer/Plugin.php
Normal file
@@ -0,0 +1,431 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\admin\controller\developer;
|
||||
|
||||
use app\AdminController;
|
||||
use app\common\model\system\AdminRules;
|
||||
use Exception;
|
||||
use FilesystemIterator;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use support\Response;
|
||||
use system\File;
|
||||
use system\ZipArchives;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use app\admin\controller\system\Plugin as PluginService;
|
||||
|
||||
/**
|
||||
* 插件开发
|
||||
* <!--Developer-->
|
||||
* Class Plugin
|
||||
* @package app\admin\controller\developer
|
||||
*/
|
||||
class Plugin extends AdminController
|
||||
{
|
||||
|
||||
// 初始化操作
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new \app\admin\model\developer\Plugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源
|
||||
* @return Response
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function index(): \support\Response
|
||||
{
|
||||
if (request()->isAjax()) {
|
||||
|
||||
$param = \request()->post();
|
||||
$param['page'] = (int)input('page');
|
||||
$param['limit'] = (int)('limit');
|
||||
$count = $this->model->count();
|
||||
$limit = empty($param['limit']) ? 10 : $param['limit'];
|
||||
$page = ($count <= $limit) ? 1 : $param['page'];
|
||||
$list = $this->model->order("id desc")->limit($limit)->page($page)->select()->toArray();
|
||||
return $this->success('查询成功', null, $list, $count);
|
||||
}
|
||||
|
||||
return view('/developer/plugin/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传插件
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function parseFile(): array
|
||||
{
|
||||
try {
|
||||
|
||||
$file = \request()->file('file');
|
||||
if (empty($file)) {
|
||||
throw new \Exception('插件上传失败');
|
||||
}
|
||||
|
||||
$uploadName = $file->getUploadName();
|
||||
$filePath = plugin_path() . $uploadName;
|
||||
if (!$file->move($filePath)) {
|
||||
throw new \Exception('插件上传失败');
|
||||
}
|
||||
|
||||
$uploadName = pathinfo($uploadName)['filename'];
|
||||
$uploadName = explode('-', $uploadName);
|
||||
$fileName = current($uploadName);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage());
|
||||
}
|
||||
|
||||
return [strtolower($fileName), $filePath];
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行本地安装测试
|
||||
* @return Response
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function install(): Response
|
||||
{
|
||||
try {
|
||||
list($name, $filePath) = $this->parseFile();
|
||||
if (is_dir(plugin_path($name))) {
|
||||
throw new \Exception('插件已存在');
|
||||
}
|
||||
ZipArchives::unzip($filePath, plugin_path(), '', true);
|
||||
$pluginClass = get_plugin_instance($name);
|
||||
$pluginClass->install();
|
||||
PluginService::pluginMenu($name);
|
||||
PluginService::executeSql($name);
|
||||
PluginService::enabled($name);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('插件安装成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级插件
|
||||
* @return \support\Response
|
||||
* @throws Exception|\Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function upgrade(): \support\Response
|
||||
{
|
||||
try {
|
||||
|
||||
list($name, $filePath) = $this->parseFile();
|
||||
$pluginPath = plugin_path($name);
|
||||
$pluginInfo = get_plugin_config($name, true);
|
||||
if (!$pluginInfo) {
|
||||
throw new \Exception('插件不存在');
|
||||
}
|
||||
|
||||
if ($pluginInfo['status']) {
|
||||
throw new \Exception('插件已启用,请先禁用插件');
|
||||
}
|
||||
|
||||
$formIndex = ZipArchives::unzip($filePath, plugin_path(), 'config.json');
|
||||
$upgradeInfo = json_decode($formIndex, true);
|
||||
if (version_compare($upgradeInfo['version'], $pluginInfo['version'], "<=")) {
|
||||
throw new \Exception('升级版本不能低于已安装版本');
|
||||
}
|
||||
|
||||
$backupDir = root_path() . $name . '_' . $pluginInfo['version'] . '.zip';
|
||||
ZipArchives::compression($backupDir, $pluginPath, plugin_path());
|
||||
ZipArchives::unzip($filePath, plugin_path(), '', true);
|
||||
|
||||
$pluginClass = get_plugin_instance($name, 'upgrade');
|
||||
$pluginClass->execute($pluginInfo['version'], $upgradeInfo['version']);
|
||||
$data = array_merge($upgradeInfo, [
|
||||
'extends' => $pluginInfo['extends'],
|
||||
'rewrite' => $pluginInfo['rewrite'],
|
||||
]);
|
||||
|
||||
write_file($pluginPath . 'config.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
PluginService::pluginMenu($name);
|
||||
PluginService::executeSql($name);
|
||||
PluginService::enabled($name);
|
||||
|
||||
} catch (\Exception $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('插件升级成功', null, $pluginInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入本地插件
|
||||
* @return Response
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function import(): \support\Response
|
||||
{
|
||||
if (request()->isPost()) {
|
||||
|
||||
$name = input('dir');
|
||||
$pluginInfo = get_plugin_config($name, true);
|
||||
if (empty($pluginInfo)) {
|
||||
return $this->error('插件信息获取失败');
|
||||
}
|
||||
|
||||
// 是否已经导入
|
||||
$result = $this->model->where('name', $name)->findOrEmpty();
|
||||
if (!$result->isEmpty()) {
|
||||
return $this->error('请勿重复导入插件');
|
||||
}
|
||||
|
||||
try {
|
||||
$pluginInfo['import'] = time();
|
||||
$this->model->create($pluginInfo);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('导入成功');
|
||||
}
|
||||
|
||||
$dirs = [];
|
||||
$iterator = new FilesystemIterator(plugin_path(), FilesystemIterator::SKIP_DOTS);
|
||||
foreach ($iterator as $item) {
|
||||
if ($item->isDir()) {
|
||||
// 是否已经导入
|
||||
$find = $this->model->where('name', $item->getBasename())->find();
|
||||
if (empty($find)) {
|
||||
$name = $item->getBasename();
|
||||
$info = get_plugin_config($name);
|
||||
$dirs[] = [
|
||||
'name' => $name,
|
||||
'title' => $info['title'] ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('/developer/plugin/import', ['dirs' => $dirs]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件生成
|
||||
* @return \support\Response
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function build(): \support\Response
|
||||
{
|
||||
$id = input('id');
|
||||
$data = $this->model->where('id', $id)->withoutField('id,status,create_time')->find();
|
||||
if (empty($data)) {
|
||||
return $this->error('插件不存在');
|
||||
}
|
||||
|
||||
$name = $data['name'];
|
||||
$pluginPath = plugin_path($name);
|
||||
$pluginClass = ucfirst($name);
|
||||
if ($data['import'] || is_dir($pluginPath)) {
|
||||
return $this->error('请勿重复生成插件');
|
||||
}
|
||||
|
||||
$pluginZip = __DIR__ . '/stubs/plugin_init.stub';
|
||||
$sourceFiles = plugin_path('plugin_init');
|
||||
$replaces = ['controller', 'model', 'validate', 'view'];
|
||||
$source = ['{name}', '{pluginClass}', '{title}', '{icon}'];
|
||||
$destVars = [$name, $pluginClass, $data['title'], $data['icon']];
|
||||
|
||||
try {
|
||||
|
||||
ZipArchives::unzip($pluginZip, plugin_path());
|
||||
foreach ($replaces as $item) {
|
||||
$namespace = $sourceFiles . 'app/admin' . DIRECTORY_SEPARATOR . $item;
|
||||
$tempPath = $namespace . DIRECTORY_SEPARATOR . 'demo';
|
||||
$tempPath = str_replace('\\', '/', $tempPath);
|
||||
if (is_dir($tempPath)) {
|
||||
$isFirst = false;
|
||||
$targetPath = $namespace . DIRECTORY_SEPARATOR . $name;
|
||||
rename($tempPath, $targetPath);
|
||||
$targetFile = $targetPath . DIRECTORY_SEPARATOR . 'Index.php';
|
||||
if (!is_file($targetFile)) {
|
||||
$isFirst = true;
|
||||
$targetFile = $targetPath . DIRECTORY_SEPARATOR . ($item === 'view' ? '/index/index.html' : 'Demo.php');
|
||||
}
|
||||
$content = str_replace($source, $destVars, read_file($targetFile));
|
||||
if (!empty($content)) {
|
||||
write_file($targetFile, $content);
|
||||
}
|
||||
if ($isFirst && $content && $item !== 'view') {
|
||||
rename($targetFile, $targetPath . DIRECTORY_SEPARATOR . $pluginClass . '.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$array = [$sourceFiles . 'app/index/controller/', $sourceFiles];
|
||||
foreach ($array as $item) {
|
||||
$file = $item . 'Demo.php';
|
||||
$content = str_replace($source, $destVars, read_file($file));
|
||||
write_file($file, $content);
|
||||
rename($file, $item . $pluginClass . '.php');
|
||||
}
|
||||
|
||||
foreach (['README.md', 'function.php', 'Upgrade.php', 'config.html'] as $item) {
|
||||
$file = $sourceFiles . $item;
|
||||
$content = str_replace($source, $destVars, read_file($file));
|
||||
write_file($file, $content);
|
||||
}
|
||||
|
||||
// 处理静态文件
|
||||
$staticFile = [
|
||||
$sourceFiles . 'app/index/view',
|
||||
$sourceFiles . 'public/static/plugin',
|
||||
$sourceFiles . 'public/static/system/plugin'
|
||||
];
|
||||
|
||||
foreach ($staticFile as $index => $item) {
|
||||
$file = $item . '/demo';
|
||||
if (!$index) {
|
||||
$elem = $file . DIRECTORY_SEPARATOR . 'index.html';
|
||||
write_file($elem, str_replace('{pluginClass}', $pluginClass, read_file($elem)));
|
||||
}
|
||||
rename($item . '/' . 'demo', $item . '/' . $name);
|
||||
}
|
||||
|
||||
$configPath = $sourceFiles . 'config.json';
|
||||
$data = $data->toArray();
|
||||
$data['rewrite'] = [];
|
||||
$data['extends'] = [
|
||||
'title' => $data['title'],
|
||||
];
|
||||
$data['area'] = ['600px', '650px',];
|
||||
write_file($configPath, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
rename($sourceFiles, $pluginPath);
|
||||
|
||||
if ($data['menu']) {
|
||||
AdminRules::createMenu($this->createPluginMenu($data), $name);
|
||||
}
|
||||
|
||||
// 启用插件
|
||||
foreach (File::getCopyDirs($name) as $copyDir) {
|
||||
copydirs($copyDir, root_path() . str_replace($pluginPath, '', $copyDir));
|
||||
}
|
||||
|
||||
AdminRules::enabled($name);
|
||||
set_plugin_config($name, ['status' => 1]);
|
||||
} catch (\Throwable $th) {
|
||||
@recursive_delete($pluginPath);
|
||||
@recursive_delete($sourceFiles);
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('插件初始化成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件打包
|
||||
* @return \support\Response
|
||||
* @throws Exception
|
||||
*/
|
||||
public function package(): \support\Response
|
||||
{
|
||||
$id = input('id');
|
||||
$data = $this->model->withoutField('id, import, create_time')->where('id', $id)->find();
|
||||
if (empty($data)) {
|
||||
return $this->error('插件不存在,打包失败!');
|
||||
}
|
||||
|
||||
$name = $data['name'];
|
||||
$pluginClass = ucfirst($name);
|
||||
$pluginPath = plugin_path($name);
|
||||
if (!is_dir($pluginPath)) {
|
||||
return $this->error('插件未生成!');
|
||||
}
|
||||
|
||||
try {
|
||||
$files = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator(root_path('app'), FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($files as $fileinfo) {
|
||||
if ($fileinfo->isFile()) {
|
||||
$filePath = $fileinfo->getPathName();
|
||||
$content = read_file($filePath);
|
||||
if (preg_match('/<!--' . $pluginClass . '-->/iU', $content, $match)) {
|
||||
$match = $match[0];
|
||||
$filePath = str_replace('\\', '/', $filePath);
|
||||
copy_file($filePath, str_replace(root_path(), $pluginPath, $filePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$statics = [
|
||||
root_path('public/static/plugin/' . $name),
|
||||
root_path('public/static/system/plugin/' . $name),
|
||||
];
|
||||
|
||||
foreach ($statics as $item) {
|
||||
if (is_dir($item)) {
|
||||
@copydirs($item, str_replace(root_path(), $pluginPath, $item));
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data['menu'])) {
|
||||
arr2file($pluginPath . '/data/menu.php', AdminRules::export($name));
|
||||
}
|
||||
|
||||
// 加载配置文件
|
||||
$configPath = $pluginPath . 'config.json';
|
||||
$configInfo = json_decode(read_file($configPath), true);
|
||||
$configPack = array_merge($configInfo, $data->toArray());
|
||||
unset($configPack['path']);
|
||||
unset($configPack['filePath']);
|
||||
if (empty($configPack['rewrite'])) {
|
||||
$configPack['rewrite'] = [];
|
||||
}
|
||||
write_file($configPath, json_encode($configPack, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
$pluginZip = root_path('public/upload') . $name . '-' . $data['version'] . '.zip';
|
||||
ZipArchives::compression($pluginZip, $pluginPath);
|
||||
$url = request()->domain() . str_replace(root_path() . 'public', '', $pluginZip);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
|
||||
return $this->success('插件打包成功', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础菜单项
|
||||
* @param $plugin
|
||||
* @return array
|
||||
*/
|
||||
public function createPluginMenu($plugin): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'title' => $plugin['title'],
|
||||
'router' => '/' . $plugin['name'] . '/Index',
|
||||
'icon' => $plugin['icon'],
|
||||
'auth' => '1',
|
||||
'children' => [
|
||||
['router' => '/' . $plugin['name'] . '/Index/index', 'title' => '查看'],
|
||||
['router' => '/' . $plugin['name'] . '/Index/add', 'title' => '添加'],
|
||||
['router' => '/' . $plugin['name'] . '/Index/edit', 'title' => '编辑'],
|
||||
['router' => '/' . $plugin['name'] . '/Index/del', 'title' => '删除'],
|
||||
['router' => '/' . $plugin['name'] . '/Index/status', 'title' => '状态']
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
22
app/admin/controller/developer/stubs/add.stub
Normal file
22
app/admin/controller/developer/stubs/add.stub
Normal file
@@ -0,0 +1,22 @@
|
||||
<include file="/public/header" />
|
||||
<!-- // 重定位style -->
|
||||
<!--{pluginClass}-->
|
||||
<link href="__STATICADMIN__css/content.css" rel="stylesheet" type="text/css" />
|
||||
<div class="layui-fluid">
|
||||
<form class="layui-form layui-card" >
|
||||
|
||||
<div class="layui-card-body">
|
||||
<gt name="$data.id" value="0">
|
||||
<input type="text" name="id" value="{$data.id}" hidden="">
|
||||
<else/>
|
||||
<input type="text" name="id" value="" hidden="">
|
||||
</gt>
|
||||
{formItems}
|
||||
<div class="layui-footer layui-form-footer">
|
||||
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
|
||||
<button class="layui-btn" type="button" lay-filter="submitIframe" lay-submit>{:__('提交')}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<include file="/public/static" />
|
||||
<include file="/public/footer" />
|
||||
22
app/admin/controller/developer/stubs/change/json.stub
Normal file
22
app/admin/controller/developer/stubs/change/json.stub
Normal file
@@ -0,0 +1,22 @@
|
||||
public function set{%field%}Attr($value)
|
||||
{
|
||||
if (!empty($value) && is_array($value)) {
|
||||
$arr = [];
|
||||
foreach ($value['key'] as $key => $elem) {
|
||||
$arr[$elem] = $value['value'][$key];
|
||||
}
|
||||
|
||||
$value = json_encode($arr,JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return $value ?: json_encode([]);
|
||||
}
|
||||
|
||||
public function get{%field%}Attr($value)
|
||||
{
|
||||
if (!empty($value) && is_string($value)) {
|
||||
$value = json_decode($value, true);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
17
app/admin/controller/developer/stubs/change/set.stub
Normal file
17
app/admin/controller/developer/stubs/change/set.stub
Normal file
@@ -0,0 +1,17 @@
|
||||
public function set{%field%}Attr($value)
|
||||
{
|
||||
if (!empty($value) && is_array($value)) {
|
||||
$value = implode(',',$value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function get{%field%}Attr($value)
|
||||
{
|
||||
if (!empty($value) && is_string($value)) {
|
||||
$value = explode(',',$value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
17
app/admin/controller/developer/stubs/change/text.stub
Normal file
17
app/admin/controller/developer/stubs/change/text.stub
Normal file
@@ -0,0 +1,17 @@
|
||||
public function set{%field%}Attr($value)
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$value = serialize($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function get{%field%}Attr($value)
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$value = unserialize($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
35
app/admin/controller/developer/stubs/controller.stub
Normal file
35
app/admin/controller/developer/stubs/controller.stub
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
namespace {%controllerNamespace%};
|
||||
|
||||
use app\AdminController;
|
||||
use Webman\Http\Request;
|
||||
use {%modelNamespace%}\{%modelName%} as {%modelName%}Model;
|
||||
|
||||
/**
|
||||
* {%table%}
|
||||
* {%title%}
|
||||
* <!--{%pluginClass%}-->
|
||||
* Class {%controllerName%}
|
||||
* @package {%controllerNamespace%}
|
||||
*/
|
||||
class {%controllerName%} extends AdminController
|
||||
{
|
||||
/**
|
||||
* {%modelName%}模型对象
|
||||
* @var \{%modelNamespace%}\{%modelName%}
|
||||
*/
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new {%modelName%}Model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认生成的方法为index/add/edit/del/status 五个方法
|
||||
* 当创建CURD的时候,DIY的函数体和模板为空,请自行编写代码
|
||||
*/
|
||||
{%controllerDiy%}
|
||||
|
||||
}
|
||||
1
app/admin/controller/developer/stubs/edit.stub
Normal file
1
app/admin/controller/developer/stubs/edit.stub
Normal file
@@ -0,0 +1 @@
|
||||
<!-- 当前模板为合并模板 如有需求请自行开发 -->
|
||||
9
app/admin/controller/developer/stubs/extend.stub
Normal file
9
app/admin/controller/developer/stubs/extend.stub
Normal file
@@ -0,0 +1,9 @@
|
||||
<include file="/public/header" />
|
||||
<!-- // 重定位style -->
|
||||
<!--{pluginClass}-->
|
||||
<link href="__STATICADMIN__css/content.css" rel="stylesheet" type="text/css" />
|
||||
<div class="layui-fluid">
|
||||
示例模板,可自行开发
|
||||
</div>
|
||||
<include file="/public/static" />
|
||||
<include file="/public/footer" />
|
||||
77
app/admin/controller/developer/stubs/index.stub
Normal file
77
app/admin/controller/developer/stubs/index.stub
Normal file
@@ -0,0 +1,77 @@
|
||||
<include file="/public/header" />
|
||||
<!--{pluginClass}-->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<!-- // 默认操作按钮 -->
|
||||
<div class="layui-card-header layadmin-card-header-auto ">
|
||||
<div class="layui-form">
|
||||
<!-- // 自定义搜索参数 -->
|
||||
<div id="laytable-search" class="layui-form-item" >
|
||||
{%everySearchHtml%}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
{%adviceSearchHtml%}
|
||||
<div class="layui-inline" >
|
||||
<!-- // 默认搜索 -->
|
||||
<button class="layui-btn icon-btn" lay-filter="formSearch" lay-submit><i class="layui-icon layui-icon-search"></i>{:__('搜索')}</button>
|
||||
<!--formBegin-->
|
||||
<button class="layui-btn icon-btn" lay-open="" data-title="{:__('添加')}" data-area="{%FormArea%}" data-maxmin="true" data-url="{:url('{%controller%}add')}" >
|
||||
<i class="layui-icon layui-icon-add-1"></i>{:__('添加')}
|
||||
</button>
|
||||
<!--formEnd-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- // 创建数据实例 -->
|
||||
<table id="lay-tableList" lay-filter="lay-tableList"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- // 列表状态栏 -->
|
||||
<script type="text/html" id="columnStatus">
|
||||
<input type="checkbox" lay-filter="switchStatus" data-url="{:url('{%controller%}status')}" value="{{d.id}}" lay-skin="switch" {{d.status==1?'checked':''}} />
|
||||
</script>
|
||||
|
||||
<!-- // 列表工具栏 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<!--formBegin-->
|
||||
<a class="layui-table-text" data-title="{:__('编辑')}" data-area="{%FormArea%}" data-maxmin="true"
|
||||
data-url="{:url('{%controller%}edit')}?id={{d.id}}" lay-event="edit" >{:__('编辑')}</a>
|
||||
<div class="layui-divider layui-divider-vertical"></div>
|
||||
<!--formEnd-->
|
||||
<a class="layui-table-text" data-url="{:url('{%controller%}del')}?id={{d.id}}" lay-event="del" >{:__('删除')}</a>
|
||||
</script>
|
||||
|
||||
{%editforms%}
|
||||
|
||||
<script type="text/html" id="tableButton"></script>
|
||||
|
||||
<include file="/public/footer" />
|
||||
<script>
|
||||
layui.use(['admin','table'], function () {
|
||||
|
||||
var admin = layui.admin;
|
||||
var table = layui.table;
|
||||
|
||||
/*
|
||||
* 初始化表格
|
||||
*/
|
||||
var isTable = table.render({
|
||||
elem: "#lay-tableList"
|
||||
,url: "{:url('{%controller%}index')}"
|
||||
,toolbar: '#tableButton'
|
||||
,defaultToolbar: ['filter', 'exports', 'print','search']
|
||||
,cellMinWidth: 160
|
||||
,page: true
|
||||
,limit: 18
|
||||
,cols: [[
|
||||
{type: 'checkbox', width: 50},
|
||||
{field: 'id', align: 'center',sort: true,width: 80, title: 'ID'},
|
||||
{%colsListArr%}
|
||||
{align: 'center', toolbar: '#tableBar', width:160, fixed: 'right', title: '{:__("操作")}'},
|
||||
]]
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
75
app/admin/controller/developer/stubs/index_inside.stub
Normal file
75
app/admin/controller/developer/stubs/index_inside.stub
Normal file
@@ -0,0 +1,75 @@
|
||||
<include file="/public/header" />
|
||||
<!--{pluginClass}-->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<!-- // 默认操作按钮 -->
|
||||
<div class="layui-card-header layadmin-card-header-auto ">
|
||||
<div class="layui-form">
|
||||
<!-- // 自定义搜索参数 -->
|
||||
<div id="laytable-search" class="layui-form-item" >
|
||||
{%everySearchHtml%}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
{%adviceSearchHtml%}
|
||||
<div class="layui-inline" >
|
||||
<!-- // 默认搜索 -->
|
||||
<button class="layui-btn icon-btn" lay-filter="formSearch" lay-submit><i class="layui-icon layui-icon-search"></i>{:__('搜索')}</button>
|
||||
<!-- // 打开添加页面 -->
|
||||
<button class="layui-btn icon-btn" lay-open="" data-title="{:__('添加')}" data-area="{%FormArea%}" data-maxmin="true" data-url="#editforms" >
|
||||
<i class="layui-icon layui-icon-add-1"></i>{:__('添加')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- // 创建数据实例 -->
|
||||
<table id="lay-tableList" lay-filter="lay-tableList"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- // 列表状态栏 -->
|
||||
<script type="text/html" id="columnStatus">
|
||||
<input type="checkbox" lay-filter="switchStatus" data-url="{:url('{%controller%}status')}" value="{{d.id}}" lay-skin="switch" {{d.status==1?'checked':''}} />
|
||||
</script>
|
||||
|
||||
<!-- // 列表工具栏 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<a class="layui-table-text" data-title="{:__('编辑')}" data-area="{%FormArea%}" data-maxmin="true" data-url="#editforms" lay-event="edit" >{:__('编辑')}</a>
|
||||
<div class="layui-divider layui-divider-vertical"></div>
|
||||
<a class="layui-table-text" data-url="{:url('{%controller%}del')}?id={{d.id}}" lay-event="del" >{:__('删除')}</a>
|
||||
</script>
|
||||
|
||||
{%editforms%}
|
||||
|
||||
<!-- // 工具栏按钮项 TODO -->
|
||||
<script type="text/html" id="tableButton">
|
||||
</script>
|
||||
|
||||
<include file="/public/footer" />
|
||||
<script>
|
||||
layui.use(['admin','table'], function () {
|
||||
|
||||
var admin = layui.admin;
|
||||
var table = layui.table;
|
||||
|
||||
/*
|
||||
* 初始化表格
|
||||
*/
|
||||
var isTable = table.render({
|
||||
elem: "#lay-tableList"
|
||||
,url: "{:url('{%controller%}index')}"
|
||||
,toolbar: '#tableButton'
|
||||
,defaultToolbar: ['filter', 'exports', 'print','search']
|
||||
,cellMinWidth: 160
|
||||
,page: true
|
||||
,limit: 18
|
||||
,cols: [[
|
||||
{type: 'checkbox', width:50},
|
||||
{field: 'id', align: 'center',sort: true,width: 80, title: 'ID'},
|
||||
{%colsListArr%}
|
||||
{align: 'center', toolbar: '#tableBar', width:160, fixed: 'right', title: '{:__("操作")}'},
|
||||
]]
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
13
app/admin/controller/developer/stubs/inside.stub
Normal file
13
app/admin/controller/developer/stubs/inside.stub
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- // 内置表单项 -->
|
||||
<script type="text/html" id="editforms" >
|
||||
<div class="layui-fluid layui-bg-white" >
|
||||
<form class="layui-form layui-form-fixed" lay-filter="editforms" >
|
||||
<input type="text" name="id" hidden="">
|
||||
{formItems}
|
||||
<div class="layui-footer layui-form-item layui-center" >
|
||||
<button class="layui-btn layui-btn-primary" type="button" sa-event="closePageDialog" >{:__('取消')}</button>
|
||||
<button class="layui-btn" type="button" lay-filter="submitPage" lay-submit>{:__('提交')}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
12
app/admin/controller/developer/stubs/list/checkbox.stub
Normal file
12
app/admin/controller/developer/stubs/list/checkbox.stub
Normal file
@@ -0,0 +1,12 @@
|
||||
templet:function(d) {
|
||||
var colsTit = [];
|
||||
var colsArr = {colsArr};
|
||||
for (var key in colsArr) {
|
||||
let el = colsArr[key];
|
||||
if (d.{field}.indexOf(el.value) !== -1) {
|
||||
colsTit.push(el.title);
|
||||
}
|
||||
}
|
||||
|
||||
return colsTit.join(' ');
|
||||
}
|
||||
3
app/admin/controller/developer/stubs/list/file.stub
Normal file
3
app/admin/controller/developer/stubs/list/file.stub
Normal file
@@ -0,0 +1,3 @@
|
||||
templet:function(d) {
|
||||
return '<a href="'+d.{field}+'" target="_blank" ><img class="filesuffix" src="'+d.{field}+'"></a>';
|
||||
}
|
||||
3
app/admin/controller/developer/stubs/list/images.stub
Normal file
3
app/admin/controller/developer/stubs/list/images.stub
Normal file
@@ -0,0 +1,3 @@
|
||||
templet:function(d) {
|
||||
return '<a href="javascript:"><img class="filesuffix" lay-image-click src="'+d.{field}+'"></a>';
|
||||
}
|
||||
3
app/admin/controller/developer/stubs/list/json.stub
Normal file
3
app/admin/controller/developer/stubs/list/json.stub
Normal file
@@ -0,0 +1,3 @@
|
||||
templet:function(d) {
|
||||
return JSON.stringify(d.{field});
|
||||
}
|
||||
7
app/admin/controller/developer/stubs/list/multiple.stub
Normal file
7
app/admin/controller/developer/stubs/list/multiple.stub
Normal file
@@ -0,0 +1,7 @@
|
||||
templet:function(d) {
|
||||
var album = [];
|
||||
for (var i in d.{field}) {
|
||||
album[i] = '<a href="javascript:" class="fileslink" ><img class="filesuffix" lay-image-click src="'+d.{field}[i].src+'"></a>'
|
||||
}
|
||||
return album.join('');
|
||||
}
|
||||
4
app/admin/controller/developer/stubs/list/radio.stub
Normal file
4
app/admin/controller/developer/stubs/list/radio.stub
Normal file
@@ -0,0 +1,4 @@
|
||||
templet:function(d) {
|
||||
var colsArr = {colsArr};
|
||||
return colsArr[d.{field}].title;
|
||||
}
|
||||
4
app/admin/controller/developer/stubs/list/select.stub
Normal file
4
app/admin/controller/developer/stubs/list/select.stub
Normal file
@@ -0,0 +1,4 @@
|
||||
templet:function(d) {
|
||||
var colsArr = {colsArr};
|
||||
return colsArr[d.{field}].title;
|
||||
}
|
||||
3
app/admin/controller/developer/stubs/list/tags.stub
Normal file
3
app/admin/controller/developer/stubs/list/tags.stub
Normal file
@@ -0,0 +1,3 @@
|
||||
templet:function(d) {
|
||||
return d.{field}.replace(',',' ');
|
||||
}
|
||||
8
app/admin/controller/developer/stubs/method.stub
Normal file
8
app/admin/controller/developer/stubs/method.stub
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* method 函数
|
||||
*/
|
||||
public function method()
|
||||
{
|
||||
return $this->view();
|
||||
}
|
||||
|
||||
28
app/admin/controller/developer/stubs/model.stub
Normal file
28
app/admin/controller/developer/stubs/model.stub
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace {%modelNamespace%};
|
||||
|
||||
use think\Model;
|
||||
{%softDeleteClassPath%}
|
||||
|
||||
/**
|
||||
* {%table%}
|
||||
* <!--{%pluginClass%}-->
|
||||
* {%title%}
|
||||
* Class {%modelName%}
|
||||
* @package {%modelNamespace%}
|
||||
*/
|
||||
class {%modelName%} extends Model
|
||||
{
|
||||
|
||||
{%softDelete%}
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = {%createTime%};
|
||||
protected $updateTime = {%updateTime%};
|
||||
protected $deleteTime = {%deleteTime%};
|
||||
|
||||
{%relationMethodList%}
|
||||
{%fieldAttrArr%}
|
||||
|
||||
}
|
||||
BIN
app/admin/controller/developer/stubs/plugin_init.stub
Normal file
BIN
app/admin/controller/developer/stubs/plugin_init.stub
Normal file
Binary file not shown.
5
app/admin/controller/developer/stubs/radio.stub
Normal file
5
app/admin/controller/developer/stubs/radio.stub
Normal file
@@ -0,0 +1,5 @@
|
||||
<if (isset($data['id'])) && $data['id']>
|
||||
<eq name="$vo.checked" value="true">checked</eq>
|
||||
<else/>
|
||||
<eq name="$vo.value" value="$data.fieldName">checked</eq>
|
||||
</if>
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="layui-inline">
|
||||
<div class="layui-form-label">{:__('{%title%}')}</div>
|
||||
<div class="layui-input-inline ">
|
||||
<input name="{%field%}" lay-cascader="" class="layui-input" type="text" placeholder="{:__('{%title%}')}"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="layui-inline">
|
||||
<div class="layui-form-label">{:__('{%title%}')}</div>
|
||||
<div class="layui-input-inline ">
|
||||
<input name="{%field%}" lay-datetime data-range="true" data-type="date" data-dateformat="yyyy/MM/dd" class="layui-input" type="text" placeholder="{:__('{%title%}')}"/>
|
||||
</div>
|
||||
</div>
|
||||
6
app/admin/controller/developer/stubs/search/input.stub
Normal file
6
app/admin/controller/developer/stubs/search/input.stub
Normal file
@@ -0,0 +1,6 @@
|
||||
<div class="layui-inline">
|
||||
<div class="layui-form-label">{:__('{%title%}')}</div>
|
||||
<div class="layui-input-inline ">
|
||||
<input name="{%field%}" class="layui-input" type="text" placeholder="{:__('{%title%}')}"/>
|
||||
</div>
|
||||
</div>
|
||||
7
app/admin/controller/developer/stubs/search/rate.stub
Normal file
7
app/admin/controller/developer/stubs/search/rate.stub
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="layui-inline">
|
||||
<div class="layui-form-label">{:__('{%title%}')}</div>
|
||||
<div class="layui-input-inline" style="max-height:20px;">
|
||||
<input name="{%field%}" class="layui-input layui-hide {%field%}" type="text" placeholder="{:__('{%title%}')}"/>
|
||||
<div lay-rate="{%field%}" data-default="1" data-theme="{theme}" data-length="{length}" class="layui-inline"></div>
|
||||
</div>
|
||||
</div>
|
||||
13
app/admin/controller/developer/stubs/search/select.stub
Normal file
13
app/admin/controller/developer/stubs/search/select.stub
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
<div class="layui-inline">
|
||||
<div class="layui-form-label">{:__('{%title%}')}</div>
|
||||
<div class="layui-input-inline ">
|
||||
<php> ${%varlist%} = {%vardata%}; </php>
|
||||
<select name="{%field%}" lay-search >
|
||||
<option value="">{:__('请选择')}</option>
|
||||
<volist name="{%varlist%}" id="vo">
|
||||
<option value="{$vo.value}">{$vo.title}</option>
|
||||
</volist>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
7
app/admin/controller/developer/stubs/search/slider.stub
Normal file
7
app/admin/controller/developer/stubs/search/slider.stub
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="layui-inline">
|
||||
<div class="layui-form-label">{:__('{%title%}')}</div>
|
||||
<div class="layui-input-inline ">
|
||||
<input name="{%field%}" class="layui-input layui-hide" type="text" />
|
||||
<div lay-slider="{%field%}" data_default="{default}" data-theme="{theme}" data-step="{step}" data-max="{max}" data-min="{min}" data-input="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
7
app/admin/controller/developer/stubs/search/status.stub
Normal file
7
app/admin/controller/developer/stubs/search/status.stub
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="layui-inline">
|
||||
<select name="status">
|
||||
<option value="">{:__('按状态查询')}</option>
|
||||
<option value="2" >{:__('正常')}</option>
|
||||
<option value="1" >{:__('关闭')}</option>
|
||||
</select>
|
||||
</div>
|
||||
36
app/admin/controller/developer/stubs/validate.stub
Normal file
36
app/admin/controller/developer/stubs/validate.stub
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace {%validateNamespace%};
|
||||
|
||||
use think\Validate;
|
||||
/**
|
||||
* <!--{%pluginClass%}-->
|
||||
* {%validateName%} 验证器
|
||||
* Class {%validateName%}
|
||||
* @package {%validateNamespace%}
|
||||
*/
|
||||
class {%validateName%} extends Validate
|
||||
{
|
||||
/**
|
||||
* 验证规则
|
||||
*/
|
||||
protected $rule = [
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*/
|
||||
protected $message = [
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 验证场景
|
||||
*/
|
||||
protected $scene = [
|
||||
'add' => [],
|
||||
'edit' => [],
|
||||
];
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user