chengjie месяцев назад: 7
Родитель
Сommit
5056c174c5
1 измененных файлов с 216 добавлено и 9 удалено
  1. 216 9
      public/mg/kylx365_db_admin.html

+ 216 - 9
public/mg/kylx365_db_admin.html

@@ -223,16 +223,21 @@
223
             overflow: auto;
223
             overflow: auto;
224
             padding: 20px;
224
             padding: 20px;
225
             background: white;
225
             background: white;
226
+            position: relative;
226
         }
227
         }
227
 
228
 
228
         .table-container {
229
         .table-container {
229
             width: 100%;
230
             width: 100%;
230
             overflow-x: auto;
231
             overflow-x: auto;
232
+            max-height: calc(100vh - 380px); /* 减去其他元素的高度 */
233
+            overflow-y: auto;
234
+            position: relative; /* 为内部元素提供定位上下文 */
231
         }
235
         }
232
 
236
 
233
         .data-table {
237
         .data-table {
234
             width: 100%;
238
             width: 100%;
235
-            border-collapse: collapse;
239
+            border-collapse: separate; /* 改为separate以支持边框样式 */
240
+            border-spacing: 0; /* 消除单元格间距 */
236
             font-size: 14px;
241
             font-size: 14px;
237
         }
242
         }
238
 
243
 
@@ -244,6 +249,21 @@
244
             position: sticky;
249
             position: sticky;
245
             top: 0;
250
             top: 0;
246
             z-index: 10;
251
             z-index: 10;
252
+            box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
253
+        }
254
+
255
+        /* 确保表头单元格背景色完整覆盖 */
256
+        .data-table thead th {
257
+            background: #F5F5F5;
258
+        }
259
+        
260
+        /* 优化表头在滚动时的视觉效果 */
261
+        .table-container:not(:hover) .data-table th {
262
+            transition: box-shadow 0.3s ease;
263
+        }
264
+        
265
+        .table-container:hover .data-table th {
266
+            box-shadow: 0 3px 5px -2px rgba(0, 0, 0, 0.2);
247
         }
267
         }
248
 
268
 
249
         .data-table td {
269
         .data-table td {
@@ -481,6 +501,77 @@
481
             color: #CCCCCC;
501
             color: #CCCCCC;
482
             cursor: not-allowed;
502
             cursor: not-allowed;
483
         }
503
         }
504
+
505
+        /* 完整内容弹出层样式 - 改进版 */
506
+        .complete-content-overlay {
507
+            position: fixed;
508
+            top: 0;
509
+            left: 0;
510
+            right: 0;
511
+            bottom: 0;
512
+            display: flex;
513
+            justify-content: center;
514
+            align-items: center;
515
+            z-index: 1000;
516
+            background-color: rgba(0, 0, 0, 0.5);
517
+            pointer-events: auto;
518
+        }
519
+        
520
+        .complete-content-container {
521
+            width: 80%;
522
+            max-width: 800px;
523
+            max-height: 80vh;
524
+            background-color: white;
525
+            border-radius: 8px;
526
+            padding: 20px;
527
+            padding-top: 50px; /* 为固定的关闭按钮留出空间 */
528
+            position: relative;
529
+            box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
530
+            overflow: auto;
531
+            animation: fadeIn 0.3s ease-out;
532
+        }
533
+
534
+        @keyframes fadeIn {
535
+            from {
536
+                opacity: 0;
537
+                transform: translateY(20px);
538
+            }
539
+            to {
540
+                opacity: 1;
541
+                transform: translateY(0);
542
+            }
543
+        }
544
+        
545
+        .close-btn {
546
+            position: absolute;
547
+            right: 15px; /* 根据弹窗宽度计算位置 */
548
+            top: 15px; /* 根据弹窗位置计算 */
549
+            z-index: 1010; /* 确保按钮在最上层 */
550
+            width: 40px;
551
+            height: 40px;
552
+            display: flex;
553
+            align-items: center;
554
+            justify-content: center;
555
+            background: rgba(255, 255, 255, 0.9);
556
+            border: none;
557
+            border-radius: 50%;
558
+            font-size: 24px;
559
+            cursor: pointer;
560
+            color: #999;
561
+            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
562
+        }
563
+        
564
+        .close-btn:hover {
565
+            color: #333;
566
+            background: #fff;
567
+        }
568
+        
569
+        .complete-content {
570
+            white-space: pre-wrap;
571
+            word-break: break-word;
572
+            font-family: monospace;
573
+            line-height: 1.5;
574
+        }
484
     </style>
575
     </style>
485
 </head>
576
 </head>
486
 
577
 
@@ -610,7 +701,9 @@
610
                                             :key="'tr-'+rowIndex">
701
                                             :key="'tr-'+rowIndex">
611
                                             <td v-for="(column, colIndex) in tableColumns" 
702
                                             <td v-for="(column, colIndex) in tableColumns" 
612
                                                 :key="'td-'+rowIndex+'-'+colIndex"
703
                                                 :key="'td-'+rowIndex+'-'+colIndex"
613
-                                                v-show="!column.startsWith('__')">
704
+                                                v-show="!column.startsWith('__')"
705
+                                                @dblclick="formatTableCell(row[column]).endsWith('...') ? showCompleteField(row, column) : copyColumnName(formatTableCell(row[column]))"
706
+                                                >
614
                                                 {{ formatTableCell(row[column]) }}
707
                                                 {{ formatTableCell(row[column]) }}
615
                                             </td>
708
                                             </td>
616
                                         </tr>
709
                                         </tr>
@@ -641,6 +734,16 @@
641
 
734
 
642
         <!-- Toast提示 -->
735
         <!-- Toast提示 -->
643
         <div class="toast" :class="{ show: showToast, [toastType]: showToast }">{{ toastMessage }}</div>
736
         <div class="toast" :class="{ show: showToast, [toastType]: showToast }">{{ toastMessage }}</div>
737
+        
738
+        <!-- 完整内容弹出层 -->
739
+        <div v-if="showCompleteContent" class="complete-content-overlay" @click.self="closeCompleteContent">
740
+            <div class="complete-content-container">
741
+                <button class="close-btn" @click="closeCompleteContent">×</button>
742
+                <div class="complete-content" @dblclick="copyToClipboard(completeContent)">
743
+                    {{ completeContent }}
744
+                </div>
745
+            </div>
746
+        </div>
644
     </div>
747
     </div>
645
 
748
 
646
     <script>
749
     <script>
@@ -665,7 +768,11 @@
665
                 allResults: [],
768
                 allResults: [],
666
                 tableColumnsList: [], // 存储表格字段列表
769
                 tableColumnsList: [], // 存储表格字段列表
667
                 limitOptions: [10, 100, 500, 1000, 2000, 3000], // LIMIT选项
770
                 limitOptions: [10, 100, 500, 1000, 2000, 3000], // LIMIT选项
668
-                selectedLimit: 100 // 默认选中的LIMIT值
771
+                selectedLimit: 100, // 默认选中的LIMIT值
772
+                showCompleteContent: false,
773
+                completeContent: '',
774
+                currentRow: null,
775
+                currentColumn: null
669
             },
776
             },
670
             computed: {
777
             computed: {
671
                 
778
                 
@@ -824,10 +931,19 @@
824
                 // 选择表格
931
                 // 选择表格
825
                 selectTable(table) {
932
                 selectTable(table) {
826
                     this.selectedTable = table;
933
                     this.selectedTable = table;
827
-                    this.sqlQuery = `SELECT * FROM ${table} LIMIT 100;`;
828
-
934
+                    
829
                     // 获取表格字段列表
935
                     // 获取表格字段列表
830
                     this.loadTableColumns(table);
936
                     this.loadTableColumns(table);
937
+                    
938
+                    // 监听字段列表变化,当加载完成后构建查询语句
939
+                    this.$watch('tableColumnsList', (newVal) => {
940
+                        if (newVal && newVal.length > 0) {
941
+                            const columns = newVal.map(col => `\`${col.name}\``).join(',');
942
+                            this.sqlQuery = `SELECT ${columns} FROM \`${table}\` LIMIT 100;`;
943
+                        } else {
944
+                            this.sqlQuery = `SELECT * FROM \`${table}\` LIMIT 100;`;
945
+                        }
946
+                    }, {immediate: true});
831
                 },
947
                 },
832
 
948
 
833
                 // 加载表格字段列表
949
                 // 加载表格字段列表
@@ -1009,6 +1125,8 @@
1009
                 insertColumnName(columnName) {
1125
                 insertColumnName(columnName) {
1010
                     // 获取文本框元素
1126
                     // 获取文本框元素
1011
                     const textarea = document.querySelector('.sql-textarea');
1127
                     const textarea = document.querySelector('.sql-textarea');
1128
+                    // 添加反引号的字段名
1129
+                    const quotedColumnName = `\`${columnName}\``;
1012
 
1130
 
1013
                     // 如果文本框存在
1131
                     // 如果文本框存在
1014
                     if (textarea) {
1132
                     if (textarea) {
@@ -1021,19 +1139,19 @@
1021
                         const textAfter = this.sqlQuery.substring(endPos);
1139
                         const textAfter = this.sqlQuery.substring(endPos);
1022
 
1140
 
1023
                         // 更新SQL查询
1141
                         // 更新SQL查询
1024
-                        this.sqlQuery = textBefore + columnName + textAfter;
1142
+                        this.sqlQuery = textBefore + quotedColumnName + textAfter;
1025
 
1143
 
1026
                         // 设置新的光标位置
1144
                         // 设置新的光标位置
1027
                         this.$nextTick(() => {
1145
                         this.$nextTick(() => {
1028
                             textarea.focus();
1146
                             textarea.focus();
1029
-                            textarea.selectionStart = startPos + columnName.length;
1030
-                            textarea.selectionEnd = startPos + columnName.length;
1147
+                            textarea.selectionStart = startPos + quotedColumnName.length;
1148
+                            textarea.selectionEnd = startPos + quotedColumnName.length;
1031
                         });
1149
                         });
1032
 
1150
 
1033
                         this.showToastMessage(`已插入字段 "${columnName}" 到查询`, 'info');
1151
                         this.showToastMessage(`已插入字段 "${columnName}" 到查询`, 'info');
1034
                     } else {
1152
                     } else {
1035
                         // 如果无法获取文本框元素,则直接在末尾添加
1153
                         // 如果无法获取文本框元素,则直接在末尾添加
1036
-                        this.sqlQuery += ' ' + columnName;
1154
+                        this.sqlQuery += ' ' + quotedColumnName;
1037
                     }
1155
                     }
1038
                 },
1156
                 },
1039
 
1157
 
@@ -1236,6 +1354,95 @@
1236
                     return value;
1354
                     return value;
1237
                 },
1355
                 },
1238
 
1356
 
1357
+                // 显示完整字段内容
1358
+                showCompleteField(row, column) {
1359
+                    // 检查当前单元格内容是否有省略
1360
+                    const cellContent = this.formatTableCell(row[column]);
1361
+                    if (!cellContent.includes('...')) {
1362
+                        return;
1363
+                    }
1364
+                    
1365
+                    this.currentRow = row;
1366
+                    this.currentColumn = column;
1367
+                    this.showCompleteContent = true;
1368
+                    this.completeContent = '加载中...';
1369
+                    
1370
+                    // 查找主键字段 - 优先使用实际存在的列名
1371
+                    let primaryKey = null;
1372
+                    
1373
+                    // 检查当前行是否有id字段
1374
+                    if ('id' in row) {
1375
+                        primaryKey = 'id';
1376
+                    } 
1377
+                    // 检查是否有ID字段(大写)
1378
+                    else if ('ID' in row) {
1379
+                        primaryKey = 'ID';
1380
+                    }
1381
+                    // 检查表字段列表中是否有id字段
1382
+                    else if (this.tableColumnsList.some(col => col.name.toLowerCase() === 'id')) {
1383
+                        primaryKey = 'id';
1384
+                    }
1385
+                    // 检查表字段列表中是否有ID字段(大写)
1386
+                    else if (this.tableColumnsList.some(col => col.name === 'ID')) {
1387
+                        primaryKey = 'ID';
1388
+                    }
1389
+                    // 使用第一个存在的字段作为主键
1390
+                    else if (this.tableColumnsList.length > 0) {
1391
+                        const firstCol = this.tableColumnsList[0].name;
1392
+                        if (firstCol in row) {
1393
+                            primaryKey = firstCol;
1394
+                        }
1395
+                    }
1396
+                    
1397
+                    if (!primaryKey || !row[primaryKey]) {
1398
+                        this.completeContent = '无法确定主键字段或主键值为空';
1399
+                        return;
1400
+                    }
1401
+                    
1402
+                    // 构建查询SQL
1403
+                    const sql = `SELECT \`${column}\` FROM \`${this.selectedTable}\` WHERE \`${primaryKey}\`='${row[primaryKey]}';`;
1404
+                    
1405
+                    // 调用API获取完整数据
1406
+                    fetch('/api/RunKylx365DBSql', {
1407
+                        method: 'POST',
1408
+                        headers: {
1409
+                            'Content-Type': 'application/json',
1410
+                        },
1411
+                        body: JSON.stringify({
1412
+                            sql: sql,
1413
+                            IsCompleteField: true
1414
+                        })
1415
+                    })
1416
+                    .then(response => response.json())
1417
+                    .then(data => {
1418
+                        if (data && data.result && data.result.length > 0) {
1419
+                            this.completeContent = this.formatTableCell(data.result[0][column]);
1420
+                        } else {
1421
+                            this.completeContent = '未获取到完整数据';
1422
+                        }
1423
+                    })
1424
+                    .catch(error => {
1425
+                        this.completeContent = '获取完整数据失败: ' + error.message;
1426
+                    });
1427
+                },
1428
+                
1429
+                // 关闭完整内容弹出层
1430
+                closeCompleteContent() {
1431
+                    this.showCompleteContent = false;
1432
+                    this.completeContent = '';
1433
+                    this.currentRow = null;
1434
+                    this.currentColumn = null;
1435
+                },
1436
+                
1437
+                // 复制到剪贴板
1438
+                copyToClipboard(text) {
1439
+                    navigator.clipboard.writeText(text).then(() => {
1440
+                        this.showToastMessage('已复制到剪贴板', 'success');
1441
+                    }).catch(err => {
1442
+                        this.showToastMessage('复制失败: ' + err, 'error');
1443
+                    });
1444
+                },
1445
+                
1239
                 // 显示提示消息
1446
                 // 显示提示消息
1240
                 showToastMessage(message, type = 'info') {
1447
                 showToastMessage(message, type = 'info') {
1241
                     this.toastMessage = message;
1448
                     this.toastMessage = message;