koishi-plugin-ets2-tools-tmp 2.4.1 → 2.5.1

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.
@@ -234,11 +234,19 @@ module.exports = async (ctx, cfg, session, targetTeamId, password) => {
234
234
  if (!teamId) return "未找到您的信息,请联系管理员";
235
235
  } else {
236
236
  // 有目标编号时验证权限
237
+ log(`用户 ${currentUserQQ} 尝试重置车队编号 ${targetTeamId} 的密码`);
237
238
  const userInfo = await getUserInfo({ teamId: targetTeamId });
238
- if (!isAdmin && userInfo.qq !== currentUserQQ) {
239
+
240
+ if (!isAdmin && String(userInfo.qq) !== String(currentUserQQ)) {
239
241
  return "您没有权限重置其他成员的密码,请联系管理员";
240
242
  }
243
+
241
244
  teamId = targetTeamId;
245
+ if (isAdmin) {
246
+ log(`管理员 ${currentUserQQ} 重置车队编号 ${targetTeamId} 的密码`);
247
+ } else {
248
+ log(`验证通过,车队编号 ${targetTeamId} 对应的QQ ${userInfo.qq} 与当前用户QQ ${currentUserQQ} 一致`);
249
+ }
242
250
  }
243
251
  } else {
244
252
  // 非私聊场景(仅管理员可操作)
@@ -246,7 +254,7 @@ module.exports = async (ctx, cfg, session, targetTeamId, password) => {
246
254
 
247
255
  teamId = targetTeamId;
248
256
  log(`管理员 ${currentUserQQ} 重置车队: ${teamId} 密码`);
249
- await getUserInfo({ teamId }); // 验证车队存在性
257
+ await getUserInfo({ teamId });
250
258
  }
251
259
  }
252
260
 
@@ -44,7 +44,7 @@ module.exports = async (ctx, cfg, session, tmpId) => {
44
44
  // 查询玩家信息
45
45
  let playerInfo = await truckersMpApi.player(ctx.http, tmpId)
46
46
  if (playerInfo.error) {
47
- return '查询玩家信息失败,请重试'
47
+ return '查询玩家位置信息失败,请重试'
48
48
  }
49
49
 
50
50
  // 查询线上信息
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VersionCheckService = void 0;
4
+
5
+ const koishi_1 = require("koishi");
6
+
7
+ class VersionCheckService {
8
+ constructor(ctx, config) {
9
+ this.ctx = ctx;
10
+ this.cfg = config;
11
+ this.currentVersion = null;
12
+ this.timers = [];
13
+ this.logger = this.initLogger();
14
+ }
15
+
16
+ initLogger() {
17
+ return {
18
+ debug: (message, ...args) => {
19
+ if (this.cfg.debugMode) {
20
+ this.ctx.logger.debug(`[TMP-BOT DEBUG] ${message}`, ...args);
21
+ }
22
+ },
23
+ info: (message, ...args) => {
24
+ this.ctx.logger.info(`[TMP-BOT] ${message}`, ...args);
25
+ },
26
+ warn: (message, ...args) => {
27
+ this.ctx.logger.warn(`[TMP-BOT WARN] ${message}`, ...args);
28
+ },
29
+ error: (message, ...args) => {
30
+ this.ctx.logger.error(`[TMP-BOT ERROR] ${message}`, ...args);
31
+ },
32
+ api: (message, data) => {
33
+ if (this.cfg.debug?.logApiResponses) {
34
+ this.ctx.logger.info(`[TMP-BOT API] ${message}`, data ? JSON.stringify(data, null, 2) : "");
35
+ }
36
+ }
37
+ };
38
+ }
39
+
40
+ start() {
41
+ this.setupVersionCheck();
42
+ this.ctx.on("dispose", () => this.cleanup());
43
+ }
44
+
45
+ setupVersionCheck() {
46
+ this.logger.info("设置TMP版本检查服务");
47
+
48
+ this.logger.debug("启动时立即检查版本");
49
+ this.checkVersion();
50
+
51
+ const checkInterval = this.cfg.checkInterval * 60 * 1000;
52
+ this.logger.info(`设置定时版本检查,间隔: ${this.cfg.checkInterval} 分钟`);
53
+
54
+ const intervalTimer = setInterval(async () => {
55
+ this.logger.debug("执行定时版本检查");
56
+ await this.checkVersion();
57
+ }, checkInterval);
58
+ this.timers.push(intervalTimer);
59
+ }
60
+
61
+ async checkVersion() {
62
+ try {
63
+ const apiUrl = "https://api.truckersmp.com/v2/version";
64
+ this.logger.api(`请求TMP版本API: ${apiUrl}`);
65
+
66
+ const startTime = Date.now();
67
+ const response = await this.ctx.http.get(apiUrl, { timeout: 10000 });
68
+ const duration = Date.now() - startTime;
69
+ this.logger.api(`TMP版本API响应耗时: ${duration}ms`);
70
+
71
+ if (response && response.name) {
72
+ const versionInfo = {
73
+ name: response.name,
74
+ time: this.convertToUTC8(response.time),
75
+ supported_game_version: response.supported_game_version,
76
+ supported_ats_game_version: response.supported_ats_game_version
77
+ };
78
+
79
+ this.logger.info(`获取到TMP版本信息: ${versionInfo.name} (${versionInfo.time})`);
80
+
81
+ if (this.currentVersion && this.currentVersion.name !== versionInfo.name) {
82
+ this.logger.info(`检测到版本更新: ${this.currentVersion.name} -> ${versionInfo.name}`);
83
+ await this.sendVersionUpdateNotification(this.currentVersion, versionInfo);
84
+ }
85
+
86
+ this.currentVersion = versionInfo;
87
+ } else {
88
+ this.logger.error("TMP版本API返回的数据格式不正确");
89
+ }
90
+ } catch (error) {
91
+ this.logger.error("检查TMP版本失败:", error.message);
92
+ }
93
+ }
94
+
95
+ convertToUTC8(utcTimeString) {
96
+ try {
97
+ const utcDate = new Date(utcTimeString);
98
+ const utc8Date = new Date(utcDate.getTime() + 8 * 60 * 60 * 1000);
99
+ const year = utc8Date.getFullYear();
100
+ const month = String(utc8Date.getMonth() + 1).padStart(2, '0');
101
+ const day = String(utc8Date.getDate()).padStart(2, '0');
102
+ const hours = String(utc8Date.getHours()).padStart(2, '0');
103
+ const minutes = String(utc8Date.getMinutes()).padStart(2, '0');
104
+ const seconds = String(utc8Date.getSeconds()).padStart(2, '0');
105
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
106
+ } catch (error) {
107
+ this.logger.error("转换UTC时间失败:", error.message);
108
+ return utcTimeString;
109
+ }
110
+ }
111
+
112
+ async sendVersionUpdateNotification(oldVersion, newVersion) {
113
+ const message = `📢 TMP版本更新通知
114
+
115
+ 旧版本: ${oldVersion.name}
116
+ 新版本: ${newVersion.name}
117
+
118
+ 更新时间: ${newVersion.time}(UTC+8)
119
+ 欧卡支持版本: ${newVersion.supported_game_version}
120
+ 美卡支持版本: ${newVersion.supported_ats_game_version}`;
121
+
122
+ this.logger.info(`发送版本更新通知到 ${this.cfg.groups.length} 个群组`);
123
+
124
+ for (const groupId of this.cfg.groups) {
125
+ try {
126
+ await this.sendToGroup(groupId, message);
127
+ this.logger.info(`已发送版本更新通知到群组 ${groupId}`);
128
+ } catch (error) {
129
+ this.logger.error(`发送版本更新通知到群组 ${groupId} 失败:`, error.message);
130
+ }
131
+ }
132
+ }
133
+
134
+ async sendToGroup(groupId, message) {
135
+ const onebotBots = this.ctx.bots.filter((bot) => {
136
+ return bot.platform === "onebot";
137
+ });
138
+
139
+ if (onebotBots.length === 0) {
140
+ throw new Error("请启用onebot适配器以发送群消息");
141
+ }
142
+
143
+ let lastError = null;
144
+ this.logger.debug(`尝试通过 ${onebotBots.length} 个onebot适配器发送消息到群组 ${groupId}`);
145
+
146
+ for (const bot of onebotBots) {
147
+ try {
148
+ await bot.sendMessage(groupId, message);
149
+ this.logger.debug(`已通过 ${bot.platform} 适配器发送消息到群组 ${groupId}`);
150
+ return;
151
+ } catch (error) {
152
+ lastError = error;
153
+ this.logger.warn(`通过 ${bot.platform} 适配器发送消息失败: ${error.message}`);
154
+ }
155
+ }
156
+
157
+ throw lastError || new Error(`所有onebot适配器都无法发送消息到群组 ${groupId}`);
158
+ }
159
+
160
+ cleanup() {
161
+ this.logger.debug("插件卸载,开始清理版本检查服务资源");
162
+ this.timers.forEach((timer) => {
163
+ clearTimeout(timer);
164
+ clearInterval(timer);
165
+ });
166
+ this.timers.length = 0;
167
+ }
168
+ }
169
+
170
+ exports.VersionCheckService = VersionCheckService;
package/lib/index.js CHANGED
@@ -77,7 +77,8 @@ exports.Config = koishi_1.Schema.intersect([
77
77
  tmpFootprint: koishi_1.Schema.boolean().default(true).description('是否启用今日足迹'),
78
78
  mainSettings: koishi_1.Schema.boolean().default(false).description('是否启用车队平台积分查询功能'),
79
79
  resetPassword: koishi_1.Schema.boolean().default(false).description('是否启用车队平台重置密码功能'),
80
- tmpActivityService: koishi_1.Schema.boolean().default(false).description('是否启用车队活动查询')
80
+ tmpActivityService: koishi_1.Schema.boolean().default(false).description('是否启用车队活动查询'),
81
+ tmpVersionCheck: koishi_1.Schema.boolean().default(false).description('是否启用TMP版本更新查询')
81
82
  }).description('指令配置'),
82
83
  baiduTranslate: koishi_1.Schema.object({
83
84
  enable: koishi_1.Schema.boolean().default(false).description('是否启用百度翻译'),
@@ -98,6 +99,10 @@ exports.Config = koishi_1.Schema.intersect([
98
99
  koishi_1.Schema.const(2).description('热力图')
99
100
  ]).default(1).description('路况信息展示方式'),
100
101
  }).description('路况查询配置'),
102
+ tmpVersionCheck: koishi_1.Schema.object({
103
+ checkInterval: koishi_1.Schema.number().description("版本检查间隔(分钟)").default(30),
104
+ groups: koishi_1.Schema.array(koishi_1.Schema.string()).role("table").description("接收版本更新通知的群组ID列表").default([])
105
+ }).description("TMP版本更新查询配置"),
101
106
  mainSettings: koishi_1.Schema.object({
102
107
  settings: koishi_1.Schema.object({
103
108
  Name: koishi_1.Schema.string().description("车队名称"),
@@ -189,7 +194,9 @@ function logDisabledCommands(ctx, cfg) {
189
194
  { key: 'tmpVtc', label: 'vtc查询' },
190
195
  { key: 'tmpFootprint', label: '足迹查询' },
191
196
  { key: 'resetPassword', label: '重置密码' },
192
- { key: 'mainSettings', label: '查询积分' }
197
+ { key: 'mainSettings', label: '查询积分' },
198
+ { key: 'tmpActivityService', label: '车队活动查询' },
199
+ { key: 'tmpVersionCheck', label: 'TMP版本更新查询' }
193
200
  ];
194
201
  for (const item of commandList) {
195
202
  if (commandFlags[item.key] !== false) enabled.push(item.label);
@@ -361,6 +368,20 @@ function apply(ctx, cfg) {
361
368
  } else if (cfg.debugMode) {
362
369
  ctx.logger.debug("[TMP-BOT] 活动查询功能已禁用");
363
370
  }
371
+
372
+ if (cfg.commands?.tmpVersionCheck) {
373
+ const { VersionCheckService } = require('./command/tmpVersionCheck');
374
+ const versionCheckConfig = {
375
+ checkInterval: cfg.tmpVersionCheck.checkInterval,
376
+ groups: cfg.tmpVersionCheck.groups,
377
+ debugMode: cfg.debugMode,
378
+ debug: cfg.tmpActivityService?.debug
379
+ };
380
+ const versionCheckService = new VersionCheckService(ctx, versionCheckConfig);
381
+ versionCheckService.start();
382
+ } else if (cfg.debugMode) {
383
+ ctx.logger.debug("[TMP-BOT] TMP版本更新查询功能已禁用");
384
+ }
364
385
  }
365
386
  __name(apply, "apply");
366
387
  0 && (module.exports = {
@@ -14,14 +14,14 @@
14
14
  font-family: "微软雅黑", serif;
15
15
  }
16
16
  #container {
17
- width: 500px;
18
- height: 320px;
17
+ width: 720px;
18
+ height: 500px;
19
19
  position: relative;
20
20
  }
21
21
  .map {
22
22
  width: 100%;
23
23
  height: 100%;
24
- background-color: #5d5d5d;
24
+ background: linear-gradient(135deg, #1f2f54, #0f2c2a);
25
25
  }
26
26
  .user-info-box {
27
27
  width: 100%;
@@ -29,7 +29,7 @@
29
29
  position: absolute;
30
30
  bottom: 0;
31
31
  z-index: 999;
32
- background-color: rgba(100, 100, 100, 0.4);
32
+ background-color: rgba(0, 0, 0, 0.4);
33
33
  backdrop-filter: blur(6px);
34
34
  display: flex;
35
35
  flex-direction: row;
@@ -44,23 +44,23 @@
44
44
  }
45
45
  .user {
46
46
  height: 56px;
47
- width: 220px;
47
+ flex: 1;
48
+ margin-left: 10px;
49
+ box-sizing: border-box;
50
+ font-size: 16px;
51
+ color: #eeeeee;
48
52
  display: flex;
49
53
  flex-direction: column;
50
54
  justify-content: center;
51
55
  }
52
- .user {
53
- font-size: 16px;
54
- color: #eeeeee;
55
- margin-left: 10px;
56
- box-sizing: border-box;
57
- }
58
56
  .user .server-name-box {
59
57
  display: flex;
60
58
  align-items: center;
61
59
  margin-top: 4px;
60
+ opacity: 0.85;
62
61
  }
63
62
  .user .username {
63
+ font-weight: 600;
64
64
  white-space: nowrap;
65
65
  overflow: hidden;
66
66
  text-overflow: ellipsis;
@@ -75,7 +75,7 @@
75
75
  box-sizing: border-box;
76
76
  }
77
77
  .location-box {
78
- flex-grow: 1;
78
+ flex: 1;
79
79
  color: #eeeeee;
80
80
  font-size: 16px;
81
81
  height: 56px;
@@ -88,11 +88,17 @@
88
88
  justify-content: center;
89
89
  }
90
90
  .location-box>* {
91
- width: 174px;
91
+ max-width: 100%;
92
92
  white-space: nowrap;
93
93
  overflow: hidden;
94
94
  text-overflow: ellipsis;
95
95
  }
96
+ .location-box .country {
97
+ font-weight: 600;
98
+ }
99
+ .location-box .real-name {
100
+ opacity: 0.85;
101
+ }
96
102
  </style>
97
103
  </head>
98
104
  <body>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-ets2-tools-tmp",
3
3
  "description": "欧卡2 TruckersMP信息查询、车队平台查询及活动提醒",
4
- "version": "2.4.1",
4
+ "version": "2.5.1",
5
5
  "contributors": [
6
6
  "opwop <slhp1013@qq.com>",
7
7
  "bot_actions <168329908@qq.com>"
package/readme.md CHANGED
@@ -14,6 +14,7 @@
14
14
  - **游戏资源查询**:地图DLC价格、TMP版本信息一键获取
15
15
  - **排行与积分**:总里程/今日里程排行榜、车队平台积分查询
16
16
  - **VTC与规则**:支持指定VTC ID查询,提供TruckersMP官方规则快速链接
17
+ - **TMP版本更新通知**:支持TMP版本更新通知
17
18
 
18
19
  ### 🚚 车队活动管理
19
20
  - **双数据源支持**:同时对接车队平台和TruckersMP API获取活动数据
@@ -114,6 +115,7 @@
114
115
  ## 📝 使用方法
115
116
 
116
117
  ### 自动功能
118
+ - TMP更新时通知
117
119
  - 每日凌晨2点自动重置活动数据
118
120
  - 按配置时间自动检查活动数据与档位状态
119
121
  - 向管理群发送档位上传状态提醒