@@ -257,6 +348,10 @@
+ 查询结果
+
+
+
请连接数据库并执行查询以查看结果
@@ -337,6 +432,82 @@
+
+
表设计器
+
+
+
+
+
+
+
+ 基本信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 列定义
+
+
+
+
+
+
+
+ 索引
+
+
+
+
+
+
+ 约束
+
+
+
+
+
+
+
+
+事件日志
@@ -361,14 +532,57 @@
}
});
} else {
- // 开发环境模拟
+ // 开发环境模拟 - 更新模拟数据以匹配新的Java结构
console.log("Java Request:", request);
- // 模拟错误/成功
setTimeout(() => {
if (request.type === 'createLocalDatabase') {
callback({status:'success', connectionId:'mock_conn_' + Date.now(), database: request.dbName, driver: request.driver}, null);
} else if (request.type === 'connectDatabase') {
callback({status:'success', connectionId:'mock_conn_' + Date.now(), database: request.database, driver: request.driver}, null);
+ } else if (request.type === 'getTables') {
+ callback({status:'success', tables:[
+ {name:'users', type:'TABLE', rows:5},
+ {name:'products', type:'TABLE', rows:12},
+ {name:'orders', type:'TABLE', rows:8}
+ ]}, null);
+ } else if (request.type === 'getTableData') {
+ callback({status:'success', columns:['id','name','email','created_at'], data:[
+ {id:1, name:'张三', email:'zhang@example.com', created_at:'2023-01-15'},
+ {id:2, name:'李四', email:'li@example.com', created_at:'2023-02-20'},
+ {id:3, name:'王五', email:'wang@example.com', created_at:'2023-03-10'}
+ ], total:3, offset:0, limit:50}, null);
+ } else if (request.type === 'insertRow') {
+ callback({status:'success', message:'插入成功', newId: Math.floor(Math.random()*1000)+3}, null);
+ } else if (request.type === 'updateRow') {
+ callback({status:'success', message:'更新成功'}, null);
+ } else if (request.type === 'deleteRow') {
+ callback({status:'success', message:'删除成功'}, null);
+ } else if (request.type === 'createTable') {
+ callback({status:'success', message:'表创建成功'}, null);
+ } else if (request.type === 'alterTable') {
+ callback({status:'success', message:'表结构修改成功'}, null);
+ } else if (request.type === 'getTableStructure') {
+ // 更新模拟数据以匹配新的Java结构
+ callback({status:'success',
+ tableName: request.tableName,
+ engine: 'InnoDB',
+ charset: 'utf8mb4',
+ collation: 'utf8mb4_unicode_ci',
+ comment: '用户表',
+ columns: [
+ {name: 'id', type: 'INT', size: 11, nullable: false, defaultValue: null, autoIncrement: true},
+ {name: 'name', type: 'VARCHAR(255)', size: 255, nullable: false, defaultValue: null, autoIncrement: false},
+ {name: 'email', type: 'VARCHAR(255)', size: 255, nullable: false, defaultValue: null, autoIncrement: false},
+ {name: 'created_at', type: 'DATETIME', size: null, nullable: true, defaultValue: 'CURRENT_TIMESTAMP', autoIncrement: false}
+ ],
+ indexes: [
+ {name: 'idx_email', type: 'UNIQUE', columns: 'email'},
+ {name: 'idx_name', type: 'INDEX', columns: 'name'}
+ ],
+ constraints: [
+ {name: 'PRIMARY', type: 'PRIMARY KEY', definition: 'PRIMARY KEY (id)'}
+ ]
+ }, null);
} else {
callback({status:'success', message:'模拟响应'}, null);
}
@@ -412,6 +626,11 @@
}
})();
+ // 绑定工具面板切换
+ document.getElementById('toolsToggle').addEventListener('click', () => {
+ document.getElementById('toolsPanel').classList.toggle('active');
+ });
+
// 绑定打开连接对话框
document.getElementById('openConnect').addEventListener('click', () => {
showModal('connectionDialog');
@@ -507,6 +726,7 @@
function onConnected(connectionId, database, driver){
window.isConnected = true;
window.currentConnectionId = connectionId;
+ window.currentDatabase = database;
// 更新数据库列表(这是简化示例:仅显示当前)
const dbList = document.getElementById('databaseList');
dbList.innerHTML = `${database}
${driver}
数据库中没有表
';
return;
}
+
+ // 存储所有表数据用于搜索
+ window.allTables = tables;
+
tables.forEach(t => {
const item = document.createElement('div');
item.className = 'table-item';
item.innerHTML = `${t.name}
${t.type} • ${t.rows} 行
-
-
-
`;
+
+
+
+
+
`;
list.appendChild(item);
});
@@ -562,6 +787,38 @@
showTableStructure(table);
});
});
+ list.querySelectorAll('button[data-action="design"]').forEach(b=>{
+ b.addEventListener('click',(e)=>{
+ e.stopPropagation();
+ const table = b.dataset.table;
+ openTableDesigner(table);
+ });
+ });
+
+ // 应用搜索过滤
+ applyTableSearch();
+ }
+
+ // 表搜索功能
+ document.getElementById('tableSearch').addEventListener('input', applyTableSearch);
+
+ function applyTableSearch() {
+ const searchTerm = document.getElementById('tableSearch').value.toLowerCase();
+ const tableItems = document.querySelectorAll('.table-item');
+ let visibleCount = 0;
+
+ tableItems.forEach(item => {
+ const tableName = item.querySelector('.name').textContent.toLowerCase();
+ if (tableName.includes(searchTerm)) {
+ item.style.display = 'flex';
+ visibleCount++;
+ } else {
+ item.style.display = 'none';
+ }
+ });
+
+ document.getElementById('tableSearchResults').textContent =
+ searchTerm ? `找到 ${visibleCount} 个表` : '';
}
// 加载表数据
@@ -587,23 +844,599 @@
content.innerHTML = `没有数据
`;
return;
}
- let html = '| ${c} | `); - html += '|
|---|---|
| 操作 | |
| ${v === null || v === undefined ? 'NULL' : escapeHtml(String(v))} | `; }); + html += `+ + + | `; html += '
+
+`;
+
+ columnsList.insertAdjacentHTML('beforeend', columnHtml);
+
+ // 绑定事件
+ const columnElement = document.getElementById(columnId);
+ columnElement.querySelector('.remove-column').addEventListener('click', () => {
+ columnElement.remove();
+ });
+
+ columnElement.querySelector('.move-up').addEventListener('click', () => {
+ const prev = columnElement.previousElementSibling;
+ if (prev) {
+ columnsList.insertBefore(columnElement, prev);
+ }
+ });
+
+ columnElement.querySelector('.move-down').addEventListener('click', () => {
+ const next = columnElement.nextElementSibling;
+ if (next) {
+ columnsList.insertBefore(next, columnElement);
+ }
+ });
+ }
+
+ // 添加索引行
+ function addIndexRow(indexData = null) {
+ const indexesList = document.getElementById('indexesList');
+ const indexId = 'index_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
+
+ const indexHtml = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ indexesList.insertAdjacentHTML('beforeend', indexHtml);
+
+ // 绑定事件
+ const indexElement = document.getElementById(indexId);
+ indexElement.querySelector('.remove-index').addEventListener('click', () => {
+ indexElement.remove();
+ });
+ }
+
+ // 添加约束行
+ function addConstraintRow(constraintData = null) {
+ const constraintsList = document.getElementById('constraintsList');
+ const constraintId = 'constraint_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
+
+ const constraintHtml = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ constraintsList.insertAdjacentHTML('beforeend', constraintHtml);
+
+ // 绑定事件
+ const constraintElement = document.getElementById(constraintId);
+ constraintElement.querySelector('.remove-constraint').addEventListener('click', () => {
+ constraintElement.remove();
+ });
+ }
+
+ // 填充表设计器 - 修改:根据新的Java数据结构处理所有字段
+ function populateTableDesigner(tableStructure) {
+ // 设置表基本信息 - 处理可能的JSONObject.NULL值
+ document.getElementById('tableName').value = tableStructure.tableName || '';
+ document.getElementById('tableEngine').value = (tableStructure.engine && tableStructure.engine !== null && tableStructure.engine !== 'null') ? tableStructure.engine : 'InnoDB';
+ document.getElementById('tableCharset').value = (tableStructure.charset && tableStructure.charset !== null && tableStructure.charset !== 'null') ? tableStructure.charset : 'utf8mb4';
+ document.getElementById('tableCollation').value = (tableStructure.collation && tableStructure.collation !== null && tableStructure.collation !== 'null') ? tableStructure.collation : 'utf8mb4_unicode_ci';
+ document.getElementById('tableComment').value = (tableStructure.comment && tableStructure.comment !== null && tableStructure.comment !== 'null') ? tableStructure.comment : '';
+
+ // 清空列列表
+ document.getElementById('columnsList').innerHTML = '';
+ document.getElementById('indexesList').innerHTML = '';
+ document.getElementById('constraintsList').innerHTML = '';
+
+ // 添加列
+ if (tableStructure.columns && tableStructure.columns.length > 0) {
+ tableStructure.columns.forEach(column => {
+ addColumnRow(column);
+ });
+ } else {
+ addColumnRow();
+ }
+
+ // 添加索引
+ if (tableStructure.indexes && tableStructure.indexes.length > 0) {
+ tableStructure.indexes.forEach(index => {
+ addIndexRow(index);
+ });
+ }
+
+ // 添加约束
+ if (tableStructure.constraints && tableStructure.constraints.length > 0) {
+ tableStructure.constraints.forEach(constraint => {
+ addConstraintRow(constraint);
+ });
+ }
+ }
+
+ // 保存表设计
+ function saveTableDesign(existingTableName) {
+ const tableName = document.getElementById('tableName').value.trim();
+ if (!tableName) {
+ alert('请输入表名');
+ return;
+ }
+
+ // 收集列信息
+ const columns = [];
+ const columnElements = document.querySelectorAll('.column-item');
+
+ columnElements.forEach(colElement => {
+ const name = colElement.querySelector('.column-name').value.trim();
+ const type = colElement.querySelector('.column-type').value;
+ const attributes = colElement.querySelector('.column-attributes').value;
+
+ if (name) {
+ columns.push({
+ name: name,
+ type: type,
+ attributes: attributes
+ });
+ }
+ });
+
+ if (columns.length === 0) {
+ alert('请至少定义一个列');
+ return;
+ }
+
+ // 收集索引信息
+ const indexes = [];
+ const indexElements = document.querySelectorAll('.index-item');
+
+ indexElements.forEach(indexElement => {
+ const name = indexElement.querySelector('.index-name').value.trim();
+ const type = indexElement.querySelector('.index-type').value;
+ const columns = indexElement.querySelector('.index-columns').value.trim();
+
+ if (name && columns) {
+ indexes.push({
+ name: name,
+ type: type,
+ columns: columns
+ });
+ }
+ });
+
+ // 收集约束信息
+ const constraints = [];
+ const constraintElements = document.querySelectorAll('.constraint-item');
+
+ constraintElements.forEach(constraintElement => {
+ const name = constraintElement.querySelector('.constraint-name').value.trim();
+ const type = constraintElement.querySelector('.constraint-type').value;
+ const definition = constraintElement.querySelector('.constraint-definition').value.trim();
+
+ if (name && definition) {
+ constraints.push({
+ name: name,
+ type: type,
+ definition: definition
+ });
+ }
+ });
+
+ // 收集表选项
+ const tableOptions = {
+ engine: document.getElementById('tableEngine').value,
+ charset: document.getElementById('tableCharset').value,
+ collation: document.getElementById('tableCollation').value,
+ comment: document.getElementById('tableComment').value
+ };
+
+ setStatus(existingTableName ? `正在修改表 ${tableName}...` : `正在创建表 ${tableName}...`);
+
+ JavaBridge.sendRequest({
+ type: existingTableName ? 'alterTable' : 'createTable',
+ connectionId: window.currentConnectionId,
+ tableName: existingTableName || tableName,
+ newTableName: existingTableName ? tableName : null,
+ columns: columns,
+ indexes: indexes,
+ constraints: constraints,
+ tableOptions: tableOptions
+ }, (resp, err) => {
+ if (err) {
+ setStatus('操作失败');
+ alert('操作失败: ' + err.message);
+ return;
+ }
+ if (resp && resp.status === 'success') {
+ setStatus('操作成功');
+ addEventLog(existingTableName ? '修改表' : '创建表',
+ existingTableName ? `表 ${existingTableName} 已更新为 ${tableName}` : `表 ${tableName} 已创建`);
+ hideModal('tableDesignerModal');
+ // 刷新表列表
+ loadTables();
+ } else {
+ setStatus('操作失败');
+ alert('操作失败: ' + (resp && resp.message || '未知错误'));
+ }
+ });
+ }
+
+ // 查看表结构 - 修改:显示更详细的结构信息
function showTableStructure(tableName){
if(!window.currentConnectionId) return alert('未连接数据库');
setStatus('查询表结构...');
@@ -618,16 +1451,100 @@
}
function renderStructureHtml(resp){
- let html = `
+
+
+
+
+
+
+
+
+
+
+
+ 表名: ${escapeHtml(resp.tableName || '')}
`;
+ let html = `
+
`;
+
if(resp.columns && resp.columns.length>0){
- html += '表名: ${escapeHtml(resp.tableName || '')}
+ 引擎: ${escapeHtml(resp.engine || '')}
+ 字符集: ${escapeHtml(resp.charset || '')}
+ 排序规则: ${escapeHtml(resp.collation || '')}
+ 注释: ${escapeHtml(resp.comment || '')}
+ | 列名 | 类型 | 大小 | 可空 | 默认值 |
|---|
| 列名 | 类型 | 大小 | 可空 | 默认值 | 自增 |
|---|---|---|---|---|---|
| ${escapeHtml(c.name)} | ${escapeHtml(c.type)} | ${c.size||''} | ${c.nullable ? '是' : '否'} | ${escapeHtml(c.defaultValue||'')} | |
| ${escapeHtml(c.name)} | +${escapeHtml(c.type)} | +${c.size||''} | +${c.nullable ? '是' : '否'} | +${escapeHtml(c.defaultValue||'')} | +${c.autoIncrement ? '是' : '否'} | +
没有列信息
`;
}
+
+ if(resp.indexes && resp.indexes.length>0){
+ html += '索引信息
'; + html += '| 索引名 | 类型 | 列 |
|---|---|---|
| ${escapeHtml(idx.name)} | +${escapeHtml(idx.type)} | +${escapeHtml(idx.columns)} | +
约束信息
'; + html += '| 约束名 | 类型 | 定义 |
|---|---|---|
| ${escapeHtml(con.name)} | +${escapeHtml(con.type)} | +${escapeHtml(con.definition)} | +
无效的ER数据
';
+ }
+
+ let html = '';
+
+ erData.tables.forEach(table => {
+ html += `
+
';
return html;
}
@@ -636,6 +1553,9 @@
btn.addEventListener('click', ()=>{
const action = btn.dataset.action;
switch(action){
+ case 'tableDesigner':
+ openTableDesigner();
+ break;
case 'queryAnalyzer':
openToolModal('查询分析器', `
+
+ `;
+ });
+
+ html += '
+ ${escapeHtml(table.name)}
+
+
+ `;
+
+ if(table.columns && Array.isArray(table.columns)) {
+ table.columns.forEach(column => {
+ const type = column.type || 'VARCHAR';
+ const size = column.size ? `(${column.size})` : '';
+ const nullable = column.nullable ? 'NULL' : 'NOT NULL';
+
+ html += `
+
+
+ ${escapeHtml(column.name)}
+
+ ${type}${size} ${nullable} +
+ `;
+ });
+ }
+
+ html += `
+ + ${type}${size} ${nullable} +
查询分析器(本地模拟)
`);
// 绑定分析按钮
@@ -679,7 +1599,7 @@
setTimeout(()=>document.getElementById('genEr').addEventListener('click', ()=>{
JavaBridge.sendRequest({type:'generateEr', connectionId: window.currentConnectionId}, (resp,err)=>{
if(err) return alert('生成失败: '+err.message);
- openToolModal('ER 图', `${escapeHtml(JSON.stringify(resp))}
`);
+ openToolModal('ER 图', renderErDiagram(resp.er));
});
}),60);
break;
@@ -704,9 +1624,31 @@
default:
alert('未实现的工具: ' + action);
}
+ // 关闭工具面板
+ document.getElementById('toolsPanel').classList.remove('active');
});
});
+ // 绑定添加列按钮
+ document.getElementById('addColumnBtn').addEventListener('click', () => {
+ addColumnRow();
+ });
+
+ // 绑定添加索引按钮
+ document.getElementById('addIndexBtn').addEventListener('click', () => {
+ addIndexRow();
+ });
+
+ // 绑定添加约束按钮
+ document.getElementById('addConstraintBtn').addEventListener('click', () => {
+ addConstraintRow();
+ });
+
+ // 快速创建表按钮
+ document.getElementById('quickCreateTableBtn').addEventListener('click', () => {
+ openTableDesigner();
+ });
+
function openToolModal(title, bodyHtml){
document.getElementById('toolModalTitle').textContent = title;
document.getElementById('toolModalBody').innerHTML = bodyHtml;
@@ -773,6 +1715,60 @@
return String(str).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"');
}
+ // 搜索功能实现
+ document.addEventListener('keydown', (e) => {
+ // Ctrl+F 在结果区域搜索
+ if (e.ctrlKey && e.key === 'f') {
+ e.preventDefault();
+ const searchBox = document.getElementById('resultsSearchBox');
+ const searchInput = document.getElementById('resultsSearchInput');
+
+ if (searchBox.style.display === 'none') {
+ searchBox.style.display = 'block';
+ searchInput.focus();
+ } else {
+ searchBox.style.display = 'none';
+ }
+ }
+ });
+
+ // 结果搜索功能
+ document.getElementById('resultsSearchInput').addEventListener('input', function() {
+ const searchTerm = this.value.toLowerCase();
+ const table = document.querySelector('.results-content table');
+
+ if (!table) return;
+
+ const rows = table.querySelectorAll('tbody tr');
+ let matchCount = 0;
+
+ rows.forEach(row => {
+ const text = row.textContent.toLowerCase();
+ if (text.includes(searchTerm)) {
+ row.style.display = '';
+ matchCount++;
+
+ // 高亮匹配的文本
+ if (searchTerm) {
+ const cells = row.querySelectorAll('td');
+ cells.forEach(cell => {
+ const originalText = cell.textContent;
+ const highlightedText = originalText.replace(
+ new RegExp(searchTerm, 'gi'),
+ match => `${match}`
+ );
+ cell.innerHTML = highlightedText;
+ });
+ }
+ } else {
+ row.style.display = 'none';
+ }
+ });
+
+ document.getElementById('resultsSearchInfo').textContent =
+ searchTerm ? `找到 ${matchCount} 个匹配项` : '';
+ });
+
// 初始化(模拟触发字体加载回调)
document.addEventListener('DOMContentLoaded', ()=>{
// 初始化 localDbPath
@@ -790,4 +1786,4 @@
});
-