koishi-plugin-jscn-aaaquery 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +9 -0
- package/lib/index.js +675 -0
- package/package.json +31 -0
- package/readme.md +60 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Context, Schema } from 'koishi';
|
|
2
|
+
export declare const name = "jscn-aaaquery";
|
|
3
|
+
export interface Config {
|
|
4
|
+
loginName: string;
|
|
5
|
+
password: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const Config: Schema<Config>;
|
|
9
|
+
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name2 in all)
|
|
8
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
Config: () => Config,
|
|
24
|
+
apply: () => apply,
|
|
25
|
+
name: () => name
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(src_exports);
|
|
28
|
+
var import_koishi = require("koishi");
|
|
29
|
+
var name = "jscn-aaaquery";
|
|
30
|
+
var Config = import_koishi.Schema.object({
|
|
31
|
+
loginName: import_koishi.Schema.string().required().description("运维系统登录账号"),
|
|
32
|
+
password: import_koishi.Schema.string().required().description("运维系统登录密码"),
|
|
33
|
+
baseUrl: import_koishi.Schema.string().default("http://172.16.251.75:8090/nms/api").description("运维系统API地址")
|
|
34
|
+
});
|
|
35
|
+
function apply(ctx, config) {
|
|
36
|
+
let currentToken = null;
|
|
37
|
+
let tokenExpireTime = 0;
|
|
38
|
+
function formatMacAddress(mac) {
|
|
39
|
+
return mac.replace(/[:-\s.]/g, "").toLowerCase();
|
|
40
|
+
}
|
|
41
|
+
__name(formatMacAddress, "formatMacAddress");
|
|
42
|
+
function isValidMacAddress(mac) {
|
|
43
|
+
const cleanMac = formatMacAddress(mac);
|
|
44
|
+
return /^[0-9a-f]{12}$/i.test(cleanMac);
|
|
45
|
+
}
|
|
46
|
+
__name(isValidMacAddress, "isValidMacAddress");
|
|
47
|
+
async function getToken() {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
if (currentToken && now < tokenExpireTime) {
|
|
50
|
+
console.log("使用缓存的token");
|
|
51
|
+
return currentToken;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
console.log("开始登录请求...");
|
|
55
|
+
console.log("请求参数:", {
|
|
56
|
+
loginName: config.loginName,
|
|
57
|
+
pwd: config.password
|
|
58
|
+
});
|
|
59
|
+
const response = await ctx.http.post(
|
|
60
|
+
`${config.baseUrl}/admin/login`,
|
|
61
|
+
`loginName=${encodeURIComponent(config.loginName)}&pwd=${encodeURIComponent(config.password)}`,
|
|
62
|
+
{
|
|
63
|
+
headers: {
|
|
64
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
65
|
+
"Accept": "application/json"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
console.log("登录响应:", JSON.stringify(response, null, 2));
|
|
70
|
+
if (response.status === 200 && response.data && response.data.token) {
|
|
71
|
+
currentToken = response.data.token;
|
|
72
|
+
tokenExpireTime = response.data.timeStamp * 1e3;
|
|
73
|
+
console.log("获取新token成功,过期时间:", new Date(tokenExpireTime).toLocaleString());
|
|
74
|
+
return currentToken;
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`登录失败:${response.message || "未知错误"}`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error("登录错误详情:", error);
|
|
79
|
+
if (error.response) {
|
|
80
|
+
console.error("错误响应:", error.response.data);
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
__name(getToken, "getToken");
|
|
86
|
+
async function queryAccount(account) {
|
|
87
|
+
try {
|
|
88
|
+
console.log("开始查询账号信息...");
|
|
89
|
+
const token = await getToken();
|
|
90
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/aaa/aaaCertification`, {
|
|
91
|
+
params: { accessUserName: account },
|
|
92
|
+
headers: {
|
|
93
|
+
"Authorization": token,
|
|
94
|
+
"Accept": "application/json",
|
|
95
|
+
"Content-Type": "application/json"
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
99
|
+
if (response.status === 200 && response.data) {
|
|
100
|
+
return response.data;
|
|
101
|
+
}
|
|
102
|
+
throw new Error(`查询失败:${response.message || "未知错误"}`);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("查询错误详情:", error);
|
|
105
|
+
if (error.response) {
|
|
106
|
+
console.error("错误响应:", error.response.data);
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
__name(queryAccount, "queryAccount");
|
|
112
|
+
async function queryAccountDetail(account) {
|
|
113
|
+
try {
|
|
114
|
+
console.log("开始查询账号详情记录...");
|
|
115
|
+
const token = await getToken();
|
|
116
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/aaa/getMoreRecord`, {
|
|
117
|
+
params: { accessUserName: account },
|
|
118
|
+
headers: {
|
|
119
|
+
"Authorization": token,
|
|
120
|
+
"Accept": "application/json",
|
|
121
|
+
"Content-Type": "application/json"
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
125
|
+
if (response.status === 200 && response.data) {
|
|
126
|
+
return response.data;
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`查询失败:${response.message || "未知错误"}`);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error("查询错误详情:", error);
|
|
131
|
+
if (error.response) {
|
|
132
|
+
console.error("错误响应:", error.response.data);
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
__name(queryAccountDetail, "queryAccountDetail");
|
|
138
|
+
async function queryOnuList(mac) {
|
|
139
|
+
try {
|
|
140
|
+
console.log("开始查询MAC设备信息...");
|
|
141
|
+
const token = await getToken();
|
|
142
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/onu/searchOnuList`, {
|
|
143
|
+
params: { mac, limit: 50, page: 1 },
|
|
144
|
+
// 增加limit以获取更多结果
|
|
145
|
+
headers: {
|
|
146
|
+
"Authorization": token,
|
|
147
|
+
"Accept": "application/json",
|
|
148
|
+
"Content-Type": "application/json"
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
152
|
+
if (response.status === 200 && response.data && response.data.rows && response.data.rows.length > 0) {
|
|
153
|
+
const activeOnu = response.data.rows.find((row) => row.status === 1);
|
|
154
|
+
if (activeOnu) {
|
|
155
|
+
console.log("找到在线设备:", activeOnu);
|
|
156
|
+
return activeOnu;
|
|
157
|
+
}
|
|
158
|
+
const lastOnu = response.data.rows[response.data.rows.length - 1];
|
|
159
|
+
console.log("没有在线设备,返回最后一条记录:", lastOnu);
|
|
160
|
+
return lastOnu;
|
|
161
|
+
}
|
|
162
|
+
throw new Error(`查询失败:${response.message || "未找到设备信息"}`);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error("查询错误详情:", error);
|
|
165
|
+
if (error.response) {
|
|
166
|
+
console.error("错误响应:", error.response.data);
|
|
167
|
+
}
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
__name(queryOnuList, "queryOnuList");
|
|
172
|
+
async function queryOnuDetailInfo(onuId) {
|
|
173
|
+
try {
|
|
174
|
+
console.log("开始查询MAC详细信息...");
|
|
175
|
+
const token = await getToken();
|
|
176
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/onu/onuDetailInfo`, {
|
|
177
|
+
params: { onuId },
|
|
178
|
+
headers: {
|
|
179
|
+
"Authorization": token,
|
|
180
|
+
"Accept": "application/json",
|
|
181
|
+
"Content-Type": "application/json"
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
185
|
+
if (response.status === 200 && response.data) {
|
|
186
|
+
if (response.data.status === 1 && (response.data.onuReceivePower === "0" || response.data.onuSendPower === "0")) {
|
|
187
|
+
console.log("设备在线但光功率为0,尝试刷新光功率...");
|
|
188
|
+
try {
|
|
189
|
+
const powerResponse = await ctx.http.get(
|
|
190
|
+
`${config.baseUrl}/fttx/onu/refreshOnuPower`,
|
|
191
|
+
{
|
|
192
|
+
params: {
|
|
193
|
+
cid: response.data.cid,
|
|
194
|
+
gponIndex: response.data.gponIndex,
|
|
195
|
+
onuIndex: response.data.onuIndex
|
|
196
|
+
},
|
|
197
|
+
headers: {
|
|
198
|
+
"Authorization": token,
|
|
199
|
+
"Accept": "application/json",
|
|
200
|
+
"Content-Type": "application/json"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
if (powerResponse.status === 200 && powerResponse.data) {
|
|
205
|
+
console.log("光功率刷新成功:", powerResponse.data);
|
|
206
|
+
response.data.onuReceivePower = powerResponse.data.onuReceivePower;
|
|
207
|
+
response.data.onuSendPower = powerResponse.data.onuSendPower;
|
|
208
|
+
response.data.statusHealth = powerResponse.data.statusHealth;
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error("刷新光功率失败:", error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return response.data;
|
|
215
|
+
}
|
|
216
|
+
throw new Error(`查询失败:${response.message || "未知错误"}`);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error("查询错误详情:", error);
|
|
219
|
+
if (error.response) {
|
|
220
|
+
console.error("错误响应:", error.response.data);
|
|
221
|
+
}
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
__name(queryOnuDetailInfo, "queryOnuDetailInfo");
|
|
226
|
+
async function queryCCName(mac) {
|
|
227
|
+
try {
|
|
228
|
+
console.log("开始查询CCNAME...");
|
|
229
|
+
const token = await getToken();
|
|
230
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/onu/getCCname`, {
|
|
231
|
+
params: { mac },
|
|
232
|
+
headers: {
|
|
233
|
+
"Authorization": token,
|
|
234
|
+
"Accept": "application/json",
|
|
235
|
+
"Content-Type": "application/json"
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
239
|
+
if (response.status === 200 && response.data && response.data.ccname) {
|
|
240
|
+
return response.data.ccname;
|
|
241
|
+
}
|
|
242
|
+
return "无CCName";
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error("查询错误详情:", error);
|
|
245
|
+
return "无CCName";
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
__name(queryCCName, "queryCCName");
|
|
249
|
+
async function queryOnuOrder(onuDetail) {
|
|
250
|
+
try {
|
|
251
|
+
console.log("开始查询工单信息...");
|
|
252
|
+
const token = await getToken();
|
|
253
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/onu/onuOrderList`, {
|
|
254
|
+
params: {
|
|
255
|
+
cid: onuDetail.cid,
|
|
256
|
+
gponIndex: onuDetail.gponIndex,
|
|
257
|
+
onuIndex: onuDetail.onuIndex,
|
|
258
|
+
serial: onuDetail.serial
|
|
259
|
+
},
|
|
260
|
+
headers: {
|
|
261
|
+
"Authorization": token,
|
|
262
|
+
"Accept": "application/json",
|
|
263
|
+
"Content-Type": "application/json"
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
267
|
+
if (response.status === 200 && response.data && response.data.length > 0) {
|
|
268
|
+
return response.data[0];
|
|
269
|
+
}
|
|
270
|
+
return null;
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.error("查询错误详情:", error);
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
__name(queryOnuOrder, "queryOnuOrder");
|
|
277
|
+
async function queryOnuDetailVlanInfo(onuId) {
|
|
278
|
+
try {
|
|
279
|
+
console.log("开始查询业务配置信息...");
|
|
280
|
+
const token = await getToken();
|
|
281
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/onu/onuDetailVlanInfo`, {
|
|
282
|
+
params: { onuId },
|
|
283
|
+
headers: {
|
|
284
|
+
"Authorization": token,
|
|
285
|
+
"Accept": "application/json",
|
|
286
|
+
"Content-Type": "application/json"
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
290
|
+
return response;
|
|
291
|
+
} catch (error) {
|
|
292
|
+
console.error("查询错误详情:", error);
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
__name(queryOnuDetailVlanInfo, "queryOnuDetailVlanInfo");
|
|
297
|
+
async function queryOrderLog(mac, startTime, endTime) {
|
|
298
|
+
try {
|
|
299
|
+
console.log("开始查询工单日志...");
|
|
300
|
+
const token = await getToken();
|
|
301
|
+
const formattedMac = formatMacAddress(mac);
|
|
302
|
+
console.log("处理后的MAC地址:", formattedMac);
|
|
303
|
+
const response = await ctx.http.get(`${config.baseUrl}/fttx/orderAnalyBlock/selectorderAnalyBlockOneList`, {
|
|
304
|
+
params: {
|
|
305
|
+
mac: formattedMac,
|
|
306
|
+
startTime,
|
|
307
|
+
endTime
|
|
308
|
+
},
|
|
309
|
+
headers: {
|
|
310
|
+
"Authorization": token,
|
|
311
|
+
"Accept": "application/json",
|
|
312
|
+
"Content-Type": "application/json"
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
console.log("查询响应:", JSON.stringify(response, null, 2));
|
|
316
|
+
return response;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.error("查询错误详情:", error);
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
__name(queryOrderLog, "queryOrderLog");
|
|
323
|
+
ctx.middleware(async (session, next) => {
|
|
324
|
+
const input = session.content.trim();
|
|
325
|
+
if (input.includes(" ") || /[\u4e00-\u9fa5]/.test(input)) {
|
|
326
|
+
return next();
|
|
327
|
+
}
|
|
328
|
+
const cleanInput = formatMacAddress(input);
|
|
329
|
+
console.log("处理后的内容:", cleanInput);
|
|
330
|
+
if (isValidMacAddress(cleanInput)) {
|
|
331
|
+
try {
|
|
332
|
+
const onuList = await queryOnuList(cleanInput);
|
|
333
|
+
if (!onuList) {
|
|
334
|
+
return "未找到该MAC地址的设备信息";
|
|
335
|
+
}
|
|
336
|
+
const onuDetail = await queryOnuDetailInfo(onuList.id);
|
|
337
|
+
const ccname = await queryCCName(cleanInput);
|
|
338
|
+
const order = await queryOnuOrder(onuDetail);
|
|
339
|
+
const vlanInfo = await queryOnuDetailVlanInfo(onuList.id);
|
|
340
|
+
const messages = [
|
|
341
|
+
"📊 终端基本信息",
|
|
342
|
+
"--------------------------------",
|
|
343
|
+
`MAC地址: ${cleanInput}`,
|
|
344
|
+
`状态:${onuDetail.status === 1 ? "在线" : "不在线"}`,
|
|
345
|
+
`机房: ${onuDetail.roomName}`,
|
|
346
|
+
`设备名称: ${onuDetail.deviceName}`,
|
|
347
|
+
`OLT IP: ${onuDetail.oltIp}`,
|
|
348
|
+
`PON端口: ${onuDetail.portName}`,
|
|
349
|
+
`端口逻辑号: ${onuDetail.logicId}`,
|
|
350
|
+
`发射光功率: ${onuDetail.onuSendPower}dBm`,
|
|
351
|
+
`接收光功率: ${onuDetail.onuReceivePower}dBm`,
|
|
352
|
+
`CCName: ${ccname}`,
|
|
353
|
+
"",
|
|
354
|
+
"📝 工单信息",
|
|
355
|
+
"--------------------------------",
|
|
356
|
+
order ? [
|
|
357
|
+
`工单编号: ${order.orderId}`,
|
|
358
|
+
`创建时间: ${order.createDate}`,
|
|
359
|
+
`更新时间: ${order.updateDate}`
|
|
360
|
+
].join("\n") : "无工单信息",
|
|
361
|
+
"",
|
|
362
|
+
"🔧 业务配置信息",
|
|
363
|
+
"--------------------------------"
|
|
364
|
+
];
|
|
365
|
+
vlanInfo.forEach((info) => {
|
|
366
|
+
messages.push(
|
|
367
|
+
`端口 ${info.LAN}:`,
|
|
368
|
+
` VLAN: ${info.actualVlan}`
|
|
369
|
+
);
|
|
370
|
+
});
|
|
371
|
+
return messages.join("\n");
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error("查询过程出错:", error);
|
|
374
|
+
return "查询失败,请稍后重试";
|
|
375
|
+
}
|
|
376
|
+
} else {
|
|
377
|
+
try {
|
|
378
|
+
const accountInfo = await queryAccount(input);
|
|
379
|
+
const message = [
|
|
380
|
+
"📊 账号查询结果",
|
|
381
|
+
"--------------------------------",
|
|
382
|
+
`账号: ${accountInfo.accessUserName}`,
|
|
383
|
+
`状态: ${accountInfo.onlineStatus}`,
|
|
384
|
+
`认证: ${accountInfo.isPass}`,
|
|
385
|
+
`IP地址: ${accountInfo.userIp}`,
|
|
386
|
+
`MAC地址: ${accountInfo.mac}`,
|
|
387
|
+
`最大上行: ${accountInfo.maxUpSpeed}Mbps`,
|
|
388
|
+
`最大下行: ${accountInfo.maxDownSpeed}Mbps`,
|
|
389
|
+
`接入域: ${accountInfo.accessDomain}`,
|
|
390
|
+
`开始时间: ${accountInfo.startTime}`,
|
|
391
|
+
`在线时长: ${accountInfo.startTimeSum}分钟`,
|
|
392
|
+
`设备名称: ${accountInfo.nickName}`
|
|
393
|
+
].join("\n");
|
|
394
|
+
return message;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
console.error("查询过程出错:", error);
|
|
397
|
+
return "查询失败,请稍后重试";
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
ctx.command("账号查询 <account:string>", "查询宽带账号状态").action(async (_, account) => {
|
|
402
|
+
if (!account) return "请输入要查询的账号";
|
|
403
|
+
try {
|
|
404
|
+
const accountInfo = await queryAccount(account);
|
|
405
|
+
const message = [
|
|
406
|
+
"📊 账号查询结果",
|
|
407
|
+
"--------------------------------",
|
|
408
|
+
`账号: ${accountInfo.accessUserName}`,
|
|
409
|
+
`状态: ${accountInfo.onlineStatus}`,
|
|
410
|
+
`认证: ${accountInfo.isPass}`,
|
|
411
|
+
`IP地址: ${accountInfo.userIp}`,
|
|
412
|
+
`MAC地址: ${accountInfo.mac}`,
|
|
413
|
+
`最大上行: ${accountInfo.maxUpSpeed}Mbps`,
|
|
414
|
+
`最大下行: ${accountInfo.maxDownSpeed}Mbps`,
|
|
415
|
+
`接入域: ${accountInfo.accessDomain}`,
|
|
416
|
+
`开始时间: ${accountInfo.startTime}`,
|
|
417
|
+
`在线时长: ${accountInfo.startTimeSum}分钟`,
|
|
418
|
+
`设备名称: ${accountInfo.nickName}`
|
|
419
|
+
].join("\n");
|
|
420
|
+
return message;
|
|
421
|
+
} catch (error) {
|
|
422
|
+
console.error("查询过程出错:", error);
|
|
423
|
+
return "查询失败,请稍后重试";
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
ctx.command("账号详情 <account:string>", "查询宽带账号详细记录").action(async (_, account) => {
|
|
427
|
+
if (!account) return "请输入要查询的账号";
|
|
428
|
+
try {
|
|
429
|
+
const records = await queryAccountDetail(account);
|
|
430
|
+
if (records.length === 0) {
|
|
431
|
+
return "未找到该账号的详细记录";
|
|
432
|
+
}
|
|
433
|
+
const messages = records.map((record, index) => [
|
|
434
|
+
`📝 记录 #${index + 1}`,
|
|
435
|
+
"--------------------------------",
|
|
436
|
+
`账号: ${record.accessUserName}`,
|
|
437
|
+
`记录类型: ${record.recordType}`,
|
|
438
|
+
`设备名称: ${record.nickName}`,
|
|
439
|
+
`IP地址: ${record.ip}`,
|
|
440
|
+
`MAC地址: ${record.mac}`,
|
|
441
|
+
`登录时间: ${record.userLoginInTime}`,
|
|
442
|
+
`登出时间: ${record.userLoginOutTime}`,
|
|
443
|
+
`原因: ${record.reason || "无"}`
|
|
444
|
+
].join("\n"));
|
|
445
|
+
return messages.join("\n\n");
|
|
446
|
+
} catch (error) {
|
|
447
|
+
console.error("查询过程出错:", error);
|
|
448
|
+
return "查询失败,请稍后重试";
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
ctx.command("终端查询 <mac:string>", "查询终端基本信息").action(async (_, mac) => {
|
|
452
|
+
if (!mac) return "请输入要查询的MAC地址";
|
|
453
|
+
try {
|
|
454
|
+
const formattedMac = formatMacAddress(mac);
|
|
455
|
+
const onuList = await queryOnuList(formattedMac);
|
|
456
|
+
if (!onuList) {
|
|
457
|
+
return "未找到该MAC地址的设备信息";
|
|
458
|
+
}
|
|
459
|
+
const onuDetail = await queryOnuDetailInfo(onuList.id);
|
|
460
|
+
const vlanInfo = await queryOnuDetailVlanInfo(onuList.id);
|
|
461
|
+
const messages = [
|
|
462
|
+
"📊 终端基本信息",
|
|
463
|
+
"--------------------------------",
|
|
464
|
+
`MAC地址: ${formattedMac}`,
|
|
465
|
+
`状态:${onuDetail.status === 1 ? "在线" : "不在线"}`,
|
|
466
|
+
`发射光功率: ${onuDetail.onuSendPower}dBm`,
|
|
467
|
+
`接收光功率: ${onuDetail.onuReceivePower}dBm`,
|
|
468
|
+
"",
|
|
469
|
+
"🔧 业务配置信息",
|
|
470
|
+
"--------------------------------"
|
|
471
|
+
];
|
|
472
|
+
vlanInfo.forEach((info) => {
|
|
473
|
+
messages.push(
|
|
474
|
+
`端口 ${info.LAN}:`,
|
|
475
|
+
` VLAN: ${info.actualVlan}`
|
|
476
|
+
);
|
|
477
|
+
});
|
|
478
|
+
return messages.join("\n");
|
|
479
|
+
} catch (error) {
|
|
480
|
+
console.error("查询过程出错:", error);
|
|
481
|
+
return "查询失败,请稍后重试";
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
ctx.command("终端详细查询 <mac:string>", "查询终端详细信息").action(async (_, mac) => {
|
|
485
|
+
if (!mac) return "请输入要查询的MAC地址";
|
|
486
|
+
try {
|
|
487
|
+
const formattedMac = formatMacAddress(mac);
|
|
488
|
+
const onuList = await queryOnuList(formattedMac);
|
|
489
|
+
if (!onuList) {
|
|
490
|
+
return "未找到该MAC地址的设备信息";
|
|
491
|
+
}
|
|
492
|
+
const onuDetail = await queryOnuDetailInfo(onuList.id);
|
|
493
|
+
const ccname = await queryCCName(formattedMac);
|
|
494
|
+
const order = await queryOnuOrder(onuDetail);
|
|
495
|
+
const vlanInfo = await queryOnuDetailVlanInfo(onuList.id);
|
|
496
|
+
const messages = [
|
|
497
|
+
"📊 终端基本信息",
|
|
498
|
+
"--------------------------------",
|
|
499
|
+
`MAC地址: ${formattedMac}`,
|
|
500
|
+
`状态:${onuDetail.status === 1 ? "在线" : "不在线"}`,
|
|
501
|
+
`机房: ${onuDetail.roomName}`,
|
|
502
|
+
`设备名称: ${onuDetail.deviceName}`,
|
|
503
|
+
`OLT IP: ${onuDetail.oltIp}`,
|
|
504
|
+
`PON端口: ${onuDetail.portName}`,
|
|
505
|
+
`端口逻辑号: ${onuDetail.logicId}`,
|
|
506
|
+
`发射光功率: ${onuDetail.onuSendPower}dBm`,
|
|
507
|
+
`接收光功率: ${onuDetail.onuReceivePower}dBm`,
|
|
508
|
+
`CCName: ${ccname}`,
|
|
509
|
+
"",
|
|
510
|
+
"📝 工单信息",
|
|
511
|
+
"--------------------------------",
|
|
512
|
+
order ? [
|
|
513
|
+
`工单编号: ${order.orderId}`,
|
|
514
|
+
`创建时间: ${order.createDate}`,
|
|
515
|
+
`更新时间: ${order.updateDate}`
|
|
516
|
+
].join("\n") : "无工单信息",
|
|
517
|
+
"",
|
|
518
|
+
"🔧 业务配置信息",
|
|
519
|
+
"--------------------------------"
|
|
520
|
+
];
|
|
521
|
+
vlanInfo.forEach((info) => {
|
|
522
|
+
messages.push(
|
|
523
|
+
`端口 ${info.LAN}:`,
|
|
524
|
+
` VLAN: ${info.actualVlan}`
|
|
525
|
+
);
|
|
526
|
+
});
|
|
527
|
+
return messages.join("\n");
|
|
528
|
+
} catch (error) {
|
|
529
|
+
console.error("查询过程出错:", error);
|
|
530
|
+
return "查询失败,请稍后重试";
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
ctx.command("日志查询 <mac:string> [startTime:string] [endTime:string]", "查询终端工单日志").action(async (_, mac, startTime, endTime) => {
|
|
534
|
+
if (!mac) return "请输入要查询的MAC地址";
|
|
535
|
+
try {
|
|
536
|
+
const formatDate = /* @__PURE__ */ __name((date) => {
|
|
537
|
+
const year = date.getFullYear();
|
|
538
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
539
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
540
|
+
return `${year}-${month}-${day}`;
|
|
541
|
+
}, "formatDate");
|
|
542
|
+
const parseDate = /* @__PURE__ */ __name((dateStr) => {
|
|
543
|
+
if (dateStr.includes(".") || dateStr.includes("/")) {
|
|
544
|
+
const parts = dateStr.split(/[./]/);
|
|
545
|
+
if (parts.length === 3) {
|
|
546
|
+
const [year, month, day] = parts.map(Number);
|
|
547
|
+
return new Date(year, month - 1, day);
|
|
548
|
+
} else if (parts.length === 2) {
|
|
549
|
+
const [month, day] = parts.map(Number);
|
|
550
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
551
|
+
return new Date(year, month - 1, day);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const chineseMonthMap = {
|
|
555
|
+
"一": 1,
|
|
556
|
+
"二": 2,
|
|
557
|
+
"三": 3,
|
|
558
|
+
"四": 4,
|
|
559
|
+
"五": 5,
|
|
560
|
+
"六": 6,
|
|
561
|
+
"七": 7,
|
|
562
|
+
"八": 8,
|
|
563
|
+
"九": 9,
|
|
564
|
+
"十": 10,
|
|
565
|
+
"十一": 11,
|
|
566
|
+
"十二": 12
|
|
567
|
+
};
|
|
568
|
+
const chineseDayMap = {
|
|
569
|
+
"一": 1,
|
|
570
|
+
"二": 2,
|
|
571
|
+
"三": 3,
|
|
572
|
+
"四": 4,
|
|
573
|
+
"五": 5,
|
|
574
|
+
"六": 6,
|
|
575
|
+
"七": 7,
|
|
576
|
+
"八": 8,
|
|
577
|
+
"九": 9,
|
|
578
|
+
"十": 10,
|
|
579
|
+
"十一": 11,
|
|
580
|
+
"十二": 12,
|
|
581
|
+
"十三": 13,
|
|
582
|
+
"十四": 14,
|
|
583
|
+
"十五": 15,
|
|
584
|
+
"十六": 16,
|
|
585
|
+
"十七": 17,
|
|
586
|
+
"十八": 18,
|
|
587
|
+
"十九": 19,
|
|
588
|
+
"二十": 20,
|
|
589
|
+
"二十一": 21,
|
|
590
|
+
"二十二": 22,
|
|
591
|
+
"二十三": 23,
|
|
592
|
+
"二十四": 24,
|
|
593
|
+
"二十五": 25,
|
|
594
|
+
"二十六": 26,
|
|
595
|
+
"二十七": 27,
|
|
596
|
+
"二十八": 28,
|
|
597
|
+
"二十九": 29,
|
|
598
|
+
"三十": 30,
|
|
599
|
+
"三十一": 31
|
|
600
|
+
};
|
|
601
|
+
const monthMatch = dateStr.match(/[一二三四五六七八九十]+月/);
|
|
602
|
+
const dayMatch = dateStr.match(/[一二三四五六七八九十]+[号日]/);
|
|
603
|
+
if (monthMatch && dayMatch) {
|
|
604
|
+
const monthStr = monthMatch[0].replace("月", "");
|
|
605
|
+
const dayStr = dayMatch[0].replace(/[号日]/, "");
|
|
606
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
607
|
+
const month = chineseMonthMap[monthStr];
|
|
608
|
+
const day = chineseDayMap[dayStr];
|
|
609
|
+
return new Date(year, month - 1, day);
|
|
610
|
+
}
|
|
611
|
+
throw new Error("不支持的日期格式");
|
|
612
|
+
}, "parseDate");
|
|
613
|
+
let queryStartTime;
|
|
614
|
+
let queryEndTime;
|
|
615
|
+
try {
|
|
616
|
+
if (startTime && endTime) {
|
|
617
|
+
queryStartTime = formatDate(parseDate(startTime));
|
|
618
|
+
queryEndTime = formatDate(parseDate(endTime));
|
|
619
|
+
} else if (startTime) {
|
|
620
|
+
const endDate = parseDate(startTime);
|
|
621
|
+
const startDate = new Date(endDate);
|
|
622
|
+
startDate.setDate(startDate.getDate() - 1);
|
|
623
|
+
queryStartTime = formatDate(startDate);
|
|
624
|
+
queryEndTime = formatDate(endDate);
|
|
625
|
+
} else {
|
|
626
|
+
const today = /* @__PURE__ */ new Date();
|
|
627
|
+
const yesterday = new Date(today);
|
|
628
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
629
|
+
queryStartTime = formatDate(yesterday);
|
|
630
|
+
queryEndTime = formatDate(today);
|
|
631
|
+
}
|
|
632
|
+
} catch (error) {
|
|
633
|
+
return "日期格式错误,支持的格式:\n1. 2025.4.4 或 2025/4/4\n2. 4.7 或 4/7(自动补全当前年份)\n3. 四月五号\n4. 四月五日";
|
|
634
|
+
}
|
|
635
|
+
const logs = await queryOrderLog(mac, queryStartTime, queryEndTime);
|
|
636
|
+
if (logs.length === 0) {
|
|
637
|
+
return `未找到${queryStartTime}到${queryEndTime}的上线分析日志`;
|
|
638
|
+
}
|
|
639
|
+
const messages = [
|
|
640
|
+
"📋 工单日志",
|
|
641
|
+
"--------------------------------"
|
|
642
|
+
];
|
|
643
|
+
logs.forEach((log) => {
|
|
644
|
+
if (log.title.includes("上线分析")) {
|
|
645
|
+
messages.push(
|
|
646
|
+
`时间: ${log.updateDate}`,
|
|
647
|
+
`标题: ${log.title}`
|
|
648
|
+
);
|
|
649
|
+
log.logs.forEach((logGroup) => {
|
|
650
|
+
logGroup.forEach((logLine) => {
|
|
651
|
+
if (logLine.startsWith("1.") && logLine.includes("Pon端TrunkAll检查结果是:") || logLine.startsWith("2.") && logLine.includes("查询ccname=")) {
|
|
652
|
+
messages.push(` ${logLine}`);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
messages.push("--------------------------------");
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
if (messages.length === 2) {
|
|
660
|
+
return `未找到${queryStartTime}到${queryEndTime}的上线分析日志`;
|
|
661
|
+
}
|
|
662
|
+
return messages.join("\n");
|
|
663
|
+
} catch (error) {
|
|
664
|
+
console.error("查询过程出错:", error);
|
|
665
|
+
return "查询失败,请稍后重试";
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
__name(apply, "apply");
|
|
670
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
671
|
+
0 && (module.exports = {
|
|
672
|
+
Config,
|
|
673
|
+
apply,
|
|
674
|
+
name
|
|
675
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-jscn-aaaquery",
|
|
3
|
+
"description": "江苏有线无锡分公司宽带信息查询插件",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "atsc",
|
|
14
|
+
"dev": "atsc -w"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"koishi": "^4.18.7"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.11.19",
|
|
21
|
+
"atsc": "^1.1.3",
|
|
22
|
+
"typescript": "^5.3.3"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@koishijs/plugin-http": "^0.6.3",
|
|
26
|
+
"koishi": "^4.18.7"
|
|
27
|
+
},
|
|
28
|
+
"contributors": [
|
|
29
|
+
"chenluziyang <wxjscnjsb@163.com>"
|
|
30
|
+
]
|
|
31
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# koishi-plugin-jscn-aaaquery
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/koishi-plugin-jscn-aaaquery)
|
|
4
|
+
|
|
5
|
+
宽带账号认证查询插件
|
|
6
|
+
|
|
7
|
+
# Koishi 运维查询插件
|
|
8
|
+
|
|
9
|
+
本插件提供了运维系统查询功能,包括账号查询、终端查询、日志查询等功能。
|
|
10
|
+
|
|
11
|
+
## 功能说明
|
|
12
|
+
|
|
13
|
+
### 1. 账号查询
|
|
14
|
+
- 命令格式:`账号查询 <账号>`
|
|
15
|
+
- 示例:`账号查询 GDC8510019239048`
|
|
16
|
+
- 功能:查询宽带账号的基本信息,包括在线状态、IP地址、MAC地址等。
|
|
17
|
+
|
|
18
|
+
### 2. 账号详情
|
|
19
|
+
- 命令格式:`账号详情 <账号>`
|
|
20
|
+
- 示例:`账号详情 GDC8510019239048`
|
|
21
|
+
- 功能:查询宽带账号的详细记录,包括登录时间、登出时间等。
|
|
22
|
+
|
|
23
|
+
### 3. 终端查询
|
|
24
|
+
- 命令格式:`终端查询 <MAC地址>`
|
|
25
|
+
- 示例:`终端查询 00:11:22:33:44:55`
|
|
26
|
+
- 功能:查询终端的基本信息,包括光功率和业务配置信息。
|
|
27
|
+
- MAC地址支持多种格式:
|
|
28
|
+
- 纯字符串:`001122334455`
|
|
29
|
+
- 冒号分隔:`00:11:22:33:44:55`
|
|
30
|
+
- 短横线分隔:`00-11-22-33-44-55`
|
|
31
|
+
- 点号分隔:`00.11.22.33.44.55`
|
|
32
|
+
|
|
33
|
+
### 4. 终端详细查询
|
|
34
|
+
- 命令格式:`终端详细查询 <MAC地址>`
|
|
35
|
+
- 示例:`终端详细查询 00:11:22:33:44:55`
|
|
36
|
+
- 功能:查询终端的详细信息,包括机房、设备名称、OLT IP、工单信息等。
|
|
37
|
+
|
|
38
|
+
### 5. 日志查询
|
|
39
|
+
- 命令格式:`日志查询 <MAC地址> [开始时间] [结束时间]`
|
|
40
|
+
- 示例:
|
|
41
|
+
- `日志查询 00:11:22:33:44:55`
|
|
42
|
+
- `日志查询 00:11:22:33:44:55 2024.3.1 2024.3.10`
|
|
43
|
+
- `日志查询 00:11:22:33:44:55 三月一日`
|
|
44
|
+
- 功能:查询终端的工单日志。
|
|
45
|
+
- 时间格式支持:
|
|
46
|
+
- 完整日期:`2024.3.1` 或 `2024/3/1`
|
|
47
|
+
- 简写日期:`3.1` 或 `3/1`(自动补全当前年份)
|
|
48
|
+
- 中文日期:`三月一日` 或 `三月一号`
|
|
49
|
+
|
|
50
|
+
### 6. 智能查询
|
|
51
|
+
- 直接输入MAC地址或账号即可查询,无需输入命令。
|
|
52
|
+
- 示例:
|
|
53
|
+
- `00:11:22:33:44:55`(自动识别为MAC地址并查询终端详情)
|
|
54
|
+
- `GDC8510019239048`(自动识别为账号并查询账号信息)
|
|
55
|
+
|
|
56
|
+
## 注意事项
|
|
57
|
+
1. 所有查询都需要正确的权限和配置。
|
|
58
|
+
2. MAC地址不区分大小写,支持多种分隔符格式。
|
|
59
|
+
3. 日期格式支持多种写法,但建议使用标准格式。
|
|
60
|
+
4. 如果查询失败,请检查输入格式是否正确。
|