first commit
This commit is contained in:
21
modules/Develop/Http/Controllers/GenerateController.php
Normal file
21
modules/Develop/Http/Controllers/GenerateController.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Http\Controllers;
|
||||
|
||||
use Catch\Base\CatchController as Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Develop\Support\Generate\Generator;
|
||||
|
||||
class GenerateController extends Controller
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Generator $generator
|
||||
* @throws Exception
|
||||
*/
|
||||
public function index(Request $request, Generator $generator)
|
||||
{
|
||||
$generator->setParams($request->all())->generate();
|
||||
}
|
||||
}
|
91
modules/Develop/Http/Controllers/ModuleController.php
Normal file
91
modules/Develop/Http/Controllers/ModuleController.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Http\Controllers;
|
||||
|
||||
use Catch\Base\CatchController;
|
||||
use Catch\Support\Module\ModuleRepository;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ModuleController extends CatchController
|
||||
{
|
||||
protected ModuleRepository $repository;
|
||||
|
||||
/**
|
||||
* @param ModuleRepository $repository
|
||||
*/
|
||||
public function __construct(ModuleRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* index
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Collection
|
||||
*/
|
||||
public function index(Request $request): Collection
|
||||
{
|
||||
return $this->repository->all($request->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* store
|
||||
*
|
||||
* @param Request $request
|
||||
* @return bool|int
|
||||
*/
|
||||
public function store(Request $request): bool|int
|
||||
{
|
||||
return $this->repository->create($request->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* show
|
||||
*
|
||||
* @param string $name
|
||||
* @return Collection
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function show(mixed $name): Collection
|
||||
{
|
||||
return $this->repository->show($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* update
|
||||
*
|
||||
* @param $name
|
||||
* @param Request $request
|
||||
* @return bool|int
|
||||
*/
|
||||
public function update($name, Request $request): bool|int
|
||||
{
|
||||
return $this->repository->update($name, $request->all());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update
|
||||
*
|
||||
* @param $name
|
||||
* @return bool|int
|
||||
*/
|
||||
public function enable($name): bool|int
|
||||
{
|
||||
return $this->repository->disOrEnable($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy
|
||||
*
|
||||
* @param $name
|
||||
* @return bool|int
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function destroy($name): bool|int
|
||||
{
|
||||
return $this->repository->delete($name);
|
||||
}
|
||||
}
|
61
modules/Develop/Http/Controllers/SchemaController.php
Normal file
61
modules/Develop/Http/Controllers/SchemaController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Http\Controllers;
|
||||
|
||||
use Catch\Base\CatchController;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Develop\Models\Schemas;
|
||||
|
||||
/**
|
||||
* SchemaController
|
||||
*/
|
||||
class SchemaController extends CatchController
|
||||
{
|
||||
public function __construct(
|
||||
protected Schemas $schemas
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->schemas->getList();
|
||||
}
|
||||
|
||||
/**
|
||||
* store
|
||||
*
|
||||
* @param Request $request
|
||||
* @throws \Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
return $this->schemas->storeBy($request->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* show
|
||||
*
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return $this->schemas->show($id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* destroy
|
||||
*
|
||||
* @param $id
|
||||
* @return bool|null
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
return $this->schemas->deleteBy($id);
|
||||
}
|
||||
}
|
39
modules/Develop/Listeners/CreatedListener.php
Normal file
39
modules/Develop/Listeners/CreatedListener.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Listeners;
|
||||
|
||||
use Catch\Events\Module\Created;
|
||||
use Modules\Develop\Support\Generate\Module;
|
||||
|
||||
class CreatedListener
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param Created $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Created $event): void
|
||||
{
|
||||
$module = $event->module;
|
||||
|
||||
(new Module(
|
||||
$module['path'],
|
||||
$module['dirs']['controllers'],
|
||||
$module['dirs']['models'],
|
||||
$module['dirs']['requests'],
|
||||
$module['dirs']['database']
|
||||
)
|
||||
)->create();
|
||||
}
|
||||
}
|
30
modules/Develop/Listeners/DeletedListener.php
Normal file
30
modules/Develop/Listeners/DeletedListener.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Listeners;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Catch\Events\Module\Deleted;
|
||||
|
||||
class DeletedListener
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param Deleted $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Deleted $event): void
|
||||
{
|
||||
CatchAdmin::deleteModulePath($event->module['path']);
|
||||
}
|
||||
}
|
129
modules/Develop/Models/Schemas.php
Normal file
129
modules/Develop/Models/Schemas.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Models;
|
||||
|
||||
use Catch\Base\CatchModel;
|
||||
use Catch\Enums\Status;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Develop\Support\Generate\Create\Schema;
|
||||
use Illuminate\Support\Facades\Schema as SchemaFacade;
|
||||
|
||||
class Schemas extends CatchModel
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'schemas';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
'id', 'module', 'name', 'columns', 'is_soft_delete', 'created_at', 'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $isPaginate = true;
|
||||
|
||||
/**
|
||||
* @var array|string[]
|
||||
*/
|
||||
public array $searchable = ['module' => 'like', 'name' => 'like'];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $mergeCasts = [
|
||||
'is_soft_delete' => Status::class
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $data
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function storeBy(array $data): bool
|
||||
{
|
||||
$schema = $data['schema'];
|
||||
|
||||
$structures = $data['structures'];
|
||||
|
||||
$schemaId = parent::storeBy([
|
||||
'module' => $schema['module'],
|
||||
|
||||
'name' => $schema['name'],
|
||||
|
||||
'columns' => implode(',', array_column($structures, 'field')),
|
||||
|
||||
'is_soft_delete' => $schema['deleted_at'] ? Status::Enable : Status::Disable
|
||||
]);
|
||||
|
||||
try {
|
||||
$schemaCreate = new Schema($schema['name'], $schema['engine'], $schema['charset'], $schema['collection'], $schema['comment']);
|
||||
|
||||
$schemaCreate->setStructures($structures)
|
||||
->setModule($schema['module'])
|
||||
->setCreatedAt($schema['created_at'])
|
||||
->setCreatorId($schema['creator_id'])
|
||||
->setUpdatedAt($schema['updated_at'])
|
||||
->setDeletedAt($schema['deleted_at'])
|
||||
->create();
|
||||
} catch (Exception $e) {
|
||||
parent::deleteBy($schemaId, true);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return Model
|
||||
*/
|
||||
public function show($id): Model
|
||||
{
|
||||
$schema = parent::firstBy($id);
|
||||
|
||||
$columns = [];
|
||||
|
||||
foreach (getTableColumns($schema->name) as $columnString) {
|
||||
$column = DB::connection()->getDoctrineColumn(DB::connection()->getTablePrefix().$schema->name, $columnString);
|
||||
$columns[] = [
|
||||
'name' => $column->getName(),
|
||||
'type' => $column->getType()->getName(),
|
||||
'nullable' => ! $column->getNotnull(),
|
||||
'default' => $column->getDefault(),
|
||||
'comment' => $column->getComment()
|
||||
];
|
||||
}
|
||||
|
||||
$schema->columns = $columns;
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete
|
||||
*
|
||||
* @param $id
|
||||
* @param bool $force
|
||||
* @return bool|null
|
||||
*/
|
||||
public function deleteBy($id, bool $force = false): ?bool
|
||||
{
|
||||
$schema = parent::firstBy($id);
|
||||
|
||||
if ($schema->delete()) {
|
||||
SchemaFacade::dropIfExists($schema->name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
30
modules/Develop/Providers/DevelopServiceProvider.php
Normal file
30
modules/Develop/Providers/DevelopServiceProvider.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Providers;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Catch\Events\Module\Created;
|
||||
use Catch\Events\Module\Deleted;
|
||||
use Catch\Providers\CatchModuleServiceProvider;
|
||||
use Modules\Develop\Listeners\CreatedListener;
|
||||
use Modules\Develop\Listeners\DeletedListener;
|
||||
|
||||
class DevelopServiceProvider extends CatchModuleServiceProvider
|
||||
{
|
||||
protected array $events = [
|
||||
Created::class => CreatedListener::class,
|
||||
|
||||
Deleted::class => DeletedListener::class
|
||||
];
|
||||
|
||||
/**
|
||||
* route path
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function routePath(): string|array
|
||||
{
|
||||
// TODO: Implement path() method.
|
||||
return CatchAdmin::getModuleRoutePath('develop');
|
||||
}
|
||||
}
|
40
modules/Develop/Providers/Install.php
Normal file
40
modules/Develop/Providers/Install.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Providers;
|
||||
|
||||
use Catch\Support\Module\Installer;
|
||||
|
||||
/**
|
||||
* install
|
||||
*/
|
||||
class Install extends Installer
|
||||
{
|
||||
protected function info(): array
|
||||
{
|
||||
// TODO: Implement info() method.
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
protected function migration(): string
|
||||
{
|
||||
// TODO: Implement migration() method.
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function seeder(): string
|
||||
{
|
||||
// TODO: Implement seed() method.
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function requirePackages(): void
|
||||
{
|
||||
// TODO: Implement requirePackages() method.
|
||||
}
|
||||
|
||||
protected function removePackages(): void
|
||||
{
|
||||
// TODO: Implement removePackages() method.
|
||||
}
|
||||
}
|
111
modules/Develop/Support/Generate/Create/Controller.php
Normal file
111
modules/Develop/Support/Generate/Create/Controller.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Controller extends Creator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $replace = [
|
||||
'{namespace}', '{uses}', '{controller}', '{model}', '{request}'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
* @param string $model
|
||||
* @param string|null $request
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $controller,
|
||||
public readonly string $model,
|
||||
public readonly ?string $request = null
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
// TODO: Implement getFile() method.
|
||||
return CatchAdmin::getModuleControllerPath($this->module).$this->getControllerName().$this->ext;
|
||||
}
|
||||
|
||||
public function getContent(): string|bool
|
||||
{
|
||||
// TODO: Implement getContent() method.
|
||||
return Str::of(File::get($this->getControllerStub()))->replace($this->replace, [
|
||||
$this->getControllerNamespace(),
|
||||
|
||||
$this->getUses(),
|
||||
|
||||
$this->getControllerName(),
|
||||
|
||||
$this->model,
|
||||
|
||||
$this->request ?: 'Request'
|
||||
])->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get controller name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getControllerName(): string
|
||||
{
|
||||
return Str::of($this->controller)->whenContains('Controller', function ($value) {
|
||||
return Str::of($value)->ucfirst();
|
||||
}, function ($value) {
|
||||
return Str::of($value)->append('Controller')->ucfirst();
|
||||
})->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get uses
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUses(): string
|
||||
{
|
||||
return Str::of('use ')
|
||||
->append(CatchAdmin::getModuleModelNamespace($this->module).$this->model)
|
||||
->append(';')
|
||||
->newLine()
|
||||
->append('use ')
|
||||
->when($this->request, function ($str) {
|
||||
return $str->append(CatchAdmin::getModuleRequestNamespace($this->module).$this->request);
|
||||
}, function ($str) {
|
||||
return $str->append("Illuminate\Http\Request");
|
||||
})->append(';')->newLine()->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get controller stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getControllerStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'controller.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* get controller namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getControllerNamespace(): string
|
||||
{
|
||||
return Str::of(CatchAdmin::getModuleControllerNamespace($this->module))->rtrim('\\')->append(';')->toString();
|
||||
}
|
||||
}
|
112
modules/Develop/Support/Generate/Create/Creator.php
Normal file
112
modules/Develop/Support/Generate/Create/Creator.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
/**
|
||||
* creator
|
||||
*/
|
||||
abstract class Creator
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $ext = '.php';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $module;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $file;
|
||||
|
||||
/**
|
||||
* create
|
||||
*
|
||||
* @return bool|string
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public function create(): bool|string
|
||||
{
|
||||
return $this->put();
|
||||
}
|
||||
|
||||
/**
|
||||
* the file which content put in
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getFile(): string;
|
||||
|
||||
/**
|
||||
* get content
|
||||
* @return string|bool
|
||||
*/
|
||||
abstract public function getContent(): string|bool;
|
||||
|
||||
/**
|
||||
* @return string|bool
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
protected function put(): string|bool
|
||||
{
|
||||
if (! $this->getContent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->file = $this->getFile();
|
||||
|
||||
File::put($this->file, $this->getContent());
|
||||
|
||||
if (File::exists($this->file)) {
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("create [$this->file] failed");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set ext
|
||||
*
|
||||
* @param string $ext
|
||||
* @return $this
|
||||
*/
|
||||
protected function setExt(string $ext): static
|
||||
{
|
||||
$this->ext = $ext;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set module
|
||||
*
|
||||
* @param string $module
|
||||
* @return $this
|
||||
*/
|
||||
public function setModule(string $module): static
|
||||
{
|
||||
$this->module = $module;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGenerateFile(): string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
}
|
188
modules/Develop/Support/Generate/Create/FrontForm.php
Normal file
188
modules/Develop/Support/Generate/Create/FrontForm.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | CatchAdmin [Just Like ~ ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class FrontForm extends Creator
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $label = '{label}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $prop = '{prop}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $modelValue = '{model-value}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $table = '{table}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $search = '{search}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $api = '{api}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $formItems = '{formItems}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $paginate = '{paginate}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $useList = '{useList}';
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $structures;
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
*/
|
||||
public function __construct(protected readonly string $controller)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* get content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
// TODO: Implement getContent() method.
|
||||
return Str::of(File::get($this->getFormStub()))->replace($this->formItems, $this->getFormContent())->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
// TODO: Implement getFile() method.
|
||||
return CatchAdmin::makeDir(CatchAdmin::getModuleViewsPath($this->module).Str::of($this->controller)->replace('Controller', '')->lcfirst()).DIRECTORY_SEPARATOR.'create.vue';
|
||||
}
|
||||
|
||||
/**
|
||||
* get form content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFormContent(): string
|
||||
{
|
||||
$form = Str::of('');
|
||||
|
||||
$formComponents = $this->formComponents();
|
||||
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['label'] && $structure['form_component'] && $structure['form']) {
|
||||
if (isset($formComponents[$structure['form_component']])) {
|
||||
$form = $form->append(
|
||||
Str::of($formComponents[$structure['form_component']])
|
||||
->replace(
|
||||
[$this->label, $this->prop, $this->modelValue],
|
||||
[$structure['label'], $structure['field'], sprintf('formData.%s', $structure['field'])]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $form->trim(PHP_EOL)->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* form components
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function formComponents(): array
|
||||
{
|
||||
$components = [];
|
||||
|
||||
foreach (File::glob(
|
||||
$this->getFormItemStub()
|
||||
) as $stub) {
|
||||
$components[File::name($stub)] = File::get($stub);
|
||||
}
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get formItem stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFormItemStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'
|
||||
|
||||
.DIRECTORY_SEPARATOR.'vue'.DIRECTORY_SEPARATOR
|
||||
|
||||
.'formItems'.DIRECTORY_SEPARATOR.'*.stub';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get form stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFormStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'
|
||||
|
||||
.DIRECTORY_SEPARATOR.'vue'.DIRECTORY_SEPARATOR.'form.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* set structures
|
||||
*
|
||||
* @param array $structures
|
||||
* @return $this
|
||||
*/
|
||||
public function setStructures(array $structures): static
|
||||
{
|
||||
$this->structures = $structures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
252
modules/Develop/Support/Generate/Create/FrontTable.php
Normal file
252
modules/Develop/Support/Generate/Create/FrontTable.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | CatchAdmin [Just Like ~ ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class FrontTable extends Creator
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $label = '{label}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $prop = '{prop}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $modelValue = '{model-value}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $table = '{table}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $search = '{search}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $api = '{api}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $formItems = '{formItems}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $paginate = '{paginate}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $useList = '{useList}';
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $structures;
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
* @param bool $hasPaginate
|
||||
* @param string $apiString
|
||||
*/
|
||||
public function __construct(
|
||||
protected readonly string $controller,
|
||||
protected readonly bool $hasPaginate,
|
||||
protected readonly string $apiString
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* get content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
// TODO: Implement getContent() method.
|
||||
return Str::of(File::get($this->getTableStub()))->replace([
|
||||
$this->table, $this->search, $this->api, $this->paginate, $this->useList
|
||||
], [
|
||||
$this->getTableContent(), $this->getSearchContent(),
|
||||
"'{$this->apiString}'", $this->getPaginateStubContent(), $this->getUseList()
|
||||
])->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
// TODO: Implement getFile() method.
|
||||
return CatchAdmin::makeDir(CatchAdmin::getModuleViewsPath($this->module).Str::of($this->controller)->replace('Controller', '')->lcfirst()).DIRECTORY_SEPARATOR.'index.vue';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get search content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSearchContent(): string
|
||||
{
|
||||
$search = Str::of('');
|
||||
|
||||
$formComponents = $this->formComponents();
|
||||
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['label'] && $structure['form_component'] && $structure['search']) {
|
||||
if (isset($formComponents[$structure['form_component']])) {
|
||||
$search = $search->append(
|
||||
Str::of($formComponents[$structure['form_component']])
|
||||
->replace(
|
||||
[$this->label, $this->prop, $this->modelValue],
|
||||
[$structure['label'], $structure['field'], sprintf('query.%s', $structure['field'])]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $search->trim(PHP_EOL)->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get list content;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTableContent(): string
|
||||
{
|
||||
$tableColumn = <<<HTML
|
||||
<el-table-column prop="{prop}" label="{label}" />
|
||||
HTML;
|
||||
|
||||
$table = Str::of('');
|
||||
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['field'] && $structure['label'] && $structure['list']) {
|
||||
$table = $table->append(
|
||||
Str::of($tableColumn)->replace([$this->label, $this->prop], [$structure['label'], $structure['field']])
|
||||
)->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
return $table->trim(PHP_EOL)->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* form components
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function formComponents(): array
|
||||
{
|
||||
$components = [];
|
||||
|
||||
foreach (File::glob(
|
||||
$this->getFormItemStub()
|
||||
) as $stub) {
|
||||
$components[File::name($stub)] = File::get($stub);
|
||||
}
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get formItem stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFormItemStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'
|
||||
|
||||
.DIRECTORY_SEPARATOR.'vue'.DIRECTORY_SEPARATOR
|
||||
|
||||
.'formItems'.DIRECTORY_SEPARATOR.'*.stub';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get table stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTableStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'
|
||||
|
||||
.DIRECTORY_SEPARATOR.'vue'.DIRECTORY_SEPARATOR.'table.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* get paginate stub content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPaginateStubContent(): string
|
||||
{
|
||||
return $this->hasPaginate ?
|
||||
File::get(
|
||||
dirname(__DIR__).DIRECTORY_SEPARATOR
|
||||
|
||||
.'stubs'.DIRECTORY_SEPARATOR.'vue'.
|
||||
|
||||
DIRECTORY_SEPARATOR.'paginate.stub'
|
||||
)
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* get use List
|
||||
* @return string
|
||||
*/
|
||||
protected function getUseList(): string
|
||||
{
|
||||
return $this->hasPaginate ?
|
||||
'const { data, query, search, reset, changePage, changeLimit, loading } = useGetList(api)' :
|
||||
'const { data, query, search, reset, loading } = useGetList(api)';
|
||||
}
|
||||
|
||||
/**
|
||||
* set structures
|
||||
*
|
||||
* @param array $structures
|
||||
* @return $this
|
||||
*/
|
||||
public function setStructures(array $structures): static
|
||||
{
|
||||
$this->structures = $structures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
276
modules/Develop/Support/Generate/Create/Model.php
Normal file
276
modules/Develop/Support/Generate/Create/Model.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | CatchAdmin [Just Like ~ ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Schema as SchemaFacade;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
||||
|
||||
class Model extends Creator
|
||||
{
|
||||
protected array $replace = [
|
||||
'{uses}',
|
||||
'{property}',
|
||||
'{namespace}',
|
||||
'{model}',
|
||||
'{traits}',
|
||||
'{table}',
|
||||
'{fillable}',
|
||||
'{searchable}',
|
||||
'{fieldsInList}',
|
||||
'{isPaginate}', '{form}'
|
||||
];
|
||||
|
||||
protected array $structures;
|
||||
|
||||
protected bool $softDelete;
|
||||
|
||||
/**
|
||||
* @param string $modelName
|
||||
* @param string $tableName
|
||||
* @param bool $isPaginate
|
||||
*/
|
||||
public function __construct(
|
||||
protected string $modelName,
|
||||
protected readonly string $tableName,
|
||||
protected readonly bool $isPaginate
|
||||
) {
|
||||
$model = new class () extends EloquentModel {
|
||||
use SoftDeletes;
|
||||
};
|
||||
|
||||
$this->softDelete = in_array($model->getDeletedAtColumn(), SchemaFacade::getColumnListing($this->tableName));
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
// TODO: Implement getFile() method.
|
||||
return CatchAdmin::getModuleModelPath($this->module).$this->getModelName().$this->ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* get content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
$modelStub = File::get($this->getModelStub());
|
||||
|
||||
|
||||
return Str::of($modelStub)->replace($this->replace, [$this->getUses(),
|
||||
$this->getProperties(),
|
||||
$this->getModelNamespace(),
|
||||
$this->getModelName(),
|
||||
$this->getTraits(),
|
||||
$this->tableName,
|
||||
$this->getFillable(),
|
||||
$this->getSearchable(),
|
||||
$this->getFieldsInList(),
|
||||
$this->isPaginate(),
|
||||
$this->getInForm()
|
||||
])->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get model namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getModelNamespace(): string
|
||||
{
|
||||
return Str::of(CatchAdmin::getModuleModelNamespace($this->module))->trim('\\')->append(';')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get model name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getModelName(): string
|
||||
{
|
||||
$modelName = Str::of($this->modelName);
|
||||
|
||||
if (! $modelName->length()) {
|
||||
$modelName = Str::of($this->tableName)->camel();
|
||||
}
|
||||
|
||||
return $modelName->ucfirst()->whenContains('Model', function ($value) {
|
||||
return Str::of($value);
|
||||
}, function ($value) {
|
||||
return Str::of($value)->append('Model');
|
||||
})->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get uses
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUses(): string
|
||||
{
|
||||
if (! $this->softDelete) {
|
||||
return <<<Text
|
||||
use Catch\Traits\DB\BaseOperate;
|
||||
use Catch\Traits\DB\ScopeTrait;
|
||||
use Catch\Traits\DB\Trans;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
Text;
|
||||
} else {
|
||||
return <<<Text
|
||||
use Catch\Base\CatchModel as Model;
|
||||
Text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get traits
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTraits(): string
|
||||
{
|
||||
return $this->softDelete ? '' : 'use BaseOperate, Trans, ScopeTrait;';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getProperties(): string
|
||||
{
|
||||
$comment = Str::of('/**')->newLine();
|
||||
|
||||
foreach ($this->getTableColumns() as $column) {
|
||||
$comment = $comment->append(sprintf(' * @property $%s', $column))->newLine();
|
||||
}
|
||||
|
||||
return $comment->append('*/')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get fillable
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFillable(): string
|
||||
{
|
||||
$fillable = Str::of('');
|
||||
|
||||
foreach ($this->getTableColumns() as $column) {
|
||||
$fillable = $fillable->append(" '{$column}'")->append(',');
|
||||
}
|
||||
|
||||
return $fillable->rtrim(',')->toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTableColumns(): array
|
||||
{
|
||||
return getTableColumns($this->tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* get field in list
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFieldsInList(): string
|
||||
{
|
||||
$str = Str::of('');
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['list']) {
|
||||
$str = $str->append("'{$structure['field']}'")->append(',');
|
||||
}
|
||||
}
|
||||
|
||||
return $str->rtrim(',')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get field in list
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getInForm(): string
|
||||
{
|
||||
$str = Str::of('');
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['form']) {
|
||||
$str = $str->append("'{$structure['field']}'")->append(',');
|
||||
}
|
||||
}
|
||||
|
||||
return $str->rtrim(',')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* searchable
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSearchable(): string
|
||||
{
|
||||
$searchable = Str::of('');
|
||||
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['search'] && $structure['field'] && $structure['search_op']) {
|
||||
$searchable = $searchable->append(sprintf("'%s' => '%s'", $structure['field'], $structure['search_op']))->append(',')->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
return $searchable->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function isPaginate(): string
|
||||
{
|
||||
return $this->isPaginate ? '' : Str::of('protected bool $isPaginate = false;')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $structures
|
||||
* @return $this
|
||||
*/
|
||||
public function setStructures(array $structures): static
|
||||
{
|
||||
$this->structures = $structures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* get stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getModelStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'model.stub';
|
||||
}
|
||||
}
|
138
modules/Develop/Support/Generate/Create/Request.php
Normal file
138
modules/Develop/Support/Generate/Create/Request.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Request extends Creator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $structures;
|
||||
|
||||
/**
|
||||
* @var array|string[]
|
||||
*/
|
||||
protected array $replace = ['{namespace}', '{request}', '{rule}'];
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
*/
|
||||
public function __construct(public readonly string $controller)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
return CatchAdmin::getModuleRequestPath($this->module).$this->getRequestName().$this->ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* get content
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getContent(): string|bool
|
||||
{
|
||||
$rule = $this->getRulesString();
|
||||
|
||||
if (! $rule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Str::of(
|
||||
File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'request.stub')
|
||||
)->replace($this->replace, [$this->getNamespace(), $this->getRequestName(), $rule])->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getNamespace(): string
|
||||
{
|
||||
return Str::of(CatchAdmin::getModuleRequestNamespace($this->module))->rtrim('\\')->append(';')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get request name
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function getRequestName(): ?string
|
||||
{
|
||||
if ($this->getRules()) {
|
||||
return Str::of($this->controller)->remove('Controller')->append('Request')->ucfirst()->toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get rule
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getRulesString(): string|bool
|
||||
{
|
||||
$rules = $this->getRules();
|
||||
|
||||
if (! count($rules)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rule = Str::of('');
|
||||
|
||||
foreach ($rules as $field => $validates) {
|
||||
$rule = $rule->append("'{$field}'")
|
||||
->append(' => ')
|
||||
->append('\'')
|
||||
->append(Arr::join($validates, '|'))
|
||||
->append('\',')
|
||||
->newLine();
|
||||
}
|
||||
|
||||
return $rule->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get rules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
foreach ($this->structures as $structure) {
|
||||
if ($structure['field'] && count($structure['validates'])) {
|
||||
$rules[$structure['field']] = $structure['validates'];
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* set structures
|
||||
*
|
||||
* @param array $structures
|
||||
* @return $this
|
||||
*/
|
||||
public function setStructures(array $structures): static
|
||||
{
|
||||
$this->structures = $structures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
123
modules/Develop/Support/Generate/Create/Route.php
Normal file
123
modules/Develop/Support/Generate/Create/Route.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Route
|
||||
*/
|
||||
class Route extends Creator
|
||||
{
|
||||
/**
|
||||
* @param string $controller
|
||||
*/
|
||||
public function __construct(public readonly string $controller)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
return CatchAdmin::getModuleRoutePath($this->module);
|
||||
}
|
||||
|
||||
/**
|
||||
* get content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
// route 主要添加两个点
|
||||
// use Controller
|
||||
// 添加路由
|
||||
$route = Str::of('');
|
||||
|
||||
$originContent = File::get(CatchAdmin::getModuleRoutePath($this->module));
|
||||
|
||||
// 如果已经有 controller,就不再追加路由
|
||||
if (Str::of($originContent)->contains($this->getUserController())) {
|
||||
return $originContent;
|
||||
}
|
||||
|
||||
File::lines(CatchAdmin::getModuleRoutePath($this->module))
|
||||
->each(function ($line) use (&$route) {
|
||||
if (Str::of($line)->contains('Route::prefix')) {
|
||||
$route = $route->trim(PHP_EOL)
|
||||
->newLine()
|
||||
->append($this->getUserController())
|
||||
->append(';')
|
||||
->newLine(2)
|
||||
->append($line)
|
||||
->newLine();
|
||||
} else {
|
||||
$route = $route->append($line)->newLine();
|
||||
}
|
||||
});
|
||||
|
||||
$apiResource = "Route::apiResource('{api}', {controller}::class);";
|
||||
|
||||
return Str::of($route->toString())->replace(
|
||||
['{module}', '//next'],
|
||||
[
|
||||
lcfirst($this->module),
|
||||
Str::of($apiResource)->replace(['{api}', '{controller}'], [$this->getApiString(), $this->getControllerName()])
|
||||
->prepend("\t")
|
||||
->prepend(PHP_EOL)
|
||||
->newLine()->append("\t//next")]
|
||||
)->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get api
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getApiString(): string
|
||||
{
|
||||
return Str::of($this->getControllerName())->remove('Controller')->snake('_')->replace('_', '/')->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get api route
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getApiRute(): string
|
||||
{
|
||||
return lcfirst($this->module).'/'.$this->getApiString();
|
||||
}
|
||||
|
||||
/**
|
||||
* use controller
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUserController(): string
|
||||
{
|
||||
return 'use '.CatchAdmin::getModuleControllerNamespace($this->module).$this->getControllerName();
|
||||
}
|
||||
|
||||
/**
|
||||
* get controller name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getControllerName(): string
|
||||
{
|
||||
return Str::of($this->controller)->whenContains('Controller', function ($value) {
|
||||
return Str::of($value)->ucfirst();
|
||||
}, function ($value) {
|
||||
return Str::of($value)->append('Controller')->ucfirst();
|
||||
})->toString();
|
||||
}
|
||||
}
|
317
modules/Develop/Support/Generate/Create/Schema.php
Normal file
317
modules/Develop/Support/Generate/Create/Schema.php
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | CatchAdmin [Just Like ~ ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Develop\Support\Generate\Create;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Exception;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Schema as MigrationSchema;
|
||||
|
||||
/**
|
||||
* schema
|
||||
*/
|
||||
class Schema extends Creator
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $createdAt = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $updatedAt = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $deletedAt = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $creatorId = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $structures = [];
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $engine
|
||||
* @param string $charset
|
||||
* @param string $collection
|
||||
* @param string $comment
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $table,
|
||||
public readonly string $engine,
|
||||
public readonly string $charset,
|
||||
public readonly string $collection,
|
||||
public readonly string $comment
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* create
|
||||
*
|
||||
* @return string|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create(): string|bool
|
||||
{
|
||||
if (! count($this->structures)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MigrationSchema::hasTable($this->table)) {
|
||||
throw new Exception(sprintf('[%s] 表已经存在', $this->table));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->createTable();
|
||||
|
||||
if (MigrationSchema::hasTable($this->table)) {
|
||||
return parent::create();
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
MigrationSchema::dropIfExists($this->table);
|
||||
throw new Exception("由于{$e->getMessage()}, 表[{$this->table}]创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile(): string
|
||||
{
|
||||
// TODO: Implement getFile() method.
|
||||
return CatchAdmin::getModuleMigrationPath($this->module).date('Y_m_d_his_').'create_'.$this->table.'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* create table
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function createTable(): void
|
||||
{
|
||||
MigrationSchema::create($this->table, function (Blueprint $table) {
|
||||
foreach ($this->structures as $structure) {
|
||||
// if field && type hava value
|
||||
if ($structure['type'] && $structure['field']) {
|
||||
if ($structure['type'] == 'string') {
|
||||
$column = $table->string($structure['field'], $structure['length'] ?: 255);
|
||||
} elseif ($structure['type'] == 'char') {
|
||||
$column = $table->char($structure['field'], $structure['length']);
|
||||
} else {
|
||||
$column = $table->{$structure['type']}($structure['field']);
|
||||
}
|
||||
|
||||
$column = $column->nullable($structure['nullable']);
|
||||
|
||||
if ($structure['default']) {
|
||||
$column = $column->default($structure['default']);
|
||||
}
|
||||
|
||||
if ($structure['comment']) {
|
||||
$column = $column->comment($structure['comment']);
|
||||
}
|
||||
|
||||
if ($structure['unique']) {
|
||||
$column->unique($structure['unique']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->creatorId) {
|
||||
$table->creatorId();
|
||||
}
|
||||
|
||||
if ($this->createdAt) {
|
||||
$table->createdAt();
|
||||
}
|
||||
|
||||
if ($this->updatedAt) {
|
||||
$table->updatedAt();
|
||||
}
|
||||
|
||||
if ($this->deletedAt) {
|
||||
$table->deletedAt();
|
||||
}
|
||||
|
||||
$table->charset = $this->charset;
|
||||
$table->engine = $this->engine;
|
||||
$table->collation = $this->collection;
|
||||
$table->comment($this->comment);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get migration content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
$stub = File::get($this->getStub());
|
||||
|
||||
return Str::of($stub)->replace(['{method}','{table}', '{content}'], ['create', $this->table, $this->getMigrationContent()])->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMigrationContent(): string
|
||||
{
|
||||
$content = Str::of('');
|
||||
|
||||
foreach ($this->structures as $structure) {
|
||||
$begin = Str::of('$table->');
|
||||
$type = Str::of($structure['type']);
|
||||
|
||||
if ($type->exactly('string')) {
|
||||
$begin = $begin->append(sprintf("string('%s'%s)", $structure['field'], $structure['length'] ? ", {$structure['length']}" : ''));
|
||||
} elseif ($type->exactly('char')) {
|
||||
$begin = $begin->append(sprintf("char('%s', %s)", $structure['field'], $structure['length']));
|
||||
} elseif ($type->exactly('id')) {
|
||||
$begin = $begin->append(Str::of($structure['field'])->exactly('id') ? 'id()' : sprintf("id('%s')", $structure['field']));
|
||||
} else {
|
||||
$begin = $begin->append(sprintf("%s('%s')", $structure['type'], $structure['field']));
|
||||
}
|
||||
|
||||
$content = $content->append($begin)
|
||||
->when($structure['nullable'], function ($str) {
|
||||
return $str->append('->nullable()');
|
||||
})
|
||||
->when(isset($structure['default']), function ($str, $default) {
|
||||
if (is_numeric($default)) {
|
||||
return $str->append("->default({$default})");
|
||||
}
|
||||
|
||||
if ($default) {
|
||||
return $str->append("->default('{$default}')");
|
||||
}
|
||||
|
||||
return $str;
|
||||
})
|
||||
->when($structure['unique'], function ($str) {
|
||||
return $str->append("->unique()");
|
||||
})
|
||||
->when($structure['comment'], function ($str, $comment) {
|
||||
return $str->append("->comment('{$comment}')");
|
||||
})
|
||||
->append(';')
|
||||
->newLine();
|
||||
}
|
||||
|
||||
if ($this->creatorId) {
|
||||
$content = $content->append(Str::of('$table->')->append('creatorId();'))->newLine();
|
||||
}
|
||||
|
||||
if ($this->createdAt) {
|
||||
$content = $content->append(Str::of('$table->')->append('createdAt();'))->newLine();
|
||||
}
|
||||
|
||||
if ($this->updatedAt) {
|
||||
$content = $content->append(Str::of('$table->')->append('updatedAt();'))->newLine();
|
||||
}
|
||||
|
||||
if ($this->deletedAt) {
|
||||
$content = $content->append(Str::of('$table->')->append('deletedAt();'))->newLine();
|
||||
}
|
||||
|
||||
return $content->newLine()
|
||||
->append("\$table->engine='{$this->engine}'")
|
||||
->append(';')
|
||||
->newLine()
|
||||
->append("\$table->comment('{$this->comment}')")
|
||||
->append(';')
|
||||
->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $createdAt
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreatedAt(bool $createdAt): static
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $updatedAt
|
||||
* @return $this
|
||||
*/
|
||||
public function setUpdatedAt(bool $updatedAt): static
|
||||
{
|
||||
$this->updatedAt = $updatedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $deletedAt
|
||||
* @return $this
|
||||
*/
|
||||
public function setDeletedAt(bool $deletedAt): static
|
||||
{
|
||||
$this->deletedAt = $deletedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $creatorId
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreatorId(bool $creatorId): static
|
||||
{
|
||||
$this->creatorId = $creatorId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $structures
|
||||
* @return $this
|
||||
*/
|
||||
public function setStructures(array $structures): static
|
||||
{
|
||||
$this->structures = $structures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* get stub
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getStub(): string
|
||||
{
|
||||
return dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'migration.stub';
|
||||
}
|
||||
}
|
214
modules/Develop/Support/Generate/Generator.php
Normal file
214
modules/Develop/Support/Generate/Generator.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | CatchAdmin [Just Like ~ ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Modules\Develop\Support\Generate;
|
||||
|
||||
use Catch\Exceptions\FailedException;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Modules\Develop\Support\Generate\Create\Controller;
|
||||
use Modules\Develop\Support\Generate\Create\FrontForm;
|
||||
use Modules\Develop\Support\Generate\Create\FrontTable;
|
||||
use Modules\Develop\Support\Generate\Create\Model;
|
||||
use Modules\Develop\Support\Generate\Create\Request;
|
||||
use Modules\Develop\Support\Generate\Create\Route;
|
||||
|
||||
/**
|
||||
* @class Generator
|
||||
*/
|
||||
class Generator
|
||||
{
|
||||
/**
|
||||
* @var array{module:string,controller:string,model:string,paginate: bool,schema: string}
|
||||
*/
|
||||
protected array $gen;
|
||||
|
||||
/**
|
||||
* @var array{name: string,charset: string, collection: string,
|
||||
* comment:string,created_at: bool, updated_at: bool, deleted_at: bool,
|
||||
* creator_id: bool, updated_at: bool, engine: string}
|
||||
*/
|
||||
protected array $schema;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $structures;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $files = [];
|
||||
|
||||
|
||||
/**
|
||||
* this model name from controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $modelName;
|
||||
|
||||
|
||||
/**
|
||||
* this request name for controller
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
protected ?string $requestName;
|
||||
|
||||
/**
|
||||
* generate
|
||||
*
|
||||
* @throws Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function generate(): bool
|
||||
{
|
||||
try {
|
||||
$this->files[] = $this->createModel();
|
||||
|
||||
$this->files[] = $this->createRequest();
|
||||
|
||||
$this->files[] = $this->createController();
|
||||
|
||||
$this->files[] = $this->createFrontTable();
|
||||
|
||||
$this->files[] = $this->createFrontForm();
|
||||
|
||||
$this->files[] = $this->createRoute();
|
||||
} catch (Exception $e) {
|
||||
$this->rollback();
|
||||
throw new FailedException($e->getMessage());
|
||||
}
|
||||
|
||||
$this->files = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* create route
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @return bool|string
|
||||
*/
|
||||
public function createRoute(): bool|string
|
||||
{
|
||||
// 保存之前的 route 文件
|
||||
$route = new Route($this->gen['controller']);
|
||||
|
||||
return $route->setModule($this->gen['module'])->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* create font
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @return bool|string|null
|
||||
*/
|
||||
public function createFrontTable(): bool|string|null
|
||||
{
|
||||
$table = new FrontTable($this->gen['controller'], $this->gen['paginate'], (new Route($this->gen['controller']))->setModule($this->gen['module'])->getApiRute());
|
||||
|
||||
return $table->setModule($this->gen['module'])->setStructures($this->structures)->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* create font
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @return bool|string|null
|
||||
*/
|
||||
public function createFrontForm(): bool|string|null
|
||||
{
|
||||
$form = new FrontForm($this->gen['controller']);
|
||||
|
||||
return $form->setModule($this->gen['module'])->setStructures($this->structures)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create model
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function createModel(): bool|string
|
||||
{
|
||||
$model = new Model($this->gen['model'], $this->gen['schema'], $this->gen['module']);
|
||||
|
||||
$this->modelName = $model->getModelName();
|
||||
|
||||
return $model->setModule($this->gen['module'])->setStructures($this->structures)->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* create request
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function createRequest(): bool|string
|
||||
{
|
||||
$request = new Request($this->gen['controller']);
|
||||
|
||||
$file = $request->setStructures($this->structures)->setModule($this->gen['module'])->create();
|
||||
|
||||
$this->requestName = $request->getRequestName();
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* create controller
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
* @return bool|string
|
||||
*/
|
||||
protected function createController(): bool|string
|
||||
{
|
||||
$controller = new Controller($this->gen['controller'], $this->modelName, $this->requestName);
|
||||
|
||||
return $controller->setModule($this->gen['module'])->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* rollback
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function rollback(): void
|
||||
{
|
||||
// delete controller & model & migration file
|
||||
foreach ($this->files as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
// 回填之前的 route 文件
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set params
|
||||
*
|
||||
* @param array $params
|
||||
* @return $this
|
||||
*/
|
||||
public function setParams(array $params): Generator
|
||||
{
|
||||
$this->gen = $params['codeGen'];
|
||||
|
||||
$this->structures = $params['structures'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
86
modules/Develop/Support/Generate/Module.php
Normal file
86
modules/Develop/Support/Generate/Module.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Develop\Support\Generate;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Module
|
||||
{
|
||||
public function __construct(
|
||||
public string $module,
|
||||
protected bool $controller,
|
||||
protected bool $models,
|
||||
protected bool $requests,
|
||||
protected bool $database
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* create
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function create(): void
|
||||
{
|
||||
if ($this->controller) {
|
||||
CatchAdmin::getModuleControllerPath($this->module);
|
||||
}
|
||||
|
||||
if ($this->models) {
|
||||
CatchAdmin::getModuleModelPath($this->module);
|
||||
}
|
||||
|
||||
if ($this->requests) {
|
||||
CatchAdmin::getModuleRequestPath($this->module);
|
||||
}
|
||||
|
||||
if ($this->database) {
|
||||
CatchAdmin::getModuleMigrationPath($this->module);
|
||||
CatchAdmin::getModuleSeederPath($this->module);
|
||||
}
|
||||
|
||||
$this->createProvider();
|
||||
|
||||
$this->createRoute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* delete
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create provider
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createProvider(): void
|
||||
{
|
||||
CatchAdmin::getModuleProviderPath($this->module);
|
||||
|
||||
File::put(
|
||||
CatchAdmin::getModuleProviderPath($this->module).sprintf('%sServiceProvider.php', ucfirst($this->module)),
|
||||
Str::of(
|
||||
File::get(__DIR__.DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'provider.stub')
|
||||
)->replace(['{Module}', '{module}'], [ucfirst($this->module), $this->module])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create route
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createRoute(): void
|
||||
{
|
||||
File::copy(__DIR__.DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'route.stub', CatchAdmin::getModuleRoutePath($this->module));
|
||||
}
|
||||
}
|
43
modules/Develop/Support/Generate/stubs/controller.stub
Normal file
43
modules/Develop/Support/Generate/stubs/controller.stub
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {namespace}
|
||||
|
||||
use Catch\Base\CatchController as Controller;
|
||||
{uses}
|
||||
|
||||
class {controller} extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly {model} $model
|
||||
){}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function index(Request $request): mixed
|
||||
{
|
||||
return $this->model->getList();
|
||||
}
|
||||
|
||||
public function store({request} $request)
|
||||
{
|
||||
return $this->model->storeBy($request->all());
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
return $this->model->firstBy($id);
|
||||
}
|
||||
|
||||
public function update($id, {request} $request)
|
||||
{
|
||||
return $this->model->updateBy($id, $request->all());
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
return $this->model->deleteBy($id);
|
||||
}
|
||||
}
|
30
modules/Develop/Support/Generate/stubs/migration.stub
Normal file
30
modules/Develop/Support/Generate/stubs/migration.stub
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::{method}('{table}', function (Blueprint $table) {
|
||||
{content}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('{table}');
|
||||
}
|
||||
};
|
36
modules/Develop/Support/Generate/stubs/model.stub
Normal file
36
modules/Develop/Support/Generate/stubs/model.stub
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {namespace}
|
||||
|
||||
{uses}
|
||||
|
||||
{property}
|
||||
class {model} extends Model
|
||||
{
|
||||
{traits}
|
||||
|
||||
protected $table = '{table}';
|
||||
|
||||
protected $fillable = [{fillable} ];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $fieldsInList = [{fieldsInList}];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $form = [{form}];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public array $searchable = [
|
||||
{searchable}
|
||||
];
|
||||
|
||||
{isPaginate}
|
||||
}
|
20
modules/Develop/Support/Generate/stubs/provider.stub
Normal file
20
modules/Develop/Support/Generate/stubs/provider.stub
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\{Module}\Providers;
|
||||
|
||||
use Catch\CatchAdmin;
|
||||
use Catch\Providers\CatchModuleServiceProvider;
|
||||
|
||||
class {Module}ServiceProvider extends CatchModuleServiceProvider
|
||||
{
|
||||
/**
|
||||
* route path
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function routePath(): string|array
|
||||
{
|
||||
// TODO: Implement path() method.
|
||||
return CatchAdmin::getModuleRoutePath('{module}');
|
||||
}
|
||||
}
|
28
modules/Develop/Support/Generate/stubs/request.stub
Normal file
28
modules/Develop/Support/Generate/stubs/request.stub
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace {namespace}
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest as Request;
|
||||
|
||||
class {request} extends Request
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
{rule}
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function message(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
7
modules/Develop/Support/Generate/stubs/route.stub
Normal file
7
modules/Develop/Support/Generate/stubs/route.stub
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('{module}')->group(function(){
|
||||
//next
|
||||
});
|
38
modules/Develop/Support/Generate/stubs/vue/form.stub
Normal file
38
modules/Develop/Support/Generate/stubs/vue/form.stub
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<el-form :model="formData" label-width="120px" ref="form" v-loading="loading" class="pr-4">
|
||||
{formItems}
|
||||
<div class="flex justify-end">
|
||||
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useCreate } from '/admin/composables/curd/useCreate'
|
||||
import { useShow } from '/admin/composables/curd/useShow'
|
||||
|
||||
import { onMounted, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
primary: String | Number,
|
||||
api: String,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const { formData, form, loading, submitForm, isClose } = useCreate(props.api, props.primary)
|
||||
|
||||
watch(isClose, function (value) {
|
||||
if (value) {
|
||||
emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.primary) {
|
||||
useShow(props.api, props.primary).then(r => {
|
||||
formData.value = r.data
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
@@ -0,0 +1,3 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-cascader v-model="{model-value}" :options="options" />
|
||||
</el-form-item>
|
@@ -0,0 +1,9 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-date-picker
|
||||
v-model="{model-value}"
|
||||
type="date"
|
||||
name="{prop}"
|
||||
placeholder="Pick a day"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
@@ -0,0 +1,9 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-date-picker
|
||||
v-model="{model-value}"
|
||||
type="datetime"
|
||||
name="{prop}"
|
||||
placeholder="Pick a day"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
@@ -0,0 +1,3 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-input-number v-model="{model-value}" name="{prop}" :min="1" />
|
||||
</el-form-item>
|
@@ -0,0 +1,3 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-input v-model="{model-value}" name="{prop}" clearable />
|
||||
</el-form-item>
|
@@ -0,0 +1,5 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-radio-group v-model="{model-value}">
|
||||
<el-radio v-for="item in options" :key="item.value" :label="item.value" name="{prop}">{{ item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
@@ -0,0 +1,3 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-rate v-model="{model-value}" name="{prop}" clearable />
|
||||
</el-form-item>
|
@@ -0,0 +1,10 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-select v-model="{model-value}" placeholder="请选择" clearable ${multiple}>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
@@ -0,0 +1,3 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-switch v-model="{model-value}" name="{prop}" />
|
||||
</el-form-item>
|
@@ -0,0 +1,9 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-tree-select
|
||||
v-model="{model-value}"
|
||||
:data="data"
|
||||
check-strictly
|
||||
multiple
|
||||
show-checkbox
|
||||
/>
|
||||
</el-form-item>
|
@@ -0,0 +1,8 @@
|
||||
<el-form-item label="{label}" prop="{prop}">
|
||||
<el-tree
|
||||
:data="data"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
12
modules/Develop/Support/Generate/stubs/vue/paginate.stub
Normal file
12
modules/Develop/Support/Generate/stubs/vue/paginate.stub
Normal file
@@ -0,0 +1,12 @@
|
||||
<div class="pt-2 pb-2 flex justify-end">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total,sizes,prev,pager,next"
|
||||
:current-page="query.page"
|
||||
:page-size="query.limit"
|
||||
@current-change="changePage"
|
||||
@size-change="changeLimit"
|
||||
:total="total"
|
||||
:page-sizes="[1, 10, 20, 30, 50]"
|
||||
/>
|
||||
</div>
|
78
modules/Develop/Support/Generate/stubs/vue/table.stub
Normal file
78
modules/Develop/Support/Generate/stubs/vue/table.stub
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="w-full min-h-0 bg-white dark:bg-regal-dark pl-5 pt-5 pr-5 rounded-lg">
|
||||
<el-form :inline="true">
|
||||
{search}
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="search()">
|
||||
<Icon name="magnifying-glass" class="w-4 mr-1 -ml-1" />
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="reset()">
|
||||
<Icon name="arrow-path" class="w-4 mr-1 -ml-1" />
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="pl-2 pr-2 bg-white dark:bg-regal-dark rounded-lg mt-4">
|
||||
<div class="pt-5 pl-2">
|
||||
<Add @click="show(null)" />
|
||||
</div>
|
||||
<el-table :data="tableData" class="mt-3" v-loading="loading">
|
||||
{table}
|
||||
<el-table-column label="操作" width="200">
|
||||
<template #default="scope">
|
||||
<Update @click="show(scope.row.id)" />
|
||||
<Destroy @click="destroy(api, scope.row.id)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
{paginate}
|
||||
</div>
|
||||
<Dialog v-model="visible" :title="title" destroy-on-close>
|
||||
<Create @close="close" :primary="id" :api="api" />
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
import { useEnabled } from '/admin/composables/curd/useEnabled'
|
||||
import { t } from '/admin/support/helper'
|
||||
|
||||
const visible = ref<boolean>(false)
|
||||
const id = ref(null)
|
||||
const api = {api}
|
||||
const title = ref<string>('');
|
||||
|
||||
{useList}
|
||||
|
||||
const { destroy, isDeleted } = useDestroy()
|
||||
const { enabled } = useEnabled()
|
||||
|
||||
onMounted(() => search())
|
||||
|
||||
const tableData = computed(() => data.value?.data)
|
||||
const total = computed(() => data.value?.total)
|
||||
|
||||
const close = () => {
|
||||
visible.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
const show = primary => {
|
||||
title.value = primary ? t('system.edit') : t('system.add')
|
||||
id.value = primary
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
watch(isDeleted, function (){
|
||||
// change origin status
|
||||
isDeleted.value = false
|
||||
reset();
|
||||
})
|
||||
</script>
|
28
modules/Develop/database/migrations/Schemas.php
Normal file
28
modules/Develop/database/migrations/Schemas.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
return new class () extends Migration {
|
||||
public function up()
|
||||
{
|
||||
Schema::create('schemas', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
|
||||
$table->string('module')->nullable(false)->comment('模块名称');
|
||||
|
||||
$table->string('name')->nullable(false)->comment('schema 名称');
|
||||
|
||||
$table->string('columns')->nullable(false)->comment('字段');
|
||||
|
||||
$table->boolean('is_soft_delete')->default(1)->comment('1 是 2 否');
|
||||
|
||||
$table->createdAt();
|
||||
|
||||
$table->updatedAt();
|
||||
|
||||
$table->deletedAt();
|
||||
});
|
||||
}
|
||||
};
|
14
modules/Develop/route.php
Normal file
14
modules/Develop/route.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Develop\Http\Controllers\ModuleController;
|
||||
use Modules\Develop\Http\Controllers\GenerateController;
|
||||
use Modules\Develop\Http\Controllers\SchemaController;
|
||||
|
||||
Route::apiResource('module', ModuleController::class);
|
||||
|
||||
Route::put('module/enable/{name}', [ModuleController::class, 'enable']);
|
||||
|
||||
Route::post('generate', [GenerateController::class, 'index']);
|
||||
|
||||
Route::apiResource('schema', SchemaController::class)->only(['index', 'show', 'store', 'destroy']);
|
109
modules/Develop/views/generate/components/codeGen.vue
Normal file
109
modules/Develop/views/generate/components/codeGen.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<el-card class="box-card" shadow="never">
|
||||
<template #header>
|
||||
<div>
|
||||
<span>{{ $t('generate.code.title') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="w-full sm:w-[40%] mx-auto">
|
||||
<el-form :model="gen" ref="form" label-width="100px">
|
||||
<el-form-item
|
||||
:label="$t('generate.code.module.name')"
|
||||
prop="module"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.code.module.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<Select v-model="gen.module" clearable :placeholder="$t('generate.code.module.placeholder')" api="modules" class="w-full" filterable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('generate.code.controller.name')"
|
||||
prop="controller"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.code.controller.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input v-model="gen.controller" clearable :placeholder="$t('generate.code.controller.placeholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('generate.code.model.name')" prop="model">
|
||||
<el-input v-model="gen.model" clearable :placeholder="$t('generate.code.model.placeholder')" />
|
||||
</el-form-item>
|
||||
|
||||
<div class="flex">
|
||||
<el-form-item :label="$t('generate.code.paginate')" prop="paginate">
|
||||
<el-switch v-model="gen.paginate" inline-prompt :active-text="$t('system.yes')" :inactive-text="$t('system.no')" />
|
||||
</el-form-item>
|
||||
<el-form-item label-width="15px">
|
||||
<div class="text-sm text-gray-300">控制列表是否使用分页功能</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
<Structure />
|
||||
<div class="w-full flex justify-center pt-5">
|
||||
<router-link to="/develop/schemas">
|
||||
<el-button>{{ $t('system.back') }}</el-button>
|
||||
</router-link>
|
||||
<el-button type="primary" @click="submitGenerate(form)" class="ml-5">{{ $t('system.finish') }}</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { watch, onMounted, reactive, ref } from 'vue'
|
||||
import { useGenerateStore } from './store'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import http from '/admin/support/http'
|
||||
import Structure from './structure.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
const generateStore = useGenerateStore()
|
||||
const gen = reactive(generateStore.getCodeGen)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const schemaId = router.currentRoute.value.params.schema
|
||||
|
||||
onMounted(() => {
|
||||
if (!generateStore.getSchemaId) {
|
||||
generateStore.setSchemaId(schemaId)
|
||||
getSchema()
|
||||
} else {
|
||||
if (schemaId !== generateStore.getSchemaId) {
|
||||
generateStore.setSchemaId(schemaId)
|
||||
generateStore.resetStructures()
|
||||
getSchema()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const getSchema = () => {
|
||||
http.get('schema/' + schemaId).then(r => {
|
||||
gen.module = r.data.data.module
|
||||
gen.schema = r.data.data.name
|
||||
|
||||
gen.model = r.data.data.name.replace(/\_(\w)/g, (value, letter) => {
|
||||
return letter.toUpperCase()
|
||||
})
|
||||
|
||||
generateStore.initStructures(r.data.data.columns)
|
||||
})
|
||||
}
|
||||
const form = ref<FormInstance>()
|
||||
const submitGenerate = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.validate(valid => {
|
||||
if (valid) {
|
||||
http.post('generate', generateStore.$state).then(r => {})
|
||||
//emits('next')
|
||||
//generateStore.$reset()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
112
modules/Develop/views/generate/components/store.ts
Normal file
112
modules/Develop/views/generate/components/store.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
/**
|
||||
* 表结构信息
|
||||
*/
|
||||
export interface Structure {
|
||||
field: string
|
||||
label: string
|
||||
form_component: string
|
||||
list: boolean
|
||||
form: boolean
|
||||
search: boolean
|
||||
search_op: string
|
||||
validates: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* CodeGen
|
||||
*/
|
||||
export interface CodeGen {
|
||||
module: string
|
||||
controller: string
|
||||
model: string
|
||||
paginate: true
|
||||
schema: string
|
||||
}
|
||||
|
||||
/**
|
||||
* generate
|
||||
*/
|
||||
interface generate {
|
||||
schemaId: number
|
||||
structures: Structure[]
|
||||
codeGen: CodeGen
|
||||
}
|
||||
|
||||
/**
|
||||
* useGenerateStore
|
||||
*/
|
||||
export const useGenerateStore = defineStore('generateStore', {
|
||||
state(): generate {
|
||||
return {
|
||||
// schema id
|
||||
schemaId: 0,
|
||||
// structures
|
||||
structures: [] as Structure[],
|
||||
// codeGen
|
||||
codeGen: Object.assign({
|
||||
module: '',
|
||||
controller: '',
|
||||
model: '',
|
||||
paginate: true,
|
||||
schema: '',
|
||||
}),
|
||||
}
|
||||
},
|
||||
|
||||
// store getters
|
||||
getters: {
|
||||
getSchemaId(): any {
|
||||
return this.schemaId
|
||||
},
|
||||
|
||||
getStructures(): Structure[] {
|
||||
return this.structures
|
||||
},
|
||||
|
||||
getCodeGen(): CodeGen {
|
||||
return this.codeGen
|
||||
},
|
||||
},
|
||||
|
||||
// store actions
|
||||
actions: {
|
||||
// set schema
|
||||
setSchemaId(schemaId: any): void {
|
||||
this.schemaId = schemaId
|
||||
},
|
||||
// reset
|
||||
resetStructures(): void {
|
||||
this.structures = []
|
||||
},
|
||||
// filter structures
|
||||
filterStructures(field: string) {
|
||||
this.structures = this.structures.filter((s: Structure) => {
|
||||
return !(s.field === field)
|
||||
})
|
||||
},
|
||||
|
||||
// init structure
|
||||
initStructures(fields: Array<any>): void {
|
||||
const unSupportFields = ['deleted_at', 'creator_id']
|
||||
|
||||
fields.forEach(field => {
|
||||
if (!unSupportFields.includes(field.name)) {
|
||||
this.structures.push(
|
||||
Object.assign({
|
||||
field: field.name,
|
||||
label: '',
|
||||
form_component: 'input',
|
||||
list: true,
|
||||
form: true,
|
||||
search: false,
|
||||
search_op: '',
|
||||
validates: [],
|
||||
}),
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
99
modules/Develop/views/generate/components/structure.vue
Normal file
99
modules/Develop/views/generate/components/structure.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table :data="structures">
|
||||
<el-table-column prop="field" :label="$t('generate.schema.structure.field_name.name')" width="100px" />
|
||||
<el-table-column prop="label" :label="$t('generate.schema.structure.form_label')" width="150px">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.label" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="label" :label="$t('generate.schema.structure.form_component')" width="110px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.form_component" class="w-full" filterable>
|
||||
<el-option v-for="component in formComponents" :key="component" :label="component" :value="component" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="list" :label="$t('generate.schema.structure.list')">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.list" inline-prompt :active-text="$t('system.yes')" :inactive-text="$t('system.no')" width="45px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="form" :label="$t('generate.schema.structure.form')">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.form" inline-prompt :active-text="$t('system.yes')" :inactive-text="$t('system.no')" width="45px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="search" :label="$t('generate.schema.structure.search')">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.search" inline-prompt :active-text="$t('system.yes')" :inactive-text="$t('system.no')" width="45px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="search_op" :label="$t('generate.schema.structure.search_op.name')" width="150px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.search_op" :placeholder="$t('generate.schema.structure.search_op.placeholder')" class="w-full">
|
||||
<el-option v-for="op in operates" :key="op" :label="op" :value="op" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="validates" :label="$t('generate.schema.structure.rules.name')" width="250px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.validates" :placeholder="$t('generate.schema.structure.rules.placeholder')" multiple filterable allow-create clearable class="w-full">
|
||||
<el-option v-for="validate in validates" :key="validate" :label="validate" :value="validate" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!--<el-table-column prop="comment" label="注释" />-->
|
||||
<el-table-column prop="id" :label="$t('generate.schema.structure.operate')" width="120px">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" :icon="Delete" @click="deleteField(scope.row.field)" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { useGenerateStore } from './store'
|
||||
import { Delete } from '@element-plus/icons-vue'
|
||||
|
||||
const generateStore = useGenerateStore()
|
||||
|
||||
const structures = computed(() => {
|
||||
return generateStore.getStructures
|
||||
})
|
||||
|
||||
const deleteField = (field: string) => {
|
||||
generateStore.filterStructures(field)
|
||||
}
|
||||
|
||||
const operates: string[] = ['=', '!=', '>', '>=', '<', '<=', 'like', 'RLike', 'LLike', 'in']
|
||||
|
||||
const validates: string[] = [
|
||||
'required',
|
||||
'integer',
|
||||
'numeric',
|
||||
'string',
|
||||
'timezone',
|
||||
'url',
|
||||
'uuid',
|
||||
'date',
|
||||
'alpha',
|
||||
'alpha_dash',
|
||||
'alpha_num',
|
||||
'boolean',
|
||||
'email',
|
||||
'image',
|
||||
'file',
|
||||
'ip',
|
||||
'ipv4',
|
||||
'ipv6',
|
||||
'mac_address',
|
||||
'json',
|
||||
'nullable',
|
||||
'present',
|
||||
'prohibited',
|
||||
]
|
||||
|
||||
const formComponents: string[] = ['cascader', 'date', 'datetime', 'input', 'input-number', 'radio', 'rate', 'select', 'tree', 'tree-select']
|
||||
</script>
|
10
modules/Develop/views/generate/index.vue
Normal file
10
modules/Develop/views/generate/index.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div class="bg-white">
|
||||
<CodeGen />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
import CodeGen from './components/codeGen.vue'
|
||||
</script>
|
89
modules/Develop/views/module/create.vue
Normal file
89
modules/Develop/views/module/create.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<el-form :model="formData" label-width="120px" ref="form" v-loading="loading" class="pr-4">
|
||||
<el-form-item
|
||||
:label="$t('module.form.name.title')"
|
||||
prop="name"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('module.form.name.required'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input v-model="formData.name" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('module.form.path.title')"
|
||||
prop="path"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('module.form.path.required'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input v-model="formData.path" :disabled="!!primary" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('module.form.keywords.title')" prop="keywords">
|
||||
<el-input v-model="formData.keywords" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('module.form.desc.title')" prop="desc">
|
||||
<el-input v-model="formData.description" type="textarea" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('module.form.dirs.title')" prop="dirs" v-if="!primary">
|
||||
<el-checkbox v-model="formData['dirs']['controllers']" label="Controllers" size="large" />
|
||||
<el-checkbox v-model="formData['dirs']['models']" label="Models" size="large" />
|
||||
<el-checkbox v-model="formData['dirs']['database']" label="Database" size="large" />
|
||||
<el-checkbox v-model="formData['dirs']['requests']" label="Requests" size="large" />
|
||||
</el-form-item>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useCreate } from '/admin/composables/curd/useCreate'
|
||||
import { useShow } from '/admin/composables/curd/useShow'
|
||||
|
||||
import { onMounted, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
primary: String | Number,
|
||||
api: String,
|
||||
})
|
||||
|
||||
const { formData, form, loading, submitForm, isClose } = useCreate(
|
||||
props.api,
|
||||
props.primary,
|
||||
Object.assign({
|
||||
name: '',
|
||||
path: '',
|
||||
keywords: '',
|
||||
description: '',
|
||||
dirs: {
|
||||
controllers: true,
|
||||
models: true,
|
||||
database: true,
|
||||
requests: false,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
watch(isClose, function (value) {
|
||||
if (value) {
|
||||
emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.primary) {
|
||||
useShow(props.api, props.primary).then(r => {
|
||||
formData.value = r.data
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
103
modules/Develop/views/module/index.vue
Normal file
103
modules/Develop/views/module/index.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="w-full min-h-0 bg-white dark:bg-regal-dark pl-5 pt-5 pr-5 rounded-lg">
|
||||
<el-form :inline="true">
|
||||
<el-form-item label="模块名称">
|
||||
<el-input v-model="query.name" name="name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="search()">
|
||||
<Icon name="magnifying-glass" class="w-4 mr-1 -ml-1" />
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="reset()">
|
||||
<Icon name="arrow-path" class="w-4 mr-1 -ml-1" />
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="pl-2 pr-2 bg-white dark:bg-regal-dark rounded-lg mt-4">
|
||||
<div class="pt-5 pl-2">
|
||||
<Add @click="show(null)" />
|
||||
</div>
|
||||
<el-table :data="tableData" class="mt-3" v-loading="loading">
|
||||
<el-table-column prop="name" label="模块名称" width="180" />
|
||||
<el-table-column prop="path" label="模块目录" width="180" />
|
||||
<el-table-column prop="version" label="模块版本">
|
||||
<template #default="scope">
|
||||
<el-tag type="warning">{{ scope.row.version }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="enable" label="模块状态">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enable" @change="enabled(api, scope.row.name)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300">
|
||||
<template #default="scope">
|
||||
<Update @click="show(scope.row.name)" />
|
||||
<Destroy @click="destroy(api, scope.row.name)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pt-2 pb-2 flex justify-end">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total,sizes,prev, pager,next"
|
||||
:current-page="query.page"
|
||||
:page-size="query.limit"
|
||||
@current-change="changePage"
|
||||
@size-change="changeLimit"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog v-model="visible" :title="title" destroy-on-close>
|
||||
<Create @close="close" :primary="id" :api="api" />
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
import { useEnabled } from '/admin/composables/curd/useEnabled'
|
||||
import { t } from '/admin/support/helper'
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
const visible = ref<boolean>(false)
|
||||
const id = ref(null)
|
||||
const api = 'module'
|
||||
const title = ref<string>('')
|
||||
|
||||
const { data, query, search, reset, changePage, changeLimit, loading } = useGetList(api)
|
||||
const { destroy, isDeleted } = useDestroy('确认删除吗? ⚠️将会删除模块下所有文件')
|
||||
const { enabled } = useEnabled()
|
||||
|
||||
onMounted(() => search())
|
||||
|
||||
const tableData = computed(() => data.value?.data)
|
||||
const total = computed(() => data.value?.total)
|
||||
|
||||
const close = () => {
|
||||
visible.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
const show = primary => {
|
||||
title.value = primary ? t('system.edit') : t('system.add')
|
||||
id.value = primary
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
watch(isDeleted, function () {
|
||||
isDeleted.value = false
|
||||
reset()
|
||||
})
|
||||
</script>
|
32
modules/Develop/views/router.ts
Normal file
32
modules/Develop/views/router.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
// @ts-ignore
|
||||
const router: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/develop',
|
||||
component: () => import('/admin/layout/index.vue'),
|
||||
meta: { title: '开发工具', icon: 'wrench-screwdriver', hidden: false },
|
||||
children: [
|
||||
{
|
||||
path: 'modules',
|
||||
name: 'modules',
|
||||
meta: { title: '模块管理', icon: 'home', hidden: false },
|
||||
component: () => import('./module/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'schemas',
|
||||
name: 'schemas',
|
||||
meta: { title: 'Schemas', icon: 'home', hidden: false },
|
||||
component: () => import('./schema/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'generate/:schema',
|
||||
name: 'generate',
|
||||
meta: { title: '代码生成', hidden: true, is_inner: true },
|
||||
component: () => import('./generate/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export default router
|
35
modules/Develop/views/schema/create.vue
Normal file
35
modules/Develop/views/schema/create.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<Schema v-if="active === 1" @next="next" @prev="prev" />
|
||||
<Structure v-if="active === 2" @next="next" @prev="prev" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import Schema from './steps/schema.vue'
|
||||
import Structure from './steps/structure.vue'
|
||||
import { useSchemaStore } from './store'
|
||||
|
||||
const schemaStore = useSchemaStore()
|
||||
|
||||
const active = ref(1)
|
||||
const next = () => {
|
||||
if (active.value++ >= 2) {
|
||||
active.value = 2
|
||||
}
|
||||
}
|
||||
|
||||
const prev = () => {
|
||||
if (active.value-- === 1) {
|
||||
active.value = 1
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
watch(() => schemaStore.getFinished, function (value){
|
||||
if (value) {
|
||||
emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
120
modules/Develop/views/schema/index.vue
Normal file
120
modules/Develop/views/schema/index.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="w-full min-h-0 bg-white dark:bg-regal-dark pl-5 pt-5 pr-5 rounded-lg">
|
||||
<el-form :inline="true">
|
||||
<el-form-item label="模块名称">
|
||||
<el-input v-model="query.module" name="module" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="Schema 名称">
|
||||
<el-input v-model="query.name" name="name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="search()">
|
||||
<Icon name="magnifying-glass" class="w-4 mr-1 -ml-1" />
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="reset()">
|
||||
<Icon name="arrow-path" class="w-4 mr-1 -ml-1" />
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="pl-2 pr-2 bg-white dark:bg-regal-dark rounded-lg mt-4">
|
||||
<div class="pt-5 pl-2">
|
||||
<Add @click="add(null)" />
|
||||
</div>
|
||||
<el-table :data="tableData" class="mt-3" v-loading="loading">
|
||||
<el-table-column prop="module" label="所属模块" />
|
||||
<el-table-column prop="name" label="schema 名称" />
|
||||
<el-table-column prop="columns" label="字段">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="success" @click="show(scope.row.id)"><Icon name="eye" class="w-3 mr-1" /> 查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="is_soft_delete" label="?软删">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.is_soft_delete">是</el-tag>
|
||||
<el-tag type="danger" v-else>否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="created_at" label="创建时间" />
|
||||
<el-table-column label="操作" width="250">
|
||||
<template #default="scope">
|
||||
<router-link :to="'/develop/generate/' + scope.row.id">
|
||||
<el-button type="warning" size="small"><Icon name="wrench-screwdriver" class="w-3 mr-1" /> 生成代码</el-button>
|
||||
</router-link>
|
||||
<Destroy @click="destroy(api, scope.row.id)" class="ml-2" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pt-2 pb-2 flex justify-end">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total,sizes,prev, pager,next"
|
||||
:current-page="query.page"
|
||||
:page-size="query.limit"
|
||||
@current-change="changePage"
|
||||
@size-change="changeLimit"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- schema 创建 -->
|
||||
<Dialog v-model="visible" :title="$t('generate.schema.title')" width="650px" destroy-on-close>
|
||||
<Create @close="close" :primary="id" :api="api" />
|
||||
</Dialog>
|
||||
|
||||
<!-- schema 表结构 -->
|
||||
<Dialog v-model="showVisible" title="Schema 结构" width="650px" destroy-on-close>
|
||||
<Show :id="id" :api="api" />
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import Create from './create.vue'
|
||||
import Show from './show.vue'
|
||||
|
||||
import { useGetList } from '/admin/composables/curd/useGetList'
|
||||
import { useDestroy } from '/admin/composables/curd/useDestroy'
|
||||
|
||||
const visible = ref<boolean>(false)
|
||||
const showVisible = ref<boolean>(false)
|
||||
|
||||
const id = ref<number>()
|
||||
const api = 'schema'
|
||||
const title = ref<string>('')
|
||||
|
||||
const { data, query, search, reset, changePage, changeLimit, loading } = useGetList(api)
|
||||
const { destroy, isDeleted } = useDestroy('确认删除吗? 将会删除数据库的 Schema,请提前做好备份,一旦删除,将无法恢复!')
|
||||
|
||||
onMounted(() => search())
|
||||
|
||||
const tableData = computed(() => data.value?.data)
|
||||
const total = computed(() => data.value?.total)
|
||||
|
||||
const close = () => {
|
||||
visible.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
const add = () => {
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const show = primaryId => {
|
||||
showVisible.value = true
|
||||
|
||||
id.value = primaryId
|
||||
}
|
||||
|
||||
watch(isDeleted, function () {
|
||||
isDeleted.value = false
|
||||
reset()
|
||||
})
|
||||
</script>
|
38
modules/Develop/views/schema/show.vue
Normal file
38
modules/Develop/views/schema/show.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<el-table :data="data" class="mt-3" v-loading="loading">
|
||||
<el-table-column prop="name" label="字段名称" />
|
||||
<el-table-column prop="type" label="类型" />
|
||||
<el-table-column prop="nullable" label="nullable">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.nullable">是</el-tag>
|
||||
<el-tag type="danger" v-else>否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="default" label="默认值">
|
||||
<template #default="scope"> </template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="comment" label="注释" />
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useShow } from '/admin/composables/curd/useShow'
|
||||
import { onMounted } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const data = ref<Array<object>>()
|
||||
|
||||
onMounted(() => {
|
||||
useShow('schema', props.id).then(r => {
|
||||
data.value = r.data.columns
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
107
modules/Develop/views/schema/steps/schema.vue
Normal file
107
modules/Develop/views/schema/steps/schema.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div class="w-full sm:w-[90%] mx-auto">
|
||||
<el-form :model="schema" ref="form" label-width="80px">
|
||||
<el-form-item
|
||||
:label="$t('generate.code.module.name')"
|
||||
prop="module"
|
||||
:rules="[
|
||||
{
|
||||
// required: true,
|
||||
message: $t('generate.code.module.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<Select v-model="schema.module" clearable :placeholder="$t('generate.code.module.placeholder')" api="modules" class="w-full" filterable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('generate.schema.name')"
|
||||
prop="name"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.schema.name_verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input v-model="schema.name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('generate.schema.engine.name')"
|
||||
prop="engine"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.schema.engine.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-select class="w-full" v-model="schema.engine" :placeholder="$t('generate.schema.engine.placeholder')" clearable>
|
||||
<el-option v-for="engine in engines" :key="engine.value" :label="engine.label" :value="engine.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('generate.schema.default_field.name')">
|
||||
<el-checkbox v-model="schema.created_at" :label="$t('generate.schema.default_field.created_at')" size="large" />
|
||||
<el-checkbox v-model="schema.updated_at" :label="$t('generate.schema.default_field.updated_at')" size="large" />
|
||||
<el-checkbox v-model="schema.creator_id" :label="$t('generate.schema.default_field.creator')" size="large" />
|
||||
<el-checkbox v-model="schema.deleted_at" :label="$t('generate.schema.default_field.delete_at')" size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('generate.schema.comment.name')"
|
||||
prop="comment"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.schema.comment.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input v-model="schema.comment" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="w-full sm:w-96 justify-between mx-auto pl-24 mt-4">
|
||||
<el-button class="mt-5" @click="$emit('prev')">{{ $t('system.prev') }}</el-button>
|
||||
<el-button class="mt-5" type="primary" @click="submitCreateTable(form)">{{ $t('system.next') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, computed, ref, unref } from 'vue'
|
||||
import { useSchemaStore } from '../store'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
const schemaStore = useSchemaStore()
|
||||
schemaStore.start()
|
||||
|
||||
const emits = defineEmits(['prev', 'next'])
|
||||
|
||||
const schema = reactive(schemaStore.getSchema)
|
||||
const form = ref<FormInstance>()
|
||||
const submitCreateTable = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.validate(valid => {
|
||||
if (valid) {
|
||||
emits('next')
|
||||
schemaStore.setSchema(unref(schema))
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
const engines = computed(() => {
|
||||
return [
|
||||
{
|
||||
value: 'InnoDB',
|
||||
label: 'InnoDB',
|
||||
},
|
||||
{
|
||||
value: 'MyISAM',
|
||||
label: 'MyISAM',
|
||||
},
|
||||
{
|
||||
value: 'Memory',
|
||||
label: 'Memory',
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
231
modules/Develop/views/schema/steps/structure.vue
Normal file
231
modules/Develop/views/schema/steps/structure.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table :data="structures" class="draggable">
|
||||
<el-table-column prop="field" :label="$t('generate.schema.structure.field_name.name')" />
|
||||
<el-table-column prop="type" :label="$t('generate.schema.structure.type.name')">
|
||||
<template #default="scope">
|
||||
<el-tag type="success">{{ scope.row.type }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nullable" :label="$t('generate.schema.structure.nullable')" width="90px">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.nullable">{{ $t('system.yes') }}</el-tag>
|
||||
<el-tag v-else type="info">{{ $t('system.no') }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="default" :label="$t('generate.schema.structure.default')" />
|
||||
<!--<el-table-column prop="comment" label="注释" />-->
|
||||
<el-table-column prop="id" :label="$t('generate.schema.structure.operate')" width="120px">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" :icon="Edit" @click="updateField(scope.row.id)" size="small" />
|
||||
<el-button type="danger" :icon="Delete" @click="deleteField(scope.row.id)" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
<el-button type="success" :icon="Plus" @click="addField">{{ $t('system.add') }}</el-button>
|
||||
</div>
|
||||
|
||||
<div class="w-full sm:w-96 justify-between mx-auto pl-24 mt-2">
|
||||
<el-button class="mt-5" @click="emits('prev')">{{ $t('system.prev') }}</el-button>
|
||||
<el-button class="mt-5" type="primary" @click="next">{{ $t('system.confirm') }}</el-button>
|
||||
</div>
|
||||
|
||||
<Dialog v-model="visible" :title="$t('system.add')">
|
||||
<el-form :model="structure" status-icon label-width="120px" ref="form">
|
||||
<el-form-item
|
||||
:label="$t('generate.schema.structure.field_name.name')"
|
||||
prop="field"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.schema.structure.field_name.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-input v-model="structure.field" />
|
||||
</el-form-item>
|
||||
<div class="flex justify-between">
|
||||
<el-form-item
|
||||
class="w-full"
|
||||
:label="$t('generate.schema.structure.type.name')"
|
||||
prop="type"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: $t('generate.schema.structure.type.verify'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<el-select v-model="structure.type" :placeholder="$t('generate.schema.structure.type.placeholder')" filterable class="w-full">
|
||||
<el-option v-for="item in types" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item :label="$t('generate.schema.structure.length')" prop="length">
|
||||
<el-input-number v-model="structure.length" :min="0" />
|
||||
</el-form-item>
|
||||
<div class="flex justify-between">
|
||||
<el-form-item label="nullable" prop="nullable">
|
||||
<el-switch v-model="structure.nullable" inline-prompt :active-text="$t('system.yes')" :inactive-text="$t('system.no')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('generate.schema.structure.default')" prop="default" v-if="!structure.nullable">
|
||||
<el-input v-model="structure.default" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item :label="$t('generate.schema.structure.unique')" prop="unique">
|
||||
<el-switch v-model="structure.unique" inline-prompt :active-text="$t('system.yes')" :inactive-text="$t('system.no')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('generate.schema.structure.comment')" prop="comment">
|
||||
<el-input v-model="structure.comment" text />
|
||||
</el-form-item>
|
||||
<div class="flex justify-end">
|
||||
<el-button type="primary" @click="submitStructure(form)">{{ $t('system.confirm') }}</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, Ref, ref } from 'vue'
|
||||
import { useSchemaStore, Structure } from '../store'
|
||||
import { Delete, Plus, Edit } from '@element-plus/icons-vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import Message from '/admin/support/message'
|
||||
import http from '/admin/support/http'
|
||||
import { Code } from '/admin/enum/app'
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
const schemaStore = useSchemaStore()
|
||||
const emits = defineEmits(['prev', 'next'])
|
||||
const visible = ref(false)
|
||||
|
||||
const structures = computed(() => {
|
||||
return schemaStore.getStructures
|
||||
})
|
||||
|
||||
const structure: Ref<Structure> = ref(schemaStore.initStructure())
|
||||
// structure
|
||||
const addField = async () => {
|
||||
await form.value?.clearValidate()
|
||||
visible.value = true
|
||||
}
|
||||
const updateField = (id: number) => {
|
||||
visible.value = true
|
||||
schemaStore.getStructures.forEach(s => {
|
||||
if (s.id === id) {
|
||||
structure.value = s
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const tbody = document.querySelector('.draggable .el-table__body-wrapper tbody')
|
||||
const structures = schemaStore.getStructures
|
||||
|
||||
Sortable.create(tbody, {
|
||||
draggable: 'tr',
|
||||
onEnd({ newIndex, oldIndex }) {
|
||||
const newStructures = []
|
||||
const s = structures.splice(oldIndex, newIndex - oldIndex)
|
||||
console.log(s, structures, oldIndex, newIndex)
|
||||
s.concat(structures).forEach(item => {
|
||||
newStructures.push(item)
|
||||
})
|
||||
schemaStore.setStructures(newStructures)
|
||||
|
||||
// console.log(structure)
|
||||
// structures[newIndex] = structures[oldIndex]
|
||||
// structures[oldIndex] = temp
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
const form = ref<FormInstance>()
|
||||
const submitStructure = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.validate(valid => {
|
||||
if (valid) {
|
||||
visible.value = !visible.value
|
||||
schemaStore.addStructure(structure.value)
|
||||
structure.value = schemaStore.initStructure()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deleteField = (id: number) => {
|
||||
schemaStore.filterStructures(id)
|
||||
}
|
||||
|
||||
const next = () => {
|
||||
if (schemaStore.getStructures.length < 1) {
|
||||
Message.error('请先填写表结构数据')
|
||||
} else {
|
||||
http.post('schema', schemaStore.$state).then(r => {
|
||||
if (r.data.code == Code.SUCCESS) {
|
||||
Message.success('创建成功')
|
||||
schemaStore.finished()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const types: string[] = [
|
||||
'id',
|
||||
'smallIncrements',
|
||||
'mediumIncrements',
|
||||
'increments',
|
||||
'smallInteger',
|
||||
'integer',
|
||||
'bigIncrements',
|
||||
'bigInteger',
|
||||
'mediumInteger',
|
||||
'unsignedInteger',
|
||||
'unsignedMediumInteger',
|
||||
'unsignedSmallInteger',
|
||||
'unsignedTinyInteger',
|
||||
'string',
|
||||
'text',
|
||||
'binary',
|
||||
'boolean',
|
||||
'char',
|
||||
'dateTimeTz',
|
||||
'dateTime',
|
||||
'date',
|
||||
'decimal',
|
||||
'double',
|
||||
'float',
|
||||
'geometryCollection',
|
||||
'geometry',
|
||||
'ipAddress',
|
||||
'json',
|
||||
'jsonb',
|
||||
'lineString',
|
||||
'longText',
|
||||
'macAddress',
|
||||
'mediumText',
|
||||
'multiLineString',
|
||||
'multiPoint',
|
||||
'multiPolygon',
|
||||
'nullableMorphs',
|
||||
'nullableTimestamps',
|
||||
'nullableUuidMorphs',
|
||||
'point',
|
||||
'polygon',
|
||||
'timeTz',
|
||||
'time',
|
||||
'timestampTz',
|
||||
'timestamp',
|
||||
'timestampsTz',
|
||||
'timestamps',
|
||||
'tinyIncrements',
|
||||
'tinyInteger',
|
||||
'tinyText',
|
||||
'unsignedDecimal',
|
||||
'uuid',
|
||||
'year',
|
||||
]
|
||||
</script>
|
146
modules/Develop/views/schema/store/index.ts
Normal file
146
modules/Develop/views/schema/store/index.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
/**
|
||||
* 表信息
|
||||
*/
|
||||
export interface Schema {
|
||||
module: string
|
||||
name: string
|
||||
comment: string
|
||||
engine: string
|
||||
charset: string
|
||||
collaction: string
|
||||
created_at: boolean
|
||||
creator_id: boolean
|
||||
updated_at: boolean
|
||||
deleted_at: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 表结构信息
|
||||
*/
|
||||
export interface Structure {
|
||||
id: number
|
||||
field: string
|
||||
length: number
|
||||
type: string
|
||||
nullable: boolean
|
||||
unique: boolean
|
||||
default: number | string
|
||||
comment: string
|
||||
}
|
||||
|
||||
/**
|
||||
* generate
|
||||
*/
|
||||
interface CreateSchema {
|
||||
schema: Schema
|
||||
structures: Structure[]
|
||||
is_finished: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* useSchemaStore
|
||||
*/
|
||||
export const useSchemaStore = defineStore('schemaStore', {
|
||||
state(): CreateSchema {
|
||||
return {
|
||||
// schema
|
||||
schema: Object.assign({
|
||||
module: '',
|
||||
name: '',
|
||||
comment: '',
|
||||
engine: 'InnoDB',
|
||||
charset: 'utf8mb4',
|
||||
collection: 'utf8mb4_unicode_ci',
|
||||
created_at: true,
|
||||
creator_id: true,
|
||||
updated_at: true,
|
||||
deleted_at: true,
|
||||
}),
|
||||
// structures
|
||||
structures: [] as Structure[],
|
||||
|
||||
// is finished
|
||||
is_finished: false,
|
||||
}
|
||||
},
|
||||
|
||||
// store getters
|
||||
getters: {
|
||||
getSchema(): Schema {
|
||||
return this.schema
|
||||
},
|
||||
|
||||
getStructures(): Structure[] {
|
||||
return this.structures
|
||||
},
|
||||
|
||||
getFinished(): boolean {
|
||||
return this.is_finished
|
||||
},
|
||||
},
|
||||
|
||||
// store actions
|
||||
actions: {
|
||||
// set schema
|
||||
setSchema(schema: Schema): void {
|
||||
this.schema = schema
|
||||
},
|
||||
|
||||
setStructures(structures: Array<Structure>): void {
|
||||
this.structures = structures
|
||||
},
|
||||
// add structure
|
||||
addStructure(structure: Structure): void {
|
||||
if (structure.id) {
|
||||
this.structures = this.structures.filter((s: Structure) => {
|
||||
if (s.id === structure.id) {
|
||||
s = structure
|
||||
}
|
||||
return s
|
||||
})
|
||||
} else {
|
||||
structure.id = this.structures.length + 1
|
||||
this.structures.push(structure)
|
||||
}
|
||||
},
|
||||
|
||||
// filter structures
|
||||
filterStructures(id: number) {
|
||||
this.structures = this.structures.filter((s: Structure) => {
|
||||
return !(s.id === id)
|
||||
})
|
||||
},
|
||||
|
||||
// init structure
|
||||
initStructure(): Structure {
|
||||
return Object.assign({
|
||||
id: 0,
|
||||
field: '',
|
||||
label: '',
|
||||
type: '',
|
||||
length: 0,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
default: '',
|
||||
comment: '',
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* finished
|
||||
*/
|
||||
finished(): void {
|
||||
this.$reset()
|
||||
this.is_finished = true
|
||||
},
|
||||
|
||||
/**
|
||||
* unfinished
|
||||
*/
|
||||
start(): void {
|
||||
this.is_finished = false
|
||||
},
|
||||
},
|
||||
})
|
Reference in New Issue
Block a user