483 lines
15 KiB
PHP
483 lines
15 KiB
PHP
<?php
|
|
/**
|
|
* MineAdmin is committed to providing solutions for quickly building web applications
|
|
* Please view the LICENSE file that was distributed with this source code,
|
|
* For the full copyright and license information.
|
|
* Thank you very much for using MineAdmin.
|
|
*
|
|
* @Author X.Mo<root@imoi.cn>
|
|
* @Link https://gitee.com/xmo/MineAdmin
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
namespace Builder\Generator;
|
|
|
|
use App\Setting\Model\SettingGenerateColumns;
|
|
use App\Setting\Model\SettingGenerateTables;
|
|
use Hyperf\Utils\Filesystem\Filesystem;
|
|
use Builder\Exception\NormalStatusException;
|
|
use Builder\Helper\Str;
|
|
use Hyperf\Database\Model\Collection;
|
|
|
|
/**
|
|
* Vue index文件生成
|
|
* Class VueIndexGenerator
|
|
* @package Builder\Generator
|
|
*/
|
|
class VueIndexGenerator extends MineGenerator implements CodeGenerator
|
|
{
|
|
/**
|
|
* @var SettingGenerateTables
|
|
*/
|
|
protected SettingGenerateTables $model;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected string $codeContent;
|
|
|
|
/**
|
|
* @var Filesystem
|
|
*/
|
|
protected Filesystem $filesystem;
|
|
|
|
/**
|
|
* @var Collection
|
|
*/
|
|
protected Collection $columns;
|
|
|
|
/**
|
|
* 设置生成信息
|
|
* @param SettingGenerateTables $model
|
|
* @return VueIndexGenerator
|
|
* @throws \Psr\Container\ContainerExceptionInterface
|
|
* @throws \Psr\Container\NotFoundExceptionInterface
|
|
*/
|
|
public function setGenInfo(SettingGenerateTables $model): VueIndexGenerator
|
|
{
|
|
$this->model = $model;
|
|
$this->filesystem = make(Filesystem::class);
|
|
if (empty($model->module_name) || empty($model->menu_name)) {
|
|
throw new NormalStatusException(t('setting.gen_code_edit'));
|
|
}
|
|
$this->columns = SettingGenerateColumns::query()
|
|
->where('table_id', $model->id)->orderByDesc('sort')
|
|
->get([
|
|
'column_name', 'column_comment', 'allow_roles', 'options', 'is_required', 'is_insert',
|
|
'is_edit', 'is_query', 'is_sort', 'is_pk', 'is_list', 'view_type', 'dict_type',
|
|
]);
|
|
|
|
return $this->placeholderReplace();
|
|
}
|
|
|
|
/**
|
|
* 生成代码
|
|
*/
|
|
public function generator(): void
|
|
{
|
|
$module = Str::lower($this->model->module_name);
|
|
$path = BASE_PATH . "/runtime/generate/vue/src/views/{$module}/{$this->getShortBusinessName()}/index.vue";
|
|
$this->filesystem->makeDirectory(
|
|
BASE_PATH . "/runtime/generate/vue/src/views/{$module}/{$this->getShortBusinessName()}",
|
|
0755, true, true
|
|
);
|
|
$this->filesystem->put($path, $this->replace()->getCodeContent());
|
|
}
|
|
|
|
/**
|
|
* 预览代码
|
|
*/
|
|
public function preview(): string
|
|
{
|
|
return $this->replace()->getCodeContent();
|
|
}
|
|
|
|
/**
|
|
* 获取模板地址
|
|
* @return string
|
|
*/
|
|
protected function getTemplatePath(): string
|
|
{
|
|
return $this->getStubDir().'/Vue/index.stub';
|
|
}
|
|
|
|
/**
|
|
* 读取模板内容
|
|
* @return string
|
|
*/
|
|
protected function readTemplate(): string
|
|
{
|
|
return $this->filesystem->sharedGet($this->getTemplatePath());
|
|
}
|
|
|
|
/**
|
|
* 占位符替换
|
|
*/
|
|
protected function placeholderReplace(): VueIndexGenerator
|
|
{
|
|
$this->setCodeContent(str_replace(
|
|
$this->getPlaceHolderContent(),
|
|
$this->getReplaceContent(),
|
|
$this->readTemplate()
|
|
));
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 获取要替换的占位符
|
|
*/
|
|
protected function getPlaceHolderContent(): array
|
|
{
|
|
return [
|
|
'{CODE}',
|
|
'{CRUD}',
|
|
'{COLUMNS}',
|
|
'{BUSINESS_EN_NAME}',
|
|
'{INPUT_NUMBER}',
|
|
'{SWITCH_STATUS}',
|
|
'{MODULE_NAME}',
|
|
'{PK}',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取要替换占位符的内容
|
|
* @return string[]
|
|
*/
|
|
protected function getReplaceContent(): array
|
|
{
|
|
return [
|
|
$this->getCode(),
|
|
$this->getCrud(),
|
|
$this->getColumns(),
|
|
$this->getBusinessEnName(),
|
|
$this->getInputNumber(),
|
|
$this->getSwitchStatus(),
|
|
$this->getModuleName(),
|
|
$this->getPk(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取标识代码
|
|
* @return string
|
|
*/
|
|
protected function getCode(): string
|
|
{
|
|
return Str::lower($this->model->module_name) . ':' . $this->getShortBusinessName();
|
|
}
|
|
|
|
/**
|
|
* 获取CRUD配置代码
|
|
* @return string
|
|
*/
|
|
protected function getCrud(): string
|
|
{
|
|
// 配置项
|
|
$options = [];
|
|
$options['rowSelection'] = [ 'showCheckedAll' => true ];
|
|
$options['searchLabelWidth'] = "'75px'";
|
|
$options['pk'] = "'".$this->getPk()."'";
|
|
$options['operationColumn'] = false;
|
|
$options['operationWidth'] = 160;
|
|
$options['viewLayoutSetting'] = [
|
|
'layout' => "'auto'",
|
|
'cols' => 1,
|
|
'viewType' => $this->model->component_type == 1 ? "'modal'" : "'drawer'",
|
|
'width' => 600,
|
|
];
|
|
$options['api'] = $this->getBusinessEnName() . '.getList';
|
|
if (Str::contains($this->model->generate_menus, 'recycle')) {
|
|
$options['recycleApi'] = $this->getBusinessEnName() . '.getRecycleList';
|
|
}
|
|
if (Str::contains($this->model->generate_menus, 'save')) {
|
|
$options['add'] = [
|
|
'show' => true, 'api' => $this->getBusinessEnName() . '.save',
|
|
'auth' => "['".$this->getCode().":save']"
|
|
];
|
|
}
|
|
if (Str::contains($this->model->generate_menus, 'update')) {
|
|
$options['operationColumn'] = true;
|
|
$options['edit'] = [
|
|
'show' => true, 'api' => $this->getBusinessEnName() . '.update',
|
|
'auth' => "['".$this->getCode().":update']"
|
|
];
|
|
}
|
|
if (Str::contains($this->model->generate_menus, 'delete')) {
|
|
$options['operationColumn'] = true;
|
|
$options['delete'] = [
|
|
'show' => true,
|
|
'api' => $this->getBusinessEnName() . '.deletes',
|
|
'auth' => "['".$this->getCode().":delete']"
|
|
];
|
|
if (Str::contains($this->model->generate_menus, 'recycle')) {
|
|
$options['delete']['realApi'] = $this->getBusinessEnName() . '.realDeletes';
|
|
$options['delete']['realAuth'] = "['".$this->getCode().":realDeletes']";
|
|
$options['recovery'] = [
|
|
'show' => true,
|
|
'api' => $this->getBusinessEnName() . '.recoverys',
|
|
'auth' => "['".$this->getCode().":recovery']"
|
|
];
|
|
}
|
|
}
|
|
$requestRoute = Str::lower($this->model->module_name) . '/' . $this->getShortBusinessName();
|
|
// 导入
|
|
if (Str::contains($this->model->generate_menus, 'import')) {
|
|
$options['import'] = [
|
|
'show' => true,
|
|
'url' => "'".$requestRoute . '/import'."'",
|
|
'templateUrl' => "'".$requestRoute . '/downloadTemplate'."'",
|
|
'auth' => "['".$this->getCode().":import']"
|
|
];
|
|
}
|
|
// 导出
|
|
if (Str::contains($this->model->generate_menus, 'export')) {
|
|
$options['export'] = [
|
|
'show' => true,
|
|
'url' => "'".$requestRoute . '/export'."'",
|
|
'auth' => "['".$this->getCode().":export']"
|
|
];
|
|
}
|
|
return 'const crud = reactive(' . $this->jsonFormat($options, true) . ')';
|
|
}
|
|
|
|
/**
|
|
* 获取列配置代码
|
|
* @return string
|
|
*/
|
|
protected function getColumns(): string
|
|
{
|
|
// 字段配置项
|
|
$options = [];
|
|
foreach ($this->columns as $column) {
|
|
$tmp = [
|
|
'title' => $column->column_comment,
|
|
'dataIndex' => $column->column_name,
|
|
'formType' => $this->getViewType($column->view_type),
|
|
];
|
|
// 基础
|
|
if ($column->is_query == self::YES) {
|
|
$tmp['search'] = true;
|
|
}
|
|
if ($column->is_insert == self::NO) {
|
|
$tmp['addDisplay'] = false;
|
|
}
|
|
if ($column->is_edit == self::NO) {
|
|
$tmp['editDisplay'] = false;
|
|
}
|
|
if ($column->is_list == self::NO) {
|
|
$tmp['hide'] = true;
|
|
}
|
|
if ($column->is_required == self::YES) {
|
|
$tmp['rules'] = [
|
|
'required' => true,
|
|
'message' => '请输入' . $column->column_comment
|
|
];
|
|
}
|
|
if ($column->is_sort == self::YES) {
|
|
$tmp['sortable'] = [
|
|
'sortDirections' => [ 'ascend', 'descend' ],
|
|
'sorter' => true
|
|
];
|
|
}
|
|
// 扩展项
|
|
if (!empty($column->options)) {
|
|
$collection = $column->options['collection'];
|
|
// 合并
|
|
$tmp = array_merge($tmp, $column->options);
|
|
// 自定义数据
|
|
if (in_array($column->view_type, ['checkbox', 'radio', 'select', 'transfer']) && !empty($collection)) {
|
|
$tmp['dict'] = [ 'data' => $collection, 'translation' => true ];
|
|
}
|
|
// 对日期时间处理
|
|
if ($column->view_type == 'date' && $column->options['mode'] == 'date') {
|
|
unset($tmp['mode']);
|
|
if (isset($column->options['range']) && $column->options['range']) {
|
|
$tmp['formType'] = 'range';
|
|
unset($tmp['range']);
|
|
}
|
|
}
|
|
unset($tmp['collection']);
|
|
}
|
|
// 字典
|
|
if (!empty($column->dict_type)) {
|
|
$tmp['dict'] = [
|
|
'name' => $column->dict_type,
|
|
'props' => [ 'label' => 'title', 'value' => 'key' ],
|
|
'translation' => true
|
|
];
|
|
}
|
|
// 密码处理
|
|
if ($column->view_type == 'password') {
|
|
$tmp['type'] = 'password';
|
|
}
|
|
// 允许查看字段的角色(前端还待支持)
|
|
// todo...
|
|
$options[] = $tmp;
|
|
}
|
|
return 'const columns = reactive(' . $this->jsonFormat($options) . ')';
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function getShowRecycle(): string
|
|
{
|
|
return ( strpos($this->model->generate_menus, 'recycle') > 0 ) ? 'true' : 'false';
|
|
}
|
|
|
|
/**
|
|
* 获取业务英文名
|
|
* @return string
|
|
*/
|
|
protected function getBusinessEnName(): string
|
|
{
|
|
return Str::camel(str_replace(env('DB_PREFIX'), '', $this->model->table_name));
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function getModuleName(): string
|
|
{
|
|
return Str::lower($this->model->module_name);
|
|
}
|
|
|
|
/**
|
|
* 返回主键
|
|
* @return string
|
|
*/
|
|
protected function getPk(): string
|
|
{
|
|
foreach ($this->columns as $column) {
|
|
if ($column->is_pk == self::YES) {
|
|
return $column->column_name;
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* 计数器组件方法
|
|
* @return string
|
|
* @noinspection BadExpressionStatementJS
|
|
*/
|
|
protected function getInputNumber(): string
|
|
{
|
|
if (in_array('numberOperation' , explode(',', $this->model->generate_menus))) {
|
|
return str_replace('{BUSINESS_EN_NAME}', $this->getBusinessEnName(), $this->getOtherTemplate('numberOperation'));
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* 计数器组件方法
|
|
* @return string
|
|
* @noinspection BadExpressionStatementJS
|
|
*/
|
|
protected function getSwitchStatus(): string
|
|
{
|
|
if (in_array('changeStatus' , explode(',', $this->model->generate_menus))) {
|
|
return str_replace('{BUSINESS_EN_NAME}', $this->getBusinessEnName(), $this->getOtherTemplate('switchStatus'));
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* @param string $tpl
|
|
* @return string
|
|
*/
|
|
protected function getOtherTemplate(string $tpl): string
|
|
{
|
|
return $this->filesystem->sharedGet($this->getStubDir() . "/Vue/{$tpl}.stub");
|
|
}
|
|
|
|
/**
|
|
* 获取短业务名称
|
|
* @return string
|
|
*/
|
|
public function getShortBusinessName(): string
|
|
{
|
|
return Str::camel(str_replace(
|
|
Str::lower($this->model->module_name),
|
|
'',
|
|
str_replace(env('DB_PREFIX'), '', $this->model->table_name)
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 视图组件
|
|
* @param string $viewType
|
|
* @return string
|
|
*/
|
|
protected function getViewType(string $viewType): string
|
|
{
|
|
$viewTypes = [
|
|
'text' => 'input',
|
|
'password' => 'input',
|
|
'textarea' => 'textarea',
|
|
'inputNumber' => 'input-number',
|
|
'inputTag' => 'input-tag',
|
|
'mention' => 'mention',
|
|
'switch' => 'switch',
|
|
'slider' => 'slider',
|
|
'select' => 'select',
|
|
'radio' => 'radio',
|
|
'checkbox' => 'checkbox',
|
|
'treeSelect' => 'tree-select',
|
|
'date' => 'date',
|
|
'time' => 'time',
|
|
'rate' => 'rate',
|
|
'cascader' => 'cascader',
|
|
'transfer' => 'transfer',
|
|
'selectUser' => 'select-user',
|
|
'userInfo' => 'user-info',
|
|
'cityLinkage' => 'city-linkage',
|
|
'icon' => 'icon',
|
|
'formGroup' => 'form-group',
|
|
'upload' => 'upload',
|
|
'selectResource' => 'select-resource',
|
|
'editor' => 'editor',
|
|
'codeEditor' => 'code-editor',
|
|
];
|
|
|
|
return $viewTypes[$viewType] ?? 'input';
|
|
}
|
|
|
|
/**
|
|
* array 到 json 数据格式化
|
|
* @param array $data
|
|
* @param bool $removeValueQuotes
|
|
* @return string
|
|
*/
|
|
protected function jsonFormat(array $data, bool $removeValueQuotes = false): string
|
|
{
|
|
$data = str_replace(' ', ' ', json_encode($data, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));
|
|
$data = str_replace(['"true"', '"false"', "\\"], [ true, false, ''], $data);
|
|
$data = preg_replace('/(\s+)\"(.+)\":/', "\\1\\2:", $data);
|
|
if ($removeValueQuotes) {
|
|
$data = preg_replace('/(:\s)\"(.+)\"/', "\\1\\2", $data);
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 设置代码内容
|
|
* @param string $content
|
|
*/
|
|
public function setCodeContent(string $content)
|
|
{
|
|
$this->codeContent = $content;
|
|
}
|
|
|
|
/**
|
|
* 获取代码内容
|
|
* @return string
|
|
*/
|
|
public function getCodeContent(): string
|
|
{
|
|
return $this->codeContent;
|
|
}
|
|
|
|
} |