chengjie преди 5 месеца
родител
ревизия
5a319168fe
променени са 5 файла, в които са добавени 158 реда и са изтрити 27 реда
  1. 3 0
      .vscode/settings.json
  2. 25 25
      public/mg/kylx365_db_admin.html
  3. 2 1
      src/api/web/webController.js
  4. 81 0
      src/test/getPublicIP.improved.js
  5. 47 1
      src/test/stringClass.test.js

+ 3 - 0
.vscode/settings.json

@@ -1,4 +1,7 @@
1 1
 {
2
+    "code-runner.executorMap": {
3
+        "javascript": "/Users/chengjie/.nvm/versions/node/v24.1.0/bin/node $fileName"
4
+    },
2 5
     "files.autoSave": "afterDelay",
3 6
     "files.autoSaveDelay": 1000,
4 7
     "code-runner.clearPreviousOutput": true,

+ 25 - 25
public/mg/kylx365_db_admin.html

@@ -4,7 +4,7 @@
4 4
 <head>
5 5
     <meta charset="UTF-8">
6 6
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
7
-    <title>数据库管理</title>
7
+    <title>数据库表查询</title>
8 8
     <script src="https://kylx365-1253256735.file.myqcloud.com/js/jquery-1.10.2.min.js"></script>
9 9
     <script src="https://kylx365-1253256735.file.myqcloud.com/js/vue.min.js"></script>
10 10
     <style>
@@ -586,7 +586,7 @@
586 586
     <div id="app" class="main00 FlexColumn">
587 587
         <div class="ListTop FlexRow">
588 588
             <div class="ListTop3 FlexRow" style="width: 100%; justify-content: space-between;">
589
-                <div class="title">数据库管理</div>
589
+                <div class="title">数据库表查询</div>
590 590
             </div>
591 591
         </div>
592 592
         <div class="main0 FlexRow">
@@ -635,29 +635,8 @@
635 635
                 <!-- SQL编辑器 -->
636 636
                 <div class="sql-editor">
637 637
                     <!-- 左侧SQL编辑区域 -->
638
-                    <div class="sql-editor-left">
639
-                        <textarea class="sql-textarea" v-model="sqlQuery" placeholder="输入SQL查询语句..."></textarea>
640
-                        <div class="btn-group" style="justify-content: flex-start;">
641
-                            <button type="button" class="btn btn-default" @click="insertSqlClause('WHERE')">WHERE</button>
642
-                            <button type="button" class="btn btn-default" @click="insertSqlClause('INNER JOIN ON')" :disabled="!hasWhere">INNER JOIN ON</button>
643
-                            <button type="button" class="btn btn-default" @click="insertSqlClause('GROUP BY')">GROUP BY</button>
644
-                            <button type="button" class="btn btn-default" @click="insertSqlClause('HAVING')" :disabled="!hasGroupBy">HAVING</button>
645
-                            <button type="button" class="btn btn-default" @click="insertSqlClause('ORDER BY')">ORDER BY</button>
646
-                            <select class="btn btn-default" v-model="selectedLimit" @change="updateQueryLimit"
647
-                                style="margin-left: 8px;">
648
-                                <option v-for="limit in limitOptions" :key="limit" :value="limit">
649
-                                    LIMIT {{ limit }}
650
-                                </option>
651
-                            </select>
652
-                            <div style="margin-left: auto;">
653
-                                <button type="button" class="btn btn-default" @click="clearQuery">清空</button>
654
-                                <button type="button" class="btn btn-primary" @click="executeQuery">执行</button>
655
-                            </div>
656
-                        </div>
657
-                    </div>
658
-
659
-                    <!-- 右侧字段列表 -->
660
-                    <div class="sql-editor-right">
638
+                    
639
+<div class="sql-editor-right">
661 640
                         <div v-if="isColumnsLoading" class="loading-overlay">
662 641
                             <div class="loading-spinner"></div>
663 642
                         </div>
@@ -679,6 +658,27 @@
679 658
                             </div>
680 659
                         </div>
681 660
                     </div>
661
+                    <!-- 右侧字段列表 -->
662
+                    <div class="sql-editor-left">
663
+                        <textarea class="sql-textarea" v-model="sqlQuery" placeholder="输入SQL查询语句..."></textarea>
664
+                        <div class="btn-group" style="justify-content: flex-start;">
665
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('WHERE')">WHERE</button>
666
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('INNER JOIN ON')" :disabled="!hasWhere">INNER JOIN ON</button>
667
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('GROUP BY')">GROUP BY</button>
668
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('HAVING')" :disabled="!hasGroupBy">HAVING</button>
669
+                            <button type="button" class="btn btn-default" @click="insertSqlClause('ORDER BY')">ORDER BY</button>
670
+                            <select class="btn btn-default" v-model="selectedLimit" @change="updateQueryLimit"
671
+                                style="margin-left: 8px;">
672
+                                <option v-for="limit in limitOptions" :key="limit" :value="limit">
673
+                                    LIMIT {{ limit }}
674
+                                </option>
675
+                            </select>
676
+                            <div style="margin-left: auto;">
677
+                                <button type="button" class="btn btn-default" @click="clearQuery">清空</button>
678
+                                <button type="button" class="btn btn-primary" @click="executeQuery">执行</button>
679
+                            </div>
680
+                        </div>
681
+                    </div>
682 682
                 </div>
683 683
 
684 684
                 <!-- 查询结果 -->

+ 2 - 1
src/api/web/webController.js

@@ -217,7 +217,8 @@ export async function RunKylx365DBSql(ctx) {
217 217
             SQL: ctx.request.body.sql || "",
218 218
             IsCompleteField:ctx.request.body.IsCompleteField || false,
219 219
         };
220
-        console.log(param.SQL);
220
+        if (process.env.NODE_ENV=='development')
221
+            console.log(param.SQL);
221 222
     
222 223
         // 获取第一个分号前的SQL语句
223 224
         const firstStatement = param.SQL.split(';')[0].trim();

+ 81 - 0
src/test/getPublicIP.improved.js

@@ -0,0 +1,81 @@
1
+'use strict';
2
+import https from 'https';
3
+import commonModel from '../model/commonModel.js';
4
+
5
+// 定义几个可用于获取公网IP的API端点
6
+const publicIPAPIs = [
7
+    { host: 'ifconfig.me', path: '/ip' },         // 只返回IP地址
8
+    { host: 'icanhazip.com', path: '/' },         // 只返回IP地址
9
+    { host: 'ipinfo.io', path: '/ip' },           // 只返回IP地址
10
+    { host: 'api.ipify.org', path: '/?format=text' } // 只返回IP地址
11
+];
12
+
13
+// 使用Promise封装HTTP请求
14
+const getPublicIP = (apiIndex = 0) => {
15
+    return new Promise((resolve, reject) => {
16
+        if (apiIndex >= publicIPAPIs.length) {
17
+            reject(new Error('所有API尝试失败'));
18
+            return;
19
+        }
20
+
21
+        const api = publicIPAPIs[apiIndex];
22
+        console.log(`尝试从 ${api.host}${api.path} 获取公网IP...`);
23
+
24
+        const req = https.get({
25
+            host: api.host,
26
+            path: api.path,
27
+            timeout: 5000, // 5秒超时
28
+            headers: {
29
+                // 添加User-Agent头以避免某些服务拒绝请求
30
+                'User-Agent': 'Mozilla/5.0 Node.js Public IP Checker'
31
+            }
32
+        }, (res) => {
33
+            let data = '';
34
+            
35
+            res.on('data', (chunk) => {
36
+                data += chunk;
37
+            });
38
+            
39
+            res.on('end', () => {
40
+                // 清理返回的数据(去除空格和换行符)
41
+                const ip = data.trim();
42
+                
43
+                // 验证返回的是否是有效的IP地址格式
44
+                const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
45
+                if (ipRegex.test(ip)) {
46
+                    console.log(`从 ${api.host} 获取到的IP: ${ip}`);
47
+                    resolve(ip);
48
+                } else {
49
+                    console.error(`从 ${api.host} 获取的响应不是有效的IP地址格式`);
50
+                    // 尝试下一个API
51
+                    resolve(getPublicIP(apiIndex + 1));
52
+                }
53
+            });
54
+        });
55
+        
56
+        req.on('error', (err) => {
57
+            console.error(`从 ${api.host} 获取IP失败: ${err.message}`);
58
+            // 尝试下一个API
59
+            resolve(getPublicIP(apiIndex + 1));
60
+        });
61
+        
62
+        req.on('timeout', () => {
63
+            console.error(`从 ${api.host} 获取IP超时`);
64
+            req.destroy();
65
+            // 尝试下一个API
66
+            resolve(getPublicIP(apiIndex + 1));
67
+        });
68
+    });
69
+};
70
+
71
+// 执行获取公网IP的操作
72
+console.log('正在获取公网IP地址...');
73
+getPublicIP()
74
+    .then(ip => {
75
+        console.log('\n您的公网IP地址是:', ip);
76
+        const sql="update MiaoguoWXUsers set IPAddress='"+ip+"' where UserID=1;"
77
+        commonModel.RunSql(null,sql);
78
+    })
79
+    .catch(err => {
80
+        console.error('获取公网IP失败:', err.message);
81
+    });

+ 47 - 1
src/test/stringClass.test.js

@@ -2,4 +2,50 @@
2 2
 import { stringUtils } from '../util/stringClass.js';
3 3
 
4 4
 // 测试获取服务器IP
5
-console.log('Server IP:', stringUtils.GetServerIP());
5
+console.log('Server IP:', stringUtils.GetServerIP());
6
+
7
+// 创建模拟的Koa上下文对象
8
+const mockCtx = {
9
+    request: {
10
+        headers: {
11
+            'x-forwarded-for': '192.168.1.1, 10.0.0.1',
12
+            'x-real-ip': '192.168.1.2'
13
+        },
14
+        ip: '192.168.1.3',
15
+        socket: {
16
+            remoteAddress: '192.168.1.4'
17
+        }
18
+    },
19
+    ip: '192.168.1.5'
20
+};
21
+
22
+// 测试不同场景的GetClientIP
23
+console.log('Client IP (with proxy headers):', stringUtils.GetClientIP(mockCtx));
24
+
25
+// 测试没有代理头的情况
26
+const mockCtxNoProxy = {
27
+    request: {
28
+        headers: {},
29
+        ip: '192.168.2.1',
30
+        socket: {
31
+            remoteAddress: '192.168.2.2'
32
+        }
33
+    },
34
+    ip: '192.168.2.3'
35
+};
36
+console.log('Client IP (no proxy headers):', stringUtils.GetClientIP(mockCtxNoProxy));
37
+
38
+// 测试IPv6格式
39
+const mockCtxIPv6 = {
40
+    request: {
41
+        headers: {
42
+            'x-forwarded-for': '::ffff:192.168.3.1'
43
+        },
44
+        ip: '::1',
45
+        socket: {
46
+            remoteAddress: '::ffff:192.168.3.2'
47
+        }
48
+    },
49
+    ip: '::ffff:192.168.3.3'
50
+};
51
+console.log('Client IP (IPv6 format):', stringUtils.GetClientIP(mockCtxIPv6));