chengjie vor 6 Monaten
Ursprung
Commit
65a66df03d
1 geänderte Dateien mit 200 neuen und 10 gelöschten Zeilen
  1. 200 10
      public/mg/kylx365_db_admin.html

+ 200 - 10
public/mg/kylx365_db_admin.html

@@ -78,11 +78,12 @@
78 78
         }
79 79
 
80 80
         .search-box {
81
-            padding: 15px;
81
+            padding: 15px 0;
82 82
             border-bottom: 1px solid #EEEEEE;
83 83
             background: white;
84 84
             width: 100%;
85 85
             justify-content: center;
86
+            width: 100%;
86 87
         }
87 88
 
88 89
         .search-input {
@@ -590,7 +591,7 @@
590 591
                 </div>
591 592
                 <div class="search-box FlexRow">
592 593
                     <div style="position: relative;">
593
-                        <input type="text" class="search-input" v-model="searchText" @keyup.enter="searchTables"
594
+                        <input type="text" class="search-input" v-model="searchText" @input="searchTables" @keyup.enter="searchTables"
594 595
                             placeholder="搜索表格...">
595 596
                         <div class="clear-btn" v-show="searchText" @click="clearSearch">
596 597
                             <span class="clear-x"></span>
@@ -630,15 +631,20 @@
630 631
                     <!-- 左侧SQL编辑区域 -->
631 632
                     <div class="sql-editor-left">
632 633
                         <textarea class="sql-textarea" v-model="sqlQuery" placeholder="输入SQL查询语句..."></textarea>
633
-                        <div class="btn-group">
634
+                        <div class="btn-group" style="justify-content: flex-start;">
635
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('GROUP BY')">GROUP BY</button>
636
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('HAVING')">HAVING</button>
637
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('ORDER BY')">ORDER BY</button>
634 638
                             <select class="btn btn-default" v-model="selectedLimit" @change="updateQueryLimit"
635
-                                style="margin-right: 8px;">
639
+                                style="margin-left: 8px;">
636 640
                                 <option v-for="limit in limitOptions" :key="limit" :value="limit">
637 641
                                     LIMIT {{ limit }}
638 642
                                 </option>
639 643
                             </select>
640
-                            <button type="button" class="btn btn-default" @click="clearQuery">清空</button>
641
-                            <button type="button" class="btn btn-primary" @click="executeQuery">执行</button>
644
+                            <div style="margin-left: auto;">
645
+                                <button type="button" class="btn btn-default" @click="clearQuery">清空</button>
646
+                                <button type="button" class="btn btn-primary" @click="executeQuery">执行</button>
647
+                            </div>
642 648
                         </div>
643 649
                     </div>
644 650
 
@@ -932,6 +938,9 @@
932 938
                 selectTable(table) {
933 939
                     this.selectedTable = table;
934 940
                     
941
+                    // 重置LIMIT值为默认的100
942
+                    this.selectedLimit = 100;
943
+                    
935 944
                     // 获取表格字段列表
936 945
                     this.loadTableColumns(table);
937 946
                     
@@ -939,9 +948,9 @@
939 948
                     this.$watch('tableColumnsList', (newVal) => {
940 949
                         if (newVal && newVal.length > 0) {
941 950
                             const columns = newVal.map(col => `\`${col.name}\``).join(',');
942
-                            this.sqlQuery = `SELECT ${columns} FROM \`${table}\` LIMIT 100;`;
951
+                            this.sqlQuery = `SELECT ${columns}\nFROM \`${table}\`\nLIMIT ${this.selectedLimit};`;
943 952
                         } else {
944
-                            this.sqlQuery = `SELECT * FROM \`${table}\` LIMIT 100;`;
953
+                            this.sqlQuery = `SELECT *\nFROM \`${table}\`\nLIMIT ${this.selectedLimit};`;
945 954
                         }
946 955
                     }, {immediate: true});
947 956
                 },
@@ -1173,10 +1182,10 @@
1173 1182
                         // 检查SQL是否以分号结尾
1174 1183
                         if (this.sqlQuery.trim().endsWith(';')) {
1175 1184
                             // 在分号前添加LIMIT
1176
-                            this.sqlQuery = this.sqlQuery.replace(/;\s*$/, ` LIMIT ${this.selectedLimit};`);
1185
+                            this.sqlQuery = this.sqlQuery.replace(/;\s*$/, `\nLIMIT ${this.selectedLimit};`);
1177 1186
                         } else {
1178 1187
                             // 直接在末尾添加LIMIT
1179
-                            this.sqlQuery = this.sqlQuery.trim() + ` LIMIT ${this.selectedLimit};`;
1188
+                            this.sqlQuery = this.sqlQuery.trim() + `\nLIMIT ${this.selectedLimit};`;
1180 1189
                         }
1181 1190
                     }
1182 1191
 
@@ -1443,6 +1452,187 @@
1443 1452
                     });
1444 1453
                 },
1445 1454
                 
1455
+                // 插入SQL子句(ORDER BY, GROUP BY, HAVING等)
1456
+                insertSqlClause(clause) {
1457
+                    // 检查SQL查询是否为空
1458
+                    if (!this.sqlQuery.trim()) {
1459
+                        this.sqlQuery = clause + ' ';
1460
+                        return;
1461
+                    }
1462
+                    
1463
+                    // 检查子句是否已存在(不区分大小写)
1464
+                    const sqlUpper = this.sqlQuery.toUpperCase();
1465
+                    const clauseUpper = clause.toUpperCase();
1466
+                    
1467
+                    if (sqlUpper.includes(clauseUpper)) {
1468
+                        this.showToastMessage(`查询中已存在 "${clause}" 子句`, 'info');
1469
+                        return;
1470
+                    }
1471
+                    
1472
+                    // 解析SQL查询,识别各个子句的位置
1473
+                    const sqlParts = {
1474
+                        select: -1,
1475
+                        from: -1,
1476
+                        where: -1,
1477
+                        groupBy: -1,
1478
+                        having: -1,
1479
+                        orderBy: -1,
1480
+                        limit: -1
1481
+                    };
1482
+                    
1483
+                    // 查找各个子句的位置
1484
+                    sqlParts.select = sqlUpper.indexOf('SELECT');
1485
+                    sqlParts.from = sqlUpper.indexOf('FROM', sqlParts.select);
1486
+                    sqlParts.where = sqlUpper.indexOf('WHERE', sqlParts.from);
1487
+                    sqlParts.groupBy = sqlUpper.indexOf('GROUP BY', sqlParts.from);
1488
+                    sqlParts.having = sqlUpper.indexOf('HAVING', sqlParts.from);
1489
+                    sqlParts.orderBy = sqlUpper.indexOf('ORDER BY', sqlParts.from);
1490
+                    
1491
+                    // 查找LIMIT子句(可能在末尾或分号前)
1492
+                    const limitMatch = sqlUpper.match(/LIMIT\s+\d+/i);
1493
+                    if (limitMatch) {
1494
+                        sqlParts.limit = limitMatch.index;
1495
+                    }
1496
+                    
1497
+                    // 确定插入位置
1498
+                    let insertPosition = -1;
1499
+                    let insertBefore = '';
1500
+                    
1501
+                    switch (clauseUpper) {
1502
+                        case 'GROUP BY':
1503
+                            // GROUP BY应该在WHERE之后,HAVING/ORDER BY/LIMIT之前
1504
+                            if (sqlParts.where > -1) {
1505
+                                // 找到WHERE子句后的位置
1506
+                                const whereEndPos = this.findClauseEndPosition(sqlUpper, sqlParts.where);
1507
+                                insertPosition = whereEndPos;
1508
+                            } else if (sqlParts.having > -1) {
1509
+                                // 如果没有WHERE但有HAVING,插入在HAVING之前
1510
+                                insertPosition = sqlParts.having;
1511
+                                insertBefore = 'HAVING';
1512
+                            } else if (sqlParts.orderBy > -1) {
1513
+                                // 如果没有WHERE和HAVING但有ORDER BY,插入在ORDER BY之前
1514
+                                insertPosition = sqlParts.orderBy;
1515
+                                insertBefore = 'ORDER BY';
1516
+                            } else if (sqlParts.limit > -1) {
1517
+                                // 如果只有LIMIT,插入在LIMIT之前
1518
+                                insertPosition = sqlParts.limit;
1519
+                                insertBefore = 'LIMIT';
1520
+                            } else {
1521
+                                // 如果没有以上子句,插入在查询末尾(可能有分号)
1522
+                                insertPosition = this.sqlQuery.length;
1523
+                                if (this.sqlQuery.trim().endsWith(';')) {
1524
+                                    insertPosition = this.sqlQuery.lastIndexOf(';');
1525
+                                }
1526
+                            }
1527
+                            break;
1528
+                            
1529
+                        case 'HAVING':
1530
+                            // HAVING应该在GROUP BY之后,ORDER BY/LIMIT之前
1531
+                            if (sqlParts.groupBy > -1) {
1532
+                                // 找到GROUP BY子句后的位置
1533
+                                const groupByEndPos = this.findClauseEndPosition(sqlUpper, sqlParts.groupBy);
1534
+                                insertPosition = groupByEndPos;
1535
+                            } else if (sqlParts.orderBy > -1) {
1536
+                                // 如果没有GROUP BY但有ORDER BY,插入在ORDER BY之前
1537
+                                insertPosition = sqlParts.orderBy;
1538
+                                insertBefore = 'ORDER BY';
1539
+                            } else if (sqlParts.limit > -1) {
1540
+                                // 如果只有LIMIT,插入在LIMIT之前
1541
+                                insertPosition = sqlParts.limit;
1542
+                                insertBefore = 'LIMIT';
1543
+                            } else {
1544
+                                // 如果没有以上子句,插入在查询末尾(可能有分号)
1545
+                                insertPosition = this.sqlQuery.length;
1546
+                                if (this.sqlQuery.trim().endsWith(';')) {
1547
+                                    insertPosition = this.sqlQuery.lastIndexOf(';');
1548
+                                }
1549
+                            }
1550
+                            break;
1551
+                            
1552
+                        case 'ORDER BY':
1553
+                            // ORDER BY应该在GROUP BY和HAVING之后,LIMIT之前
1554
+                            if (sqlParts.having > -1) {
1555
+                                // 找到HAVING子句后的位置
1556
+                                const havingEndPos = this.findClauseEndPosition(sqlUpper, sqlParts.having);
1557
+                                insertPosition = havingEndPos;
1558
+                            } else if (sqlParts.groupBy > -1) {
1559
+                                // 如果没有HAVING但有GROUP BY,找到GROUP BY子句后的位置
1560
+                                const groupByEndPos = this.findClauseEndPosition(sqlUpper, sqlParts.groupBy);
1561
+                                insertPosition = groupByEndPos;
1562
+                            } else if (sqlParts.limit > -1) {
1563
+                                // 如果只有LIMIT,插入在LIMIT之前
1564
+                                insertPosition = sqlParts.limit;
1565
+                                insertBefore = 'LIMIT';
1566
+                            } else {
1567
+                                // 如果没有以上子句,插入在查询末尾(可能有分号)
1568
+                                insertPosition = this.sqlQuery.length;
1569
+                                if (this.sqlQuery.trim().endsWith(';')) {
1570
+                                    insertPosition = this.sqlQuery.lastIndexOf(';');
1571
+                                }
1572
+                            }
1573
+                            break;
1574
+                    }
1575
+                    
1576
+                    // 执行插入
1577
+                    if (insertPosition > -1) {
1578
+                        let newQuery = '';
1579
+                        if (insertBefore) {
1580
+                            // 在特定子句之前插入
1581
+                            const beforeInsert = this.sqlQuery.substring(0, insertPosition);
1582
+                            const afterInsert = this.sqlQuery.substring(insertPosition);
1583
+                            
1584
+                            // 添加换行符和子句
1585
+                            newQuery = beforeInsert + '\n' + clause + ' ' + afterInsert;
1586
+                        } else {
1587
+                            // 在子句末尾插入
1588
+                            const beforeInsert = this.sqlQuery.substring(0, insertPosition);
1589
+                            const afterInsert = this.sqlQuery.substring(insertPosition);
1590
+                            
1591
+                            // 添加换行符和子句
1592
+                            newQuery = beforeInsert + '\n' + clause + ' ' + afterInsert;
1593
+                        }
1594
+                        
1595
+                        this.sqlQuery = newQuery;
1596
+                        this.showToastMessage(`已插入 "${clause}" 子句到查询`, 'success');
1597
+                        
1598
+                        // 设置光标位置到插入的子句之后
1599
+                        this.$nextTick(() => {
1600
+                            const textarea = document.querySelector('.sql-textarea');
1601
+                            if (textarea) {
1602
+                                textarea.focus();
1603
+                                const newPosition = insertPosition + clause.length + 1;
1604
+                                textarea.selectionStart = newPosition;
1605
+                                textarea.selectionEnd = newPosition;
1606
+                            }
1607
+                        });
1608
+                    } else {
1609
+                        // 如果无法确定位置,则在末尾添加
1610
+                        if (this.sqlQuery.trim().endsWith(';')) {
1611
+                            this.sqlQuery = this.sqlQuery.replace(/;\s*$/, `\n${clause} ;`);
1612
+                        } else {
1613
+                            this.sqlQuery += `\n${clause} `;
1614
+                        }
1615
+                        this.showToastMessage(`已插入 "${clause}" 子句到查询末尾`, 'info');
1616
+                    }
1617
+                },
1618
+                
1619
+                // 查找子句结束位置的辅助方法
1620
+                findClauseEndPosition(sqlUpper, clauseStartPos) {
1621
+                    // 子句可能的结束标记
1622
+                    const endMarkers = ['GROUP BY', 'HAVING', 'ORDER BY', 'LIMIT', ';'];
1623
+                    let endPos = sqlUpper.length;
1624
+                    
1625
+                    // 查找最近的下一个子句
1626
+                    for (const marker of endMarkers) {
1627
+                        const pos = sqlUpper.indexOf(marker, clauseStartPos + 1);
1628
+                        if (pos > -1 && pos < endPos) {
1629
+                            endPos = pos;
1630
+                        }
1631
+                    }
1632
+                    
1633
+                    return endPos;
1634
+                },
1635
+                
1446 1636
                 // 显示提示消息
1447 1637
                 showToastMessage(message, type = 'info') {
1448 1638
                     this.toastMessage = message;