feat(CRUD):多数据库连接配置支持

This commit is contained in:
2368302435@qq.com 2024-02-29 21:06:37 +08:00
parent c95fc126d0
commit bbeb267649
11 changed files with 259 additions and 172 deletions

View File

@ -59,7 +59,7 @@ class Crud extends Backend
*/
protected array $dtStringToArray = ['checkbox', 'selects', 'remoteSelects', 'city', 'images', 'files'];
protected array $noNeedPermission = ['logStart', 'getFileData', 'parseFieldData', 'generateCheck', 'databaseList'];
protected array $noNeedPermission = ['logStart', 'getFileData', 'parseFieldData', 'generateCheck'];
public function initialize(): void
{
@ -89,11 +89,11 @@ class Crud extends Backend
]);
// 表名称
$tableName = TableManager::tableName($table['name'], false);
$tableName = TableManager::tableName($table['name'], false, $table['databaseConnection']);
if ($type == 'create' || $table['rebuild'] == 'Yes') {
// 数据表存在则删除
TableManager::phinxTable($tableName)->drop()->save();
TableManager::phinxTable($tableName, [], true, $table['databaseConnection'])->drop()->save();
}
// 处理表设计
@ -127,6 +127,7 @@ class Crud extends Backend
$this->modelData['beforeInsertMixins'] = [];
$this->modelData['beforeInsert'] = '';
$this->modelData['afterInsert'] = '';
$this->modelData['connection'] = $table['databaseConnection'];
$this->modelData['name'] = $tableName;
$this->modelData['className'] = $modelFile['lastName'];
$this->modelData['namespace'] = $modelFile['namespace'];
@ -205,7 +206,7 @@ class Crud extends Backend
// 关联表数据解析
if (in_array($field['designType'], ['remoteSelect', 'remoteSelects'])) {
$this->parseJoinData($field);
$this->parseJoinData($field, $table);
}
// 模型方法
@ -308,9 +309,15 @@ class Crud extends Backend
}
// 数据表是否有数据
$adapter = TableManager::phinxAdapter();
if ($adapter->hasTable($info['table']['name'])) {
$info['table']['empty'] = Db::name($info['table']['name'])->limit(1)->select()->isEmpty();
$connection = TableManager::getConnection($info['table']['databaseConnection']);
$tableName = TableManager::tableName($info['table']['name'], false, $connection);
$adapter = TableManager::phinxAdapter(true, $connection);
if ($adapter->hasTable($tableName)) {
$info['table']['empty'] = Db::connect($connection)
->name($tableName)
->limit(1)
->select()
->isEmpty();
} else {
$info['table']['empty'] = true;
}
@ -438,9 +445,13 @@ class Crud extends Backend
*/
public function checkCrudLog(): void
{
$table = $this->request->get('table');
$table = $this->request->get('table');
$connection = $this->request->get('connection');
$connection = $connection ?: config('database.default');
$crudLog = Db::name('crud_log')
->where('table_name', $table)
->where('connection', $connection)
->order('create_time desc')
->find();
$this->success('', [
@ -455,27 +466,36 @@ class Crud extends Backend
public function parseFieldData(): void
{
AdminLog::setTitle(__('Parse field data'));
$type = $this->request->post('type');
$table = $this->request->post('table');
$table = TableManager::tableName($table);
$type = $this->request->post('type');
$table = $this->request->post('table');
$connection = $this->request->post('connection');
$connection = TableManager::getConnection($connection);
$table = TableManager::tableName($table, true, $connection);
$connectionConfig = TableManager::getConnectionConfig($connection);
if ($type == 'db') {
$sql = 'SELECT * FROM `information_schema`.`tables` '
. 'WHERE TABLE_SCHEMA = ? AND table_name = ?';
$tableInfo = Db::query($sql, [config('database.connections.mysql.database'), $table]);
$tableInfo = Db::connect($connection)->query($sql, [$connectionConfig['database'], $table]);
if (!$tableInfo) {
$this->error(__('Record not found'));
}
// 数据表是否有数据
$adapter = TableManager::phinxAdapter(false);
$adapter = TableManager::phinxAdapter(false, $connection);
if ($adapter->hasTable($table)) {
$empty = Db::table($table)->limit(1)->select()->isEmpty();
$empty = Db::connect($connection)
->table($table)
->limit(1)
->select()
->isEmpty();
} else {
$empty = true;
}
$this->success('', [
'columns' => Helper::parseTableColumns($table),
'columns' => Helper::parseTableColumns($table, false, $connection),
'comment' => $tableInfo[0]['TABLE_COMMENT'] ?? '',
'empty' => $empty,
]);
@ -490,6 +510,7 @@ class Crud extends Backend
{
$table = $this->request->post('table');
$controllerFile = $this->request->post('controllerFile', '');
$connection = $this->request->post('connection');
if (!$table) {
$this->error(__('Parameter error'));
@ -505,8 +526,8 @@ class Crud extends Backend
$this->error($e->getMessage());
}
$tableList = TableManager::getTableList();
$tableExist = array_key_exists(TableManager::tableName($table), $tableList);
$tableList = TableManager::getTableList($connection);
$tableExist = array_key_exists(TableManager::tableName($table, true, $connection), $tableList);
$controllerExist = file_exists(root_path() . $controllerFile);
if ($controllerExist || $tableExist) {
@ -518,55 +539,21 @@ class Crud extends Backend
$this->success();
}
/**
* 数据表列表
* @throws Throwable
*/
public function databaseList(): void
{
$tablePrefix = config('database.connections.mysql.prefix');
$outExcludeTable = [
// 功能表
'area',
'token',
'captcha',
'admin_group_access',
'config',
'admin_log',
// 不建议生成crud的表
'user_money_log',
'user_score_log',
];
$outTables = [];
$tables = TableManager::getTableList();
$pattern = '/^' . $tablePrefix . '/i';
foreach ($tables as $table => $tableComment) {
if (!preg_match($pattern, $table)) continue;
$table = preg_replace($pattern, '', $table);
if (!in_array($table, $outExcludeTable)) {
$outTables[$table] = $tableComment;
}
}
$this->success('', [
'dbs' => $outTables,
]);
}
/**
* 关联表数据解析
* @param $field
* @param $table
* @throws Throwable
*/
private function parseJoinData($field): void
private function parseJoinData($field, $table): void
{
$dictEn = [];
$dictZhCn = [];
if ($field['form']['relation-fields'] && $field['form']['remote-table']) {
$columns = Helper::parseTableColumns($field['form']['remote-table'], true);
$columns = Helper::parseTableColumns($field['form']['remote-table'], true, $table['databaseConnection']);
$relationFields = explode(',', $field['form']['relation-fields']);
$tableName = TableManager::tableName($field['form']['remote-table'], false);
$tableName = TableManager::tableName($field['form']['remote-table'], false, $table['databaseConnection']);
$rnPattern = '/(.*)(_ids|_id)$/';
if (preg_match($rnPattern, $field['name'])) {
$relationName = parse_name(preg_replace($rnPattern, '$1', $field['name']), 1, false);
@ -586,6 +573,7 @@ class Crud extends Backend
$joinModelData['beforeInsertMixins'] = [];
$joinModelData['beforeInsert'] = '';
$joinModelData['afterInsert'] = '';
$joinModelData['connection'] = $table['databaseConnection'];
$joinModelData['name'] = $tableName;
$joinModelData['className'] = $joinModelFile['lastName'];
$joinModelData['namespace'] = $joinModelFile['namespace'];

View File

@ -281,10 +281,13 @@ class Helper
]);
return $data['id'];
}
$log = CrudLog::create([
$connection = $data['table']['databaseConnection'] ?: config('database.default');
$log = CrudLog::create([
'table_name' => $data['table']['name'],
'table' => $data['table'],
'fields' => $data['fields'],
'connection' => $connection,
'status' => $data['status'],
]);
return $log->id;
@ -424,16 +427,17 @@ class Helper
/**
* 表字段排序
* @param string $tableName 表名
* @param array $fields 字段数据
* @param array $designChange 前端字段改变数据
* @param string $tableName 表名
* @param array $fields 字段数据
* @param array $designChange 前端字段改变数据
* @param ?string $connection 数据库连接标识
* @return void
* @throws Throwable
*/
public static function updateFieldOrder(string $tableName, array $fields, array $designChange): void
public static function updateFieldOrder(string $tableName, array $fields, array $designChange, ?string $connection = null): void
{
if ($designChange) {
$table = TableManager::phinxTable($tableName, [], false);
$table = TableManager::phinxTable($tableName, [], false, $connection);
foreach ($designChange as $item) {
if (!$item['sync']) continue;
@ -469,10 +473,10 @@ class Helper
*/
public static function handleTableDesign(array $table, array $fields): array
{
$name = TableManager::tableName($table['name']);
$name = TableManager::tableName($table['name'], true, $table['databaseConnection']);
$comment = $table['comment'] ?? '';
$designChange = $table['designChange'] ?? [];
$adapter = TableManager::phinxAdapter(false);
$adapter = TableManager::phinxAdapter(false, $table['databaseConnection']);
$pk = self::searchArray($fields, function ($item) {
return $item['primaryKey'];
@ -482,8 +486,8 @@ class Helper
if ($adapter->hasTable($name)) {
// 更新表
if ($designChange) {
$table = TableManager::phinxTable($name, [], false);
$table->changeComment($comment)->update();
$tableManager = TableManager::phinxTable($name, [], false, $table['databaseConnection']);
$tableManager->changeComment($comment)->update();
// 改名和删除操作优先
$priorityOpt = false;
@ -491,23 +495,23 @@ class Helper
if (!$item['sync']) continue;
if (in_array($item['type'], ['change-field-name', 'del-field']) && !$table->hasColumn($item['oldName'])) {
if (in_array($item['type'], ['change-field-name', 'del-field']) && !$tableManager->hasColumn($item['oldName'])) {
// 字段不存在
throw new BaException(__($item['type'] . ' fail not exist', [$item['oldName']]));
}
if ($item['type'] == 'change-field-name') {
$priorityOpt = true;
$table->renameColumn($item['oldName'], $item['newName']);
$tableManager->renameColumn($item['oldName'], $item['newName']);
} elseif ($item['type'] == 'del-field') {
$priorityOpt = true;
$table->removeColumn($item['oldName']);
$tableManager->removeColumn($item['oldName']);
}
}
// 保存需要优先执行的操作,避免先改名再改属性时找不到字段
if ($priorityOpt) {
$table->update();
$tableManager->update();
}
// 修改字段属性和添加字段操作
@ -517,7 +521,7 @@ class Helper
if ($item['type'] == 'change-field-attr') {
if (!$table->hasColumn($item['oldName'])) {
if (!$tableManager->hasColumn($item['oldName'])) {
// 字段不存在
throw new BaException(__($item['type'] . ' fail not exist', [$item['oldName']]));
}
@ -525,10 +529,10 @@ class Helper
$phinxFieldData = self::getPhinxFieldData(self::searchArray($fields, function ($field) use ($item) {
return $field['name'] == $item['oldName'];
}));
$table->changeColumn($item['oldName'], $phinxFieldData['type'], $phinxFieldData['options']);
$tableManager->changeColumn($item['oldName'], $phinxFieldData['type'], $phinxFieldData['options']);
} elseif ($item['type'] == 'add-field') {
if ($table->hasColumn($item['newName'])) {
if ($tableManager->hasColumn($item['newName'])) {
// 字段已经存在
throw new BaException(__($item['type'] . ' fail exist', [$item['newName']]));
}
@ -536,28 +540,28 @@ class Helper
$phinxFieldData = self::getPhinxFieldData(self::searchArray($fields, function ($field) use ($item) {
return $field['name'] == $item['newName'];
}));
$table->addColumn($item['newName'], $phinxFieldData['type'], $phinxFieldData['options']);
$tableManager->addColumn($item['newName'], $phinxFieldData['type'], $phinxFieldData['options']);
}
}
$table->update();
$tableManager->update();
// 表更新结构完成再处理字段排序
self::updateFieldOrder($name, $fields, $designChange);
self::updateFieldOrder($name, $fields, $designChange, $table['databaseConnection']);
}
} else {
// 创建表
$table = TableManager::phinxTable($name, [
$tableManager = TableManager::phinxTable($name, [
'id' => false,
'comment' => $comment,
'row_format' => 'DYNAMIC',
'primary_key' => $pk,
'collation' => 'utf8mb4_unicode_ci',
], false);
], false, $table['databaseConnection']);
foreach ($fields as $field) {
$phinxFieldData = self::getPhinxFieldData($field);
$table->addColumn($field['name'], $phinxFieldData['type'], $phinxFieldData['options']);
$tableManager->addColumn($field['name'], $phinxFieldData['type'], $phinxFieldData['options']);
}
$table->create();
$tableManager->create();
}
return [$pk];
@ -732,15 +736,19 @@ class Helper
* 根据数据表解析字段数据
* @throws Throwable
*/
public static function parseTableColumns(string $table, bool $analyseField = false): array
public static function parseTableColumns(string $table, bool $analyseField = false, ?string $connection = null): array
{
$connection = TableManager::getConnection($connection);
$connectionConfig = TableManager::getConnectionConfig($connection);
// 从数据库中获取表字段信息
$sql = 'SELECT * FROM `information_schema`.`columns` '
. 'WHERE TABLE_SCHEMA = ? AND table_name = ? '
. 'ORDER BY ORDINAL_POSITION';
$columns = [];
$tableColumn = Db::query($sql, [config('database.connections.mysql.database'), TableManager::tableName($table)]);
$tableColumn = Db::connect($connection)->query($sql, [$connectionConfig['database'], TableManager::tableName($table, true, $connection)]);
foreach ($tableColumn as $item) {
$isNullAble = $item['IS_NULLABLE'] == 'YES';
if (str_contains($item['COLUMN_TYPE'], '(')) {
@ -989,7 +997,13 @@ class Helper
public static function writeModelFile(string $tablePk, array $fieldsMap, array $modelData, array $modelFile): void
{
$modelData['pk'] = $tablePk == 'id' ? '' : "\n" . self::tab() . "// 表主键\n" . self::tab() . 'protected $pk = ' . "'$tablePk';\n" . self::tab();
if ($modelData['connection'] && $modelData['connection'] != config('database.default')) {
$modelData['connection'] = "\n" . self::tab() . "// 数据库连接配置标识\n" . self::tab() . 'protected $connection = ' . "'{$modelData['connection']}';\n";
} else {
$modelData['connection'] = '';
}
$modelData['pk'] = $tablePk == 'id' ? '' : "\n" . self::tab() . "// 表主键\n" . self::tab() . 'protected $pk = ' . "'$tablePk';\n";
$modelData['autoWriteTimestamp'] = array_key_exists(self::$createTimeField, $fieldsMap) || array_key_exists(self::$updateTimeField, $fieldsMap) ? 'true' : 'false';
if ($modelData['autoWriteTimestamp'] == 'true') {
$modelData['createTime'] = array_key_exists(self::$createTimeField, $fieldsMap) ? '' : "\n" . self::tab() . "protected \$createTime = false;";

View File

@ -8,7 +8,7 @@ use think\Model;
* {%className%}
*/
class {%className%} extends Model
{{%pk%}
{{%connection%}{%pk%}
// 表名
protected $name = '{%name%}';

View File

@ -26,5 +26,11 @@ class Version206 extends Migrator
$table = $this->table('config');
$table->insert($rows)->saveData();
}
$crudLog = $this->table('crud_log');
if (!$crudLog->hasColumn('connection')) {
$crudLog->addColumn('connection', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据库连接配置标识', 'null' => false, 'after' => 'status']);
$crudLog->save();
}
}
}

View File

@ -15,13 +15,6 @@ export function generate(data: anyObj) {
)
}
export function getDatabaseList() {
return createAxios({
url: url + 'databaseList',
method: 'get',
})
}
export function getFileData(table: string, commonModel = 0) {
return createAxios({
url: url + 'getFileData',
@ -46,15 +39,11 @@ export function generateCheck(data: anyObj) {
)
}
export function parseFieldData(type: string, table = '', sql = '') {
export function parseFieldData(data: anyObj) {
return createAxios({
url: url + 'parseFieldData',
method: 'post',
data: {
type: type,
table: table,
sql: sql,
},
data: data,
})
}
@ -78,12 +67,13 @@ export function postDel(id: number) {
})
}
export function checkCrudLog(table: string) {
export function checkCrudLog(table: string, connection: string) {
return createAxios({
url: url + 'checkCrudLog',
method: 'get',
params: {
table: table,
connection: connection,
},
})
}

View File

@ -71,6 +71,10 @@ export default {
'Generated Validator Location': 'Generated Validator Location',
'Common model': 'Common model',
'WEB end view directory': 'WEB end view directory',
'Database connection': 'Database connection',
'Database connection help': 'You can configure multiple database connections in config/database.php and select it here',
'Check model class': "Check whether protected $connection = '{connection}'; is configured in the above data model class",
'There is no connection attribute in model class': 'If no configuration is available, you can configure it manually',
'Advanced Configuration': 'Advanced Configuration',
'Common Fields': 'Common Fields',
'Base Fields': 'Base Fields',

View File

@ -69,6 +69,10 @@ export default {
'Generated Data Model Location': '生成的数据模型位置',
'Generated Validator Location': '生成的验证器位置',
'WEB end view directory': 'WEB端视图目录',
'Database connection': '数据库连接配置标识',
'Database connection help': '您可以在 config/database.php 内配置多个数据库连接,然后在此处选择它',
'Check model class': "请检查以上数据模型类中是否已经配置 protected $connection = '{connection}';",
'There is no connection attribute in model class': '未配置请手动配置。',
'Common model': '公共模型',
'Advanced Configuration': '高级配置',
'Common Fields': '常用字段',

View File

@ -138,6 +138,20 @@
labelWidth: 140,
}"
/>
<FormItem
:label="t('crud.crud.Database connection')"
v-model="state.table.databaseConnection"
type="remoteSelect"
:attr="{
labelWidth: 140,
blockHelp: t('crud.crud.Database connection help'),
}"
:input-attr="{
pk: 'key',
field: 'key',
'remote-url': getDatabaseConnectionListUrl,
}"
/>
</div>
</div>
</transition>
@ -418,15 +432,31 @@
v-if="state.remoteSelectPre.index != -1 && state.fields[state.remoteSelectPre.index]"
>
<FormItem
prop="table"
type="select"
:label="t('crud.crud.Associated Data Table')"
v-model="state.remoteSelectPre.form.table"
:key="JSON.stringify(state.remoteSelectPre.dbList)"
:data="{
content: state.remoteSelectPre.dbList,
type="remoteSelect"
:key="state.table.databaseConnection"
:input-attr="{
pk: 'table',
field: 'comment',
params: {
connection: state.table.databaseConnection,
samePrefix: 1,
excludeTable: [
'area',
'token',
'captcha',
'admin_group_access',
'config',
'admin_log',
'user_money_log',
'user_score_log',
],
},
'remote-url': getTableListUrl,
onChange: onJoinTableChange,
}"
:input-attr="{ onChange: onJoinTableChange }"
prop="table"
/>
<div v-loading="state.loading.remoteSelect">
<FormItem
@ -494,6 +524,16 @@
),
}"
/>
<el-form-item
v-if="state.table.databaseConnection && state.remoteSelectPre.form.modelFile"
:label="t('crud.crud.Database connection')"
>
<el-text size="large" type="danger">{{ state.table.databaseConnection }}</el-text>
<div class="block-help">
<div>{{ t('crud.crud.Check model class', { connection: state.table.databaseConnection }) }}</div>
<div>{{ t('crud.crud.There is no connection attribute in model class') }}</div>
</div>
</el-form-item>
<el-form-item :label="t('Reminder')">
<div class="block-help">
{{ t('crud.crud.Design remote select tips') }}
@ -604,8 +644,8 @@ import { useTemplateRefsList } from '@vueuse/core'
import { changeStep, state as crudState, getTableAttr, fieldItem, designTypes, tableFieldsKey } from '/@/views/backend/crud/index'
import { ElNotification, ElMessageBox, ElMessage } from 'element-plus'
import type { FormItemRule, FormInstance, TimelineItemProps, MessageHandler } from 'element-plus'
import { getDatabaseList, getFileData, generateCheck, generate, parseFieldData, postLogStart } from '/@/api/backend/crud'
import { getTableFieldList } from '/@/api/common'
import { getFileData, generateCheck, generate, parseFieldData, postLogStart } from '/@/api/backend/crud'
import { getTableFieldList, getTableListUrl, getDatabaseConnectionListUrl } from '/@/api/common'
import { buildValidatorData, regularVarName } from '/@/utils/validate'
import { getArrayKey } from '/@/utils/common'
import { useI18n } from 'vue-i18n'
@ -635,6 +675,7 @@ const state: {
controllerFile: string
validateFile: string
webViewsDir: string
databaseConnection: string
designChange: TableDesignChange[]
rebuild: string
}
@ -644,7 +685,6 @@ const state: {
remoteSelectPre: {
show: boolean
index: number
dbList: anyObj
fieldList: anyObj
modelFileList: anyObj
controllerFileList: anyObj
@ -692,6 +732,7 @@ const state: {
controllerFile: '',
validateFile: '',
webViewsDir: '',
databaseConnection: '',
designChange: [],
rebuild: 'No',
},
@ -701,7 +742,6 @@ const state: {
remoteSelectPre: {
show: false,
index: -1,
dbList: [],
fieldList: [],
modelFileList: [],
controllerFileList: [],
@ -884,34 +924,30 @@ const showRemoteSelectPre = (index: number, hideDelField = false) => {
state.remoteSelectPre.loading = true
state.remoteSelectPre.index = index
state.remoteSelectPre.hideDelField = hideDelField
getDatabaseList()
.then((res) => {
state.remoteSelectPre.dbList = res.data.dbs
if (state.fields[index] && state.fields[index].form['remote-table'].value) {
state.remoteSelectPre.form.table = state.fields[index].form['remote-table'].value
state.remoteSelectPre.form.pk = state.fields[index].form['remote-pk'].value
state.remoteSelectPre.form.label = state.fields[index].form['remote-field'].value
state.remoteSelectPre.form.controllerFile = state.fields[index].form['remote-controller'].value
state.remoteSelectPre.form.modelFile = state.fields[index].form['remote-model'].value
state.remoteSelectPre.form.joinField = state.fields[index].form['relation-fields'].value.split(',')
getTableFieldList(state.fields[index].form['remote-table'].value).then((res) => {
const fieldSelect: anyObj = {}
for (const key in res.data.fieldList) {
fieldSelect[key] = (key ? key + ' - ' : '') + res.data.fieldList[key]
}
state.remoteSelectPre.fieldList = fieldSelect
})
if (isEmpty(state.remoteSelectPre.modelFileList) || isEmpty(state.remoteSelectPre.controllerFileList)) {
getFileData(state.fields[index].form['remote-table'].value).then((res) => {
state.remoteSelectPre.modelFileList = res.data.modelFileList
state.remoteSelectPre.controllerFileList = res.data.controllerFileList
})
}
if (state.fields[index] && state.fields[index].form['remote-table'].value) {
state.remoteSelectPre.form.table = state.fields[index].form['remote-table'].value
state.remoteSelectPre.form.pk = state.fields[index].form['remote-pk'].value
state.remoteSelectPre.form.label = state.fields[index].form['remote-field'].value
state.remoteSelectPre.form.controllerFile = state.fields[index].form['remote-controller'].value
state.remoteSelectPre.form.modelFile = state.fields[index].form['remote-model'].value
state.remoteSelectPre.form.joinField = state.fields[index].form['relation-fields'].value.split(',')
getTableFieldList(state.fields[index].form['remote-table'].value).then((res) => {
const fieldSelect: anyObj = {}
for (const key in res.data.fieldList) {
fieldSelect[key] = (key ? key + ' - ' : '') + res.data.fieldList[key]
}
state.remoteSelectPre.fieldList = fieldSelect
})
.finally(() => {
state.remoteSelectPre.loading = false
})
if (isEmpty(state.remoteSelectPre.modelFileList) || isEmpty(state.remoteSelectPre.controllerFileList)) {
getFileData(state.fields[index].form['remote-table'].value).then((res) => {
state.remoteSelectPre.modelFileList = res.data.modelFileList
state.remoteSelectPre.controllerFileList = res.data.controllerFileList
})
}
}
state.remoteSelectPre.loading = false
}
const onEditField = (index: number, field: FieldItem) => {
@ -987,6 +1023,7 @@ const onGenerate = () => {
state.loading.generate = true
generateCheck({
table: state.table.name,
connection: state.table.databaseConnection,
controllerFile: state.table.controllerFile,
})
.then(() => {
@ -1112,7 +1149,12 @@ const loadData = () => {
}
// sql
parseFieldData(crudState.type, crudState.startData.db, crudState.startData.sql)
parseFieldData({
type: crudState.type,
table: crudState.startData.table,
sql: crudState.startData.sql,
connection: crudState.startData.databaseConnection,
})
.then((res) => {
let fields = []
for (const key in res.data.columns) {
@ -1134,12 +1176,13 @@ const loadData = () => {
}
state.fields = fields
state.table.comment = res.data.comment
state.table.databaseConnection = crudState.startData.databaseConnection
if (res.data.empty) {
state.table.rebuild = 'Yes'
}
if (crudState.type == 'db' && crudState.startData.db) {
state.table.name = crudState.startData.db
onTableChange(crudState.startData.db)
if (crudState.type == 'db' && crudState.startData.table) {
state.table.name = crudState.startData.table
onTableChange(crudState.startData.table)
}
})
.finally(() => {

View File

@ -27,17 +27,19 @@ export const state: {
step: 'Start' | 'Design'
type: string
startData: {
db: string
sql: string
table: string
logId: string
databaseConnection: string
}
} = reactive({
step: 'Start',
type: '',
startData: {
db: '',
sql: '',
table: '',
logId: '',
databaseConnection: '',
},
})

View File

@ -13,7 +13,15 @@
:buttons="['refresh', 'quickSearch', 'columnDisplay']"
:quick-search-placeholder="t('Quick search placeholder', { fields: t('crud.log.quick Search Fields') })"
/>
<Table ref="tableRef" />
<Table ref="tableRef">
<template #tableName>
<el-table-column :show-overflow-tooltip="true" prop="table_name" align="center" :label="t('crud.log.table_name')">
<template #default="scope">
{{ (scope.row.table.databaseConnection ? scope.row.table.databaseConnection + '.' : '') + scope.row.table.name }}
</template>
</el-table-column>
</template>
</Table>
</el-dialog>
</div>
</template>
@ -105,11 +113,10 @@ const baTable = new baTableClass(
{ label: t('crud.log.id'), prop: 'id', align: 'center', width: 70, operator: '=', operatorPlaceholder: t('Id'), sortable: 'custom' },
{
label: t('crud.log.table_name'),
prop: 'table_name',
align: 'center',
operatorPlaceholder: t('Fuzzy query'),
operator: 'LIKE',
sortable: false,
render: 'slot',
slotName: 'tableName',
},
{
label: t('crud.log.status'),

View File

@ -59,7 +59,7 @@
</el-row>
<el-dialog
class="ba-operate-dialog select-db-dialog"
class="ba-operate-dialog select-table-dialog"
v-model="state.dialog.visible"
:title="state.dialog.type == 'sql' ? t('crud.crud.Please enter SQL') : t('crud.crud.Please select a data table')"
:destroy-on-close="true"
@ -67,7 +67,7 @@
<el-form
:label-width="140"
@keyup.enter="onSubmit()"
class="select-db-form"
class="select-table-form"
ref="formRef"
:model="crudState.startData"
:rules="rules"
@ -87,22 +87,51 @@
</template>
<template v-else-if="state.dialog.type == 'db'">
<FormItem
:label="t('crud.crud.data sheet')"
class="select-db"
v-model="crudState.startData.db"
type="select"
:key="JSON.stringify(state.dialog.dbList)"
:placeholder="t('crud.crud.Please select a data table')"
:data="{
content: state.dialog.dbList,
}"
:label="t('crud.crud.Database connection')"
v-model="crudState.startData.databaseConnection"
type="remoteSelect"
:attr="{
labelWidth: 140,
blockHelp: t('crud.crud.Database connection help'),
}"
:input-attr="{
pk: 'key',
field: 'key',
'remote-url': getDatabaseConnectionListUrl,
onChange: onDatabaseChange,
}"
/>
<FormItem
:label="t('crud.crud.data sheet')"
v-model="crudState.startData.table"
type="remoteSelect"
:key="crudState.startData.databaseConnection"
:placeholder="t('crud.crud.Please select a data table')"
:attr="{
labelWidth: 140,
blockHelp: t('crud.crud.data sheet help'),
}"
:input-attr="{
onChange: onDbStartChange,
pk: 'table',
field: 'comment',
params: {
connection: crudState.startData.databaseConnection,
samePrefix: 1,
excludeTable: [
'area',
'token',
'captcha',
'admin_group_access',
'config',
'admin_log',
'user_money_log',
'user_score_log',
],
},
'remote-url': getTableListUrl,
onChange: onTableStartChange,
}"
prop="db"
prop="table"
/>
<el-alert
v-if="state.successRecord"
@ -132,7 +161,7 @@
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { getDatabaseList, checkCrudLog } from '/@/api/backend/crud'
import { checkCrudLog } from '/@/api/backend/crud'
import FormItem from '/@/components/formItem/index.vue'
import { changeStep, state as crudState } from '/@/views/backend/crud/index'
import { ElNotification } from 'element-plus'
@ -140,6 +169,7 @@ import type { FormInstance, FormItemRule } from 'element-plus'
import { buildValidatorData } from '/@/utils/validate'
import CrudLog from '/@/views/backend/crud/log.vue'
import { useI18n } from 'vue-i18n'
import { getDatabaseConnectionListUrl, getTableListUrl } from '/@/api/common'
const { t } = useI18n()
const sqlInputRef = ref()
@ -148,7 +178,6 @@ const state = reactive({
dialog: {
type: '',
visible: false,
dbList: [],
},
showLog: false,
loading: false,
@ -164,15 +193,12 @@ const onShowDialog = (type: string) => {
}, 200)
} else if (type == 'db') {
state.successRecord = 0
crudState.startData.db = ''
getDatabaseList().then((res) => {
state.dialog.dbList = res.data.dbs
})
crudState.startData.table = ''
}
}
const rules: Partial<Record<string, FormItemRule[]>> = reactive({
db: [buildValidatorData({ name: 'required', message: t('crud.crud.Please select a data table') })],
table: [buildValidatorData({ name: 'required', message: t('crud.crud.Please select a data table') })],
})
const onSubmit = () => {
@ -191,11 +217,16 @@ const onSubmit = () => {
})
}
const onDbStartChange = () => {
if (crudState.startData.db) {
const onDatabaseChange = () => {
state.successRecord = 0
crudState.startData.table = ''
}
const onTableStartChange = () => {
if (crudState.startData.table) {
// CRUD
state.loading = true
checkCrudLog(crudState.startData.db)
checkCrudLog(crudState.startData.table, crudState.startData.databaseConnection)
.then((res) => {
state.successRecord = res.data.id
})
@ -218,16 +249,17 @@ const isDev = () => {
</script>
<style scoped lang="scss">
:deep(.select-db-dialog) .el-dialog__body {
:deep(.select-table-dialog) .el-dialog__body {
height: unset;
.select-db-form {
.select-table-form {
width: 88%;
padding: 40px 0;
}
.success-record-alert {
width: calc(100% - 140px);
margin-left: 140px;
margin-bottom: 30px;
margin-top: -30px;
margin-top: -10px;
}
}
.crud-title {
@ -264,9 +296,6 @@ const isDev = () => {
.sql-input {
margin: 20px 0;
}
.select-db {
margin: 40px 0;
}
.crud-tips {
margin-top: 60px;
padding: 20px;