表前缀

This commit is contained in:
李琦
2026-01-23 17:13:23 +08:00
parent 0d21609586
commit a1abba3835
8 changed files with 1850 additions and 2 deletions

View File

@@ -0,0 +1,308 @@
<?php
namespace App\Http\Controllers\Api;
use App\BaseApp\BaseController;
use App\Service\DatabaseService;
use Exception;
use Illuminate\Http\JsonResponse;
class DatabaseController extends BaseController
{
public function __construct()
{
parent::__construct();
$this->service = DatabaseService::getInstance();
}
/**
* 获取表列表
* @Method GET
* @return JsonResponse
*/
public function listTables(): JsonResponse
{
return jok($this->service->listTables());
}
/**
* 获取表详细信息
* @Method GET
* @return JsonResponse
* @throws Exception
*/
public function getTableInfo(): JsonResponse
{
$tableName = request()->get('table_name');
if (!$tableName) {
return jerr('表名不能为空');
}
return jok($this->service->getTableInfo($tableName));
}
/**
* 获取表数据(分页)
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function getTableData(): JsonResponse
{
$tableName = request()->post('table_name');
$page = request()->post('page', 1);
$pageSize = request()->post('page_size', 20);
$where = request()->post('where', []);
if (!$tableName) {
return jerr('表名不能为空');
}
return jok($this->service->getTableData($tableName, $page, $pageSize, $where));
}
/**
* 更新表数据
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function updateTableData(): JsonResponse
{
$tableName = request()->post('table_name');
$data = request()->post('data', []);
$where = request()->post('where', []);
if (!$tableName) {
return jerr('表名不能为空');
}
if (empty($data)) {
return jerr('更新数据不能为空');
}
if (empty($where)) {
return jerr('WHERE条件不能为空');
}
$result = $this->service->updateTableData($tableName, $data, $where);
return jok($result, '更新成功');
}
/**
* 删除表数据
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function deleteTableData(): JsonResponse
{
$tableName = request()->post('table_name');
$where = request()->post('where', []);
if (!$tableName) {
return jerr('表名不能为空');
}
if (empty($where)) {
return jerr('WHERE条件不能为空');
}
$result = $this->service->deleteTableData($tableName, $where);
return jok($result, '删除成功');
}
/**
* 批量删除表数据
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function batchDeleteTableData(): JsonResponse
{
$tableName = request()->post('table_name');
$where = request()->post('where', []);
if (!$tableName) {
return jerr('表名不能为空');
}
if (empty($where)) {
return jerr('WHERE条件不能为空');
}
$count = $this->service->batchDeleteTableData($tableName, $where);
return jok(['count' => $count], "成功删除 {$count} 条记录");
}
/**
* 插入表数据
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function insertTableData(): JsonResponse
{
$tableName = request()->post('table_name');
$data = request()->post('data', []);
if (!$tableName) {
return jerr('表名不能为空');
}
if (empty($data)) {
return jerr('插入数据不能为空');
}
$id = $this->service->insertTableData($tableName, $data);
return jok(['id' => $id], '插入成功');
}
/**
* 更新表注释
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function updateTableComment(): JsonResponse
{
$tableName = request()->post('table_name');
$comment = request()->post('comment', '');
if (!$tableName) {
return jerr('表名不能为空');
}
$this->service->updateTableComment($tableName, $comment);
return jok(true, '更新成功');
}
/**
* 更新字段注释
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function updateColumnComment(): JsonResponse
{
$tableName = request()->post('table_name');
$columnName = request()->post('column_name');
$comment = request()->post('comment', '');
if (!$tableName) {
return jerr('表名不能为空');
}
if (!$columnName) {
return jerr('字段名不能为空');
}
$this->service->updateColumnComment($tableName, $columnName, $comment);
return jok(true, '更新成功');
}
/**
* 添加索引
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function addIndex(): JsonResponse
{
$tableName = request()->post('table_name');
$indexName = request()->post('index_name');
$columns = request()->post('columns', []);
$unique = request()->post('unique', false);
$type = request()->post('type', 'BTREE');
if (!$tableName) {
return jerr('表名不能为空');
}
if (!$indexName) {
return jerr('索引名不能为空');
}
if (empty($columns)) {
return jerr('索引列不能为空');
}
$this->service->addIndex($tableName, $indexName, $columns, $unique, $type);
return jok(true, '添加成功');
}
/**
* 删除索引
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function dropIndex(): JsonResponse
{
$tableName = request()->post('table_name');
$indexName = request()->post('index_name');
if (!$tableName) {
return jerr('表名不能为空');
}
if (!$indexName) {
return jerr('索引名不能为空');
}
$this->service->dropIndex($tableName, $indexName);
return jok(true, '删除成功');
}
/**
* 修改表结构
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function updateTableStructure(): JsonResponse
{
$tableName = request()->post('table_name');
$action = request()->post('action'); // add|modify|drop
$columnInfo = request()->post('column_info', []);
if (!$tableName) {
return jerr('表名不能为空');
}
if (!in_array($action, ['add', 'modify', 'drop'])) {
return jerr('操作类型不正确');
}
$this->service->updateTableStructure($tableName, $action, $columnInfo);
return jok(true, '操作成功');
}
/**
* 执行SQL查询仅SELECT
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function executeSqlQuery(): JsonResponse
{
$sql = request()->post('sql');
if (empty($sql)) {
return jerr('SQL语句不能为空');
}
$results = $this->service->executeSelectQuery($sql);
return jok($results, '查询成功');
}
/**
* 获取变更记录列表
* @Method GET
* @return JsonResponse
* @throws Exception
*/
public function getChangeLog(): JsonResponse
{
$page = request()->get('page', 1);
$pageSize = request()->get('page_size', 20);
$filters = [
'table_name' => request()->get('table_name'),
'operation_type' => request()->get('operation_type'),
'start_time' => request()->get('start_time'),
'end_time' => request()->get('end_time'),
];
$result = $this->service->getChangeLog((int)$page, (int)$pageSize, array_filter($filters));
return jok($result, '获取成功');
}
}

View File

@@ -42,6 +42,49 @@ class CodeGenerationController extends BaseController
);
}
/**
* 批量生成代码
* @Method POST
* @return JsonResponse
* @throws \Exception
*/
public function batchGeneration()
{
$params = request()->post();
if (!is_array($params) || empty($params)) {
return jerr('参数错误,需要数组格式!');
}
$results = [];
$errors = [];
foreach ($params as $index => $item) {
try {
// 验证必填字段
if (empty($item['class_name']) || empty($item['field']) || !is_array($item['field'])) {
$errors[] = "模块 " . ($index + 1) . " 参数不完整";
continue;
}
$result = $this->service->generate($item);
$results[] = $result;
} catch (\Exception $e) {
$errors[] = "模块 " . ($index + 1) . " 生成失败: " . $e->getMessage();
}
}
if (empty($results)) {
return jerr('批量生成失败:' . implode('; ', $errors));
}
if (!empty($errors)) {
return jok($results, '部分生成成功,共生成 ' . count($results) . ' 个模块。错误:' . implode('; ', $errors));
}
return jok($results, '批量生成成功,共生成 ' . count($results) . ' 个模块!');
}
public function download()
{
// $id = request()->post('id');
@@ -64,4 +107,57 @@ class CodeGenerationController extends BaseController
);
}
/**
* 获取数据库表列表
* @Method GET
* @return JsonResponse
*/
public function getTables()
{
return jok(
$this->service->getTableList()
);
}
/**
* 获取表结构
* @Method GET
* @return JsonResponse
* @throws \Exception
*/
public function getTableStructure()
{
$tableName = request()->get('table_name');
if (!$tableName) {
return jerr('表名不能为空!');
}
return jok(
$this->service->getTableColumns($tableName)
);
}
/**
* 从数据库表生成代码生成数据
* @Method POST
* @return JsonResponse
* @throws \Exception
*/
public function generateFromTable()
{
$tableName = request()->post('table_name');
$className = request()->post('class_name', '');
$classComment = request()->post('class_comment', '');
$icon = request()->post('icon', '');
$sort = request()->post('sort', 9999);
$pid = request()->post('pid', 0);
if (!$tableName) {
return jerr('表名不能为空!');
}
$codeGenData = $this->service->convertTableToCodeGenData($tableName, $className, $classComment, $icon, $sort, $pid);
return jok($codeGenData);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -260,6 +260,7 @@ class CodeGenerationService
$this->genViews();
// 生成菜单
$this->genMenu();
DB::commit();
} catch (Exception $e) {
DB::rollBack();
// ds([
@@ -537,4 +538,172 @@ class CodeGenerationService
$this->utils->errorThrow($e->getMessage());
}
}
/**
* 获取数据库表列表
* @return array
*/
public function getTableList(): array
{
$database = config('database.connections.mysql.database');
$prefix = config('database.prefix', 'nl_');
$tables = DB::select("
SELECT
TABLE_NAME as `name`,
TABLE_COMMENT as `comment`,
TABLE_ROWS as `rows`,
CREATE_TIME as create_time
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = ?
AND TABLE_NAME LIKE ?
ORDER BY TABLE_NAME
", [$database, $prefix . '%']);
$result = [];
foreach ($tables as $table) {
$result[] = [
'name' => $table->name,
'comment' => $table->comment ?: $table->name,
'rows' => $table->rows,
'create_time' => $table->create_time,
];
}
return $result;
}
/**
* 获取表字段信息
* @param string $tableName
* @return array
* @throws Exception
*/
public function getTableColumns(string $tableName): array
{
$database = config('database.connections.mysql.database');
$columns = DB::select("
SELECT
COLUMN_NAME as `name`,
DATA_TYPE as `type`,
CHARACTER_MAXIMUM_LENGTH as `length`,
COLUMN_DEFAULT as default_value,
COLUMN_COMMENT as `comment`,
IS_NULLABLE as nullable,
COLUMN_KEY as key_type,
EXTRA as extra
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = ?
AND TABLE_NAME = ?
ORDER BY ORDINAL_POSITION
", [$database, $tableName]);
if (empty($columns)) {
$this->utils->errorThrow('表不存在或没有字段');
}
$result = [];
foreach ($columns as $column) {
// 跳过id字段代码生成会自动添加
if ($column->name === 'id') {
continue;
}
// 跳过系统字段
if (in_array($column->name, ['created_at', 'updated_at', 'deleted_at', 'status'])) {
continue;
}
// 转换数据类型
$type = strtoupper($column->type);
$typeLength = '';
if (in_array($type, ['VARCHAR', 'CHAR'])) {
$typeLength = $column->length ?: '255';
} elseif (in_array($type, ['INT', 'TINYINT', 'BIGINT', 'SMALLINT'])) {
$typeLength = $column->length ?: '11';
} elseif (in_array($type, ['DECIMAL', 'FLOAT', 'DOUBLE'])) {
$typeLength = $column->length ?: '10,2';
}
// 判断表单组件类型
$formType = 'VbenInput';
if (strpos($type, 'TEXT') !== false) {
$formType = 'VbenTextarea';
} elseif (in_array($type, ['TINYINT', 'INT']) && $column->length == 1) {
$formType = 'VbenSwitch';
} elseif (strpos($column->name, 'time') !== false || strpos($column->name, 'date') !== false) {
$formType = 'VbenDatePicker';
}
$result[] = [
'name' => $column->name,
'type' => $type,
'type_length' => $typeLength,
'default' => $column->default_value ?? '',
'comment' => $column->comment ?: $column->name,
'not_null' => $column->nullable === 'NO' ? 1 : 0,
'formShow' => 1,
'tableShow' => 1,
'formType' => $formType,
'search' => in_array($type, ['VARCHAR', 'CHAR', 'INT', 'TINYINT', 'BIGINT']) ? 1 : 0,
'searchValue' => in_array($type, ['VARCHAR', 'CHAR']) ? 'like' : '=',
];
}
return $result;
}
/**
* 将数据库表结构转换为代码生成数据格式
* @param string $tableName
* @param string $className
* @param string $classComment
* @param string $icon
* @param int $sort
* @param int $pid
* @return array
* @throws Exception
*/
public function convertTableToCodeGenData(
string $tableName,
string $className = '',
string $classComment = '',
string $icon = '',
int $sort = 9999,
int $pid = 0
): array {
// 如果没有提供类名,从表名生成
if (empty($className)) {
$prefix = config('database.prefix', 'nl_');
$tableNameWithoutPrefix = str_replace($prefix, '', $tableName);
// 下划线转驼峰
$className = str_replace('_', '', ucwords($tableNameWithoutPrefix, '_'));
}
// 如果没有提供中文名称,使用表注释或表名
if (empty($classComment)) {
$database = config('database.connections.mysql.database');
$tableInfo = DB::selectOne("
SELECT TABLE_COMMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
", [$database, $tableName]);
$classComment = $tableInfo->TABLE_COMMENT ?: $tableName;
}
// 获取字段信息
$fields = $this->getTableColumns($tableName);
return [
'class_name' => $className,
'class_comment' => $classComment,
'icon' => $icon,
'sort' => $sort,
'pid' => $pid,
'field' => $fields,
];
}
}