koishi-plugin-ets2-tools-tmp 2.0.0 → 2.1.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.
@@ -31,3 +31,9 @@ export function dlcList(http: any, type: any): Promise<{
31
31
  export function mileageRankingList(http: any, rankingType: any, tmpId: any): Promise<{
32
32
  error: boolean;
33
33
  }>;
34
+ /**
35
+ * 查询玩家历史数据
36
+ */
37
+ export function mapPlayerHistory(http: any, tmpId: any, serverId: any, startTime: any, endTime: any): Promise<{
38
+ error: boolean;
39
+ }>;
@@ -50,7 +50,7 @@ module.exports = {
50
50
  async playerInfo(http, tmpId) {
51
51
  let result = null;
52
52
  try {
53
- result = await http.get(`https://da.vtcm.link/player/info?tmpId=${tmpId}`);
53
+ result = await http.get(`${BASE_API}/player/info?tmpId=${tmpId}`);
54
54
  }
55
55
  catch {
56
56
  return {
@@ -110,5 +110,27 @@ module.exports = {
110
110
  data.data = result.data;
111
111
  }
112
112
  return data;
113
+ },
114
+ /**
115
+ * 查询玩家历史数据
116
+ */
117
+ async mapPlayerHistory(http, tmpId, serverId, startTime, endTime) {
118
+ let result = null;
119
+ try {
120
+ result = await http.get(`${BASE_API}/map/playerHistory?tmpId=${tmpId}&serverId=${serverId}&startTime=${startTime}&endTime=${endTime}`);
121
+ }
122
+ catch {
123
+ return {
124
+ error: true
125
+ };
126
+ }
127
+ // 拼接返回数据
128
+ let data = {
129
+ error: result.code !== 200
130
+ };
131
+ if (!data.error) {
132
+ data.data = result.data;
133
+ }
134
+ return data;
113
135
  }
114
136
  };
@@ -1,5 +1,6 @@
1
1
  const guildBind = require('../database/guildBind');
2
2
  const truckersMpApi = require("../api/truckersMpApi");
3
+ const evmOpenApi = require('../api/evmOpenApi');
3
4
  /**
4
5
  * 绑定 TMP ID
5
6
  */
@@ -8,11 +9,11 @@ module.exports = async (ctx, cfg, session, tmpId) => {
8
9
  return `请输入正确的玩家编号`;
9
10
  }
10
11
  // 查询玩家信息
11
- let playerInfo = await truckersMpApi.player(ctx.http, tmpId);
12
+ let playerInfo = await evmOpenApi.playerInfo(ctx.http, tmpId);
12
13
  if (playerInfo.error) {
13
14
  return '绑定失败 (查询玩家信息失败)';
14
15
  }
15
16
  // 更新数据库
16
- guildBind.saveOrUpdate(ctx.database, session.platform, session.userId, tmpId);
17
+ guildBind.saveOrUpdate(ctx.database, session.platform, session.userId, playerInfo.data.tmpId);
17
18
  return `绑定成功 ( ${playerInfo.data.name} )`;
18
19
  };
@@ -0,0 +1,3 @@
1
+ declare function _exports(ctx: any, session: any, serverName: any): Promise<string | segment>;
2
+ export = _exports;
3
+ import { segment } from "@koishijs/core";
@@ -0,0 +1,68 @@
1
+ const { segment } = require('koishi');
2
+ const dayjs = require('dayjs');
3
+ const { resolve } = require('path');
4
+ const common = require('../util/common');
5
+ const { ServerAliasToId, PromodsIds } = require('../util/constant');
6
+ const evmOpenApi = require('../api/evmOpenApi');
7
+ const guildBind = require('../database/guildBind');
8
+ module.exports = async (ctx, session, serverName) => {
9
+ if (!ctx.puppeteer) {
10
+ return '未启用 puppeteer 服务';
11
+ }
12
+ // 转换服务器别名到ID
13
+ let serverId = ServerAliasToId[serverName];
14
+ if (!serverId) {
15
+ return '请输入正确的服务器名称 (s1, s2, p, a)';
16
+ }
17
+ // 尝试从数据库查询绑定信息
18
+ let guildBindData = await guildBind.get(ctx.database, session.platform, session.userId);
19
+ if (!guildBindData) {
20
+ return `请先绑定玩家编号`;
21
+ }
22
+ let tmpId = guildBindData.tmp_id;
23
+ // 查询玩家信息
24
+ let playerInfo = await evmOpenApi.playerInfo(ctx.http, tmpId);
25
+ if (playerInfo.error && playerInfo.code === 10001) {
26
+ return '玩家不存在';
27
+ }
28
+ else if (playerInfo.error) {
29
+ return '查询玩家信息失败,请重试';
30
+ }
31
+ // 查询当日历史位置数据
32
+ const startTime = dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss');
33
+ const endTime = dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss');
34
+ let mapPlayerHistory = await evmOpenApi.mapPlayerHistory(ctx.http, tmpId, serverId, startTime, endTime);
35
+ if (mapPlayerHistory.data.length === 0) {
36
+ return `当日暂无数据`;
37
+ }
38
+ // 拼接数据
39
+ let data = {
40
+ mapType: PromodsIds.indexOf(serverId) !== -1 ? 'promods' : 'ets',
41
+ name: playerInfo.data.name,
42
+ smallAvatarUrl: playerInfo.data.smallAvatarUrl,
43
+ todayMileage: playerInfo.data.todayMileage,
44
+ points: mapPlayerHistory.data
45
+ };
46
+ let page;
47
+ try {
48
+ page = await ctx.puppeteer.page();
49
+ await page.setViewport({ width: 1000, height: 1000 });
50
+ await page.goto(`file:///${resolve(__dirname, '../resource/footprint.html')}`);
51
+ await page.evaluate(`init(${JSON.stringify(data)})`);
52
+ await common.sleep(100);
53
+ await page.waitForNetworkIdle();
54
+ const element = await page.$("#container");
55
+ return (segment.image(await element.screenshot({
56
+ encoding: "binary"
57
+ }), "image/jpg"));
58
+ }
59
+ catch (e) {
60
+ return '渲染异常,请重试';
61
+ }
62
+ finally {
63
+ if (page) {
64
+ await page.close();
65
+ }
66
+ }
67
+ return `OK: ` + playerInfo.data.name;
68
+ };
@@ -12,10 +12,26 @@ const common = require('../util/common')
12
12
  */
13
13
  module.exports = async (ctx, cfg, session, tmpId) => {
14
14
  if (ctx.puppeteer) {
15
- if (tmpId && isNaN(tmpId)) {
16
- return `请输入正确的玩家编号`
15
+ if (tmpId && tmpId.startsWith("<at ")) {
16
+ if (tmpId.startsWith('<at ')) {
17
+ queryQQ = tmpId.replace('<at ', '');
18
+ }
19
+ let id = '';
20
+ const idStart = queryQQ.indexOf('id="');
21
+ if (idStart !== -1) {
22
+ const valueStart = idStart + 4;
23
+ const valueEnd = queryQQ.indexOf('"', valueStart);
24
+ if (valueEnd !== -1) {
25
+ id = queryQQ.substring(valueStart, valueEnd);
26
+ }
27
+ }
28
+ queryQQ = id;
29
+ let guildBindData = await guildBind.get(ctx.database, session.platform, queryQQ);
30
+ if (!guildBindData) {
31
+ return `该用户没有绑定玩家编号`;
32
+ }
33
+ tmpId = guildBindData.tmp_id;
17
34
  }
18
-
19
35
  // 如果没有传入tmpId,尝试从数据库查询绑定信息
20
36
  if (!tmpId) {
21
37
  let guildBindData = await guildBind.get(ctx.database, session.platform, session.userId)
package/lib/index.js CHANGED
@@ -18,7 +18,8 @@ const commands = {
18
18
  tmpMileageRanking: require('./command/tmpMileageRanking'),
19
19
  resetPassword: require('./command/ets-app/resetPassword'),
20
20
  queryPoint: require('./command/ets-app/queryPoint'),
21
- tmpVtc: require('./command/tmpVtc')
21
+ tmpVtc: require('./command/tmpVtc'),
22
+ tmpFootprint: require('./command/tmpFootprint')
22
23
  };
23
24
  const { ActivityService } = require('./command/tmpActivityService');
24
25
 
@@ -72,6 +73,7 @@ exports.Config = koishi_1.Schema.intersect([
72
73
  tmpDlcMap: koishi_1.Schema.boolean().default(true).description('是否启用DLC地图查询'),
73
74
  tmpMileageRanking: koishi_1.Schema.boolean().default(true).description('是否启用里程排行榜'),
74
75
  tmpVtc: koishi_1.Schema.boolean().default(true).description('是否启用VTC查询'),
76
+ tmpFootprint: koishi_1.Schema.boolean().default(true).description('是否启用今日足迹'),
75
77
  mainSettings: koishi_1.Schema.boolean().default(false).description('是否启用车队平台积分查询功能'),
76
78
  resetPassword: koishi_1.Schema.boolean().default(false).description('是否启用车队平台重置密码功能'),
77
79
  tmpActivityService: koishi_1.Schema.boolean().default(false).description('是否启用车队活动查询')
@@ -182,6 +184,7 @@ function logDisabledCommands(ctx, cfg) {
182
184
  { key: 'tmpDlcMap', label: '??dlc??' },
183
185
  { key: 'tmpMileageRanking', label: '?????/???????' },
184
186
  { key: 'tmpVtc', label: 'vtc??' },
187
+ { key: 'tmpFootprint', label: '???' },
185
188
  { key: 'resetPassword', label: '????' },
186
189
  { key: 'mainSettings', label: '????' }
187
190
  ];
@@ -257,6 +260,13 @@ function registerBaseCommands(ctx, cfg) {
257
260
  .action(async ({ session }, vtcid) => await commands.tmpVtc(ctx, cfg, session, vtcid));
258
261
  }
259
262
 
263
+ if (cfg.commands?.tmpFootprint) {
264
+ ctx.command('今日足迹 <serverName>')
265
+ .usage("查询今日足迹")
266
+ .example("今日足迹 s1")
267
+ .action(async ({ session }, serverName) => await commands.tmpFootprint(ctx, session, serverName));
268
+ }
269
+
260
270
  if (cfg.commands?.resetPassword) {
261
271
  ctx.command(`重置密码 [targetTeamId:string] [password:string]`, "重置欧卡车队平台密码")
262
272
  .usage("V1.0使用teamId,V2.0使用QQ号;管理员可用 uid=12345;V2.0可指定新密码")
@@ -0,0 +1,241 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>玩家足迹展示</title>
6
+ <link href="./package/leaflet/leaflet.min.css" rel="stylesheet">
7
+ <script src="./package/leaflet/leaflet.min.js"></script>
8
+ <style>
9
+ @font-face {
10
+ font-family: 'segui-emj';
11
+ src: url('./package/SEGUIEMJ.TTF');
12
+ font-weight: normal;
13
+ font-style: normal;
14
+ }
15
+ body, html {
16
+ margin: 0;
17
+ padding: 0;
18
+ font-family: 'segui-emj', "微软雅黑", serif;
19
+ }
20
+ #container {
21
+ width: 800px;
22
+ height: 600px;
23
+ background: #1a1a1a;
24
+ overflow: hidden;
25
+ position: relative;
26
+ }
27
+ .status-bar {
28
+ position: absolute;
29
+ bottom: 0;
30
+ left: 0;
31
+ right: 0;
32
+ height: 32px;
33
+ background-color: rgba(0, 0, 0, 0.5);
34
+ backdrop-filter: blur(10px);
35
+ -webkit-backdrop-filter: blur(10px);
36
+ display: flex;
37
+ align-items: center;
38
+ padding: 0 12px;
39
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, .5);
40
+ z-index: 1001;
41
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
42
+ font-size: 13px;
43
+ box-sizing: border-box;
44
+ }
45
+ .status-bar .avatar {
46
+ width: 20px;
47
+ height: 20px;
48
+ border-radius: 4px;
49
+ border: 1px solid rgba(255, 255, 255, 0.3);
50
+ margin-right: 8px;
51
+ }
52
+ .status-bar .info {
53
+ flex: 1;
54
+ display: flex;
55
+ align-items: center;
56
+ }
57
+ .status-bar .info .name {
58
+ color: #b0c7ff;
59
+ font-weight: 600;
60
+ }
61
+ .status-bar .stats {
62
+ display: flex;
63
+ align-items: center;
64
+ color: #aaaaaa;
65
+ }
66
+ .status-bar .stats .label {
67
+ margin-right: 6px;
68
+ }
69
+ .status-bar .stats .value {
70
+ font-weight: bold;
71
+ color: #54d354;
72
+ }
73
+
74
+ #map-box {
75
+ width: 100%;
76
+ height: 100%;
77
+ }
78
+ #map {
79
+ width: 100%;
80
+ height: 100%;
81
+ background-color: rgba(0, 0, 0, 0.25);
82
+ }
83
+
84
+ .marker-label {
85
+ background: rgba(0, 0, 0, 0.6);
86
+ border: 1px solid rgba(255, 255, 255, 0.2);
87
+ border-radius: 4px;
88
+ color: #fff;
89
+ padding: 2px 6px;
90
+ font-size: 12px;
91
+ white-space: nowrap;
92
+ }
93
+ </style>
94
+ </head>
95
+ <body>
96
+ <div id="container">
97
+ <div id="map-box">
98
+ <div id="map"></div>
99
+ </div>
100
+ <div class="status-bar">
101
+ <img class="avatar" id="avatar" src="https://static.truckersmp.com/avatarsN/small/defaultavatar.png" alt="avatar"/>
102
+ <div class="info">
103
+ <div class="name" id="username">测试玩家</div>
104
+ </div>
105
+ <div class="stats" id="stats-box">
106
+ <span class="label">今日里程</span>
107
+ <span class="value" id="distance">0.0 km</span>
108
+ </div>
109
+ </div>
110
+ </div>
111
+
112
+ <script src="./package/ets-map.js"></script>
113
+ <script>
114
+ function calculateDistance(p1, p2) {
115
+ return Math.sqrt(Math.pow(p1.axisX - p2.axisX, 2) + Math.pow(p1.axisY - p2.axisY, 2));
116
+ }
117
+
118
+ function parseTime(timeStr) {
119
+ return new Date(timeStr.replace(/-/g, '/')).getTime();
120
+ }
121
+
122
+ function init(data) {
123
+ if (!data) return;
124
+
125
+ document.getElementById('username').innerText = (data.name || 'Unknown') + ' 的今日行驶足迹';
126
+ if (data.smallAvatarUrl) {
127
+ document.getElementById('avatar').src = data.smallAvatarUrl;
128
+ }
129
+
130
+ const points = (data.points || []).filter(p => !(p.axisX === 0 && p.axisY === 0 && p.heading === 0));
131
+ // 使用传入的今日里程数据(米转千米)
132
+ const mileage = data.todayMileage || 0;
133
+ const km = (mileage / 1000).toFixed(1);
134
+ document.getElementById('distance').innerText = `${km} km`;
135
+
136
+ if (points.length === 0) {
137
+ return;
138
+ }
139
+
140
+ const lines = [];
141
+ let currentLine = [];
142
+
143
+ if (points.length > 0) {
144
+ let first = points[0];
145
+ currentLine.push({ x: first.axisX, y: first.axisY });
146
+
147
+ for (let i = 1; i < points.length; i++) {
148
+ const prev = points[i - 1];
149
+ const curr = points[i];
150
+
151
+ let dist = calculateDistance(prev, curr);
152
+ dist = dist * 19;
153
+ const isDistJump = dist > 50000; // > 50km
154
+
155
+ let timeDiff = 0;
156
+ try {
157
+ timeDiff = (parseTime(curr.updateTime) - parseTime(prev.updateTime)) / 1000;
158
+ } catch (e) { }
159
+
160
+ const isTimeJump = timeDiff > 90;
161
+ const isServerJump = prev.serverId !== curr.serverId;
162
+
163
+ if (isDistJump || isTimeJump || isServerJump) {
164
+ if (currentLine.length > 0) lines.push(currentLine);
165
+ currentLine = [];
166
+ }
167
+ currentLine.push({ x: curr.axisX, y: curr.axisY });
168
+ }
169
+ if (currentLine.length > 0) lines.push(currentLine);
170
+ }
171
+
172
+ render(lines, data.mapType);
173
+ }
174
+ function render(lines, mapType) {
175
+ const config = mapConfig[mapType];
176
+
177
+ // 边界
178
+ let bounds = L.latLngBounds(
179
+ map.unproject([0, config.bounds.y], config.maxZoom),
180
+ map.unproject([config.bounds.x, 0], config.maxZoom)
181
+ );
182
+ map.setMaxBounds(bounds);
183
+
184
+ // 瓦片
185
+ L.tileLayer(config.tileUrl, {
186
+ minZoom: 0,
187
+ maxZoom: 8,
188
+ minNativeZoom: 2,
189
+ maxNativeZoom: 8,
190
+ tileSize: 512,
191
+ bounds: bounds,
192
+ reuseTiles: true
193
+ }).addTo(map);
194
+
195
+ let allLatlngs = [];
196
+
197
+ lines.forEach(points => {
198
+ if (!points || points.length === 0) return;
199
+
200
+ let latlngs = [];
201
+ points.forEach(xy => {
202
+ let unprojected = map.unproject(config.calculateMapCoordinate(xy.x, xy.y), 8);
203
+ latlngs.push([unprojected.lat, unprojected.lng]);
204
+ allLatlngs.push([unprojected.lat, unprojected.lng]);
205
+ });
206
+
207
+ // 轨迹线
208
+ L.polyline(latlngs, {
209
+ color: '#3498db',
210
+ weight: 4,
211
+ opacity: 0.8,
212
+ lineJoin: 'round'
213
+ }).addTo(map);
214
+
215
+ // 起点
216
+ L.circleMarker(latlngs[0], {
217
+ radius: 4,
218
+ fillColor: '#2ecc71',
219
+ color: '#fff',
220
+ weight: 2,
221
+ fillOpacity: 1
222
+ }).addTo(map);
223
+
224
+ // 终点
225
+ L.circleMarker(latlngs[latlngs.length - 1], {
226
+ radius: 4,
227
+ fillColor: '#e74c3c',
228
+ color: '#fff',
229
+ weight: 2,
230
+ fillOpacity: 1
231
+ }).addTo(map);
232
+ });
233
+
234
+ // 自动适应
235
+ if (allLatlngs.length > 0) {
236
+ map.fitBounds(L.latLngBounds(allLatlngs), { padding: [50, 50] });
237
+ }
238
+ }
239
+ </script>
240
+ </body>
241
+ </html>
@@ -0,0 +1,63 @@
1
+ let mapConfig = {
2
+ ets: {
3
+ tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/ets2/05102019/{z}/{x}/{y}.png',
4
+ multipliers: {
5
+ x: 70272,
6
+ y: 76157
7
+ },
8
+ breakpoints: {
9
+ uk: {
10
+ x: -31056.8,
11
+ y: -5832.867
12
+ }
13
+ },
14
+ bounds: {
15
+ y: 131072,
16
+ x: 131072
17
+ },
18
+ maxZoom: 8,
19
+ minZoom: 2,
20
+ // 游戏地转地图坐标
21
+ calculateMapCoordinate (x, y) {
22
+ return [
23
+ x / 1.609055 + mapConfig.ets.multipliers.x,
24
+ y / 1.609055 + mapConfig.ets.multipliers.y
25
+ ];
26
+ }
27
+ },
28
+ promods: {
29
+ tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/promods/05102019/{z}/{x}/{y}.png',
30
+ multipliers: {
31
+ x: 51953,
32
+ y: 76024
33
+ },
34
+ breakpoints: {
35
+ uk: {
36
+ x: -31056.8,
37
+ y: -5832.867
38
+ }
39
+ },
40
+ bounds: {
41
+ y: 131072,
42
+ x: 131072
43
+ },
44
+ maxZoom: 8,
45
+ minZoom: 2,
46
+ // 游戏地转地图坐标
47
+ calculateMapCoordinate (x, y) {
48
+ return [
49
+ x / 2.598541 + mapConfig.promods.multipliers.x,
50
+ y / 2.598541 + mapConfig.promods.multipliers.y
51
+ ]
52
+ }
53
+ }
54
+ }
55
+
56
+ // 定义地图
57
+ let map = L.map('map', {
58
+ attributionControl: false,
59
+ crs: L.CRS.Simple,
60
+ zoomControl: false,
61
+ zoomSnap: 0.2,
62
+ zoomDelta: 0.2
63
+ });
@@ -3,11 +3,11 @@ const translateCache = require('../database/translateCache');
3
3
  const TRANSLATE_API = 'https://fanyi-api.baidu.com/api/trans/vip/translate';
4
4
  module.exports = async (ctx, cfg, content, cache = true) => {
5
5
  // 没有开启百度翻译功能,直接返回文本
6
- if (!cfg.baiduTranslate?.enable) {
6
+ if (!cfg.baiduTranslateEnable) {
7
7
  return content;
8
8
  }
9
9
  // 如果开启了缓存,尝试从缓存中查询翻译
10
- if (cfg.baiduTranslate?.cacheEnable && cache) {
10
+ if (cfg.baiduTranslateCacheEnable && cache) {
11
11
  let translateContent = await translateCache.getTranslate(ctx.database, md5(content));
12
12
  if (translateContent) {
13
13
  return translateContent;
@@ -15,15 +15,15 @@ module.exports = async (ctx, cfg, content, cache = true) => {
15
15
  }
16
16
  // 创建请求秘钥
17
17
  let randomInt = Math.floor(Math.random() * 10000);
18
- let sign = md5(cfg.baiduTranslate?.appId + content + randomInt + cfg.baiduTranslate?.key);
18
+ let sign = md5(cfg.baiduTranslateAppId + content + randomInt + cfg.baiduTranslateKey);
19
19
  // 调用请求
20
- let result = await ctx.http.get(`${TRANSLATE_API}?q=${encodeURI(content)}&from=auto&to=zh&appid=${cfg.baiduTranslate?.appId}&salt=${randomInt}&sign=${sign}`);
20
+ let result = await ctx.http.get(`${TRANSLATE_API}?q=${encodeURI(content)}&from=auto&to=zh&appid=${cfg.baiduTranslateAppId}&salt=${randomInt}&sign=${sign}`);
21
21
  // 如果翻译失败,直接返回内容
22
22
  if (result.error_code) {
23
23
  return content;
24
24
  }
25
25
  // 如果开启了缓存,将翻译内容缓存到数据库
26
- if (cfg.baiduTranslate?.cacheEnable && cache) {
26
+ if (cfg.baiduTranslateCacheEnable && cache) {
27
27
  translateCache.save(ctx.database, md5(content), content, result.trans_result[0].dst);
28
28
  }
29
29
  return result.trans_result[0].dst;
@@ -6,3 +6,10 @@ export namespace MileageRankingType {
6
6
  let total: number;
7
7
  let today: number;
8
8
  }
9
+ export namespace ServerAliasToId {
10
+ let s1: number;
11
+ let s2: number;
12
+ let p: number;
13
+ let a: number;
14
+ }
15
+ export let PromodsIds: number[];
@@ -12,5 +12,18 @@ module.exports = {
12
12
  MileageRankingType: {
13
13
  total: 1,
14
14
  today: 2
15
- }
15
+ },
16
+ /**
17
+ * 服务器别名映射ID
18
+ */
19
+ ServerAliasToId: {
20
+ 's1': 2,
21
+ 's2': 41,
22
+ 'p': 50,
23
+ 'a': 7
24
+ },
25
+ /**
26
+ * P服务器ID集合
27
+ */
28
+ PromodsIds: [50, 51]
16
29
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-ets2-tools-tmp",
3
3
  "description": "欧卡2 TMP在线查询、车队平台查询及活动提醒",
4
- "version": "2.0.0",
4
+ "version": "2.1.1",
5
5
  "contributors": [
6
6
  "opwop <slhp1013@qq.com>",
7
7
  "bot_actions <168329908@qq.com>"
package/readme.md CHANGED
@@ -102,12 +102,11 @@
102
102
  | 里程排行榜 | 总里程排行榜(数据从2025年8月23日20:00开始统计,绑定ID后可查个人排名) | 里程排行榜 |
103
103
  | 今日里程排行榜 | 今日里程排行榜(每日0点重置数据,绑定ID后可查个人排名) | 今日里程排行榜 |
104
104
  | vtc查询 <vtcid> | 查询指定VTC ID的详细信息 | vtc查询 456 |
105
- | 重置密码 [teamId]| 重置车队平台(V1.0)密码,管理员可指定teamId,普通用户重置自身密码 | 重置密码 789 |
106
- | 查询积分 [QQ号] | 查询车队平台(V1.0)积分,可查询自身或指定QQ号积分 | 查询积分 123456 |
105
+ | 重置密码 [teamId]| 重置车队平台密码,管理员可指定teamId,普通用户重置自身密码 | 重置密码 789 |
106
+ | 查询积分 [QQ号] | 查询车队平台积分,可查询自身或指定QQ号积分 | 查询积分 123456 |
107
107
  | 规则查询 | 获取TruckersMP官方规则链接 | 规则查询 |
108
108
  | 活动查询 | 手动检查今日活动数据,返回活动数量统计 | 活动查询 |
109
- | 活动DEBUG | 查看插件运行状态、数据统计等调试信息 | 活动DEBUG |
110
- | 重置数据 | 手动重置今日活动数据与提醒记录 | 重置数据 |
109
+ | 今日足迹 <serverName> | 查看今日的足迹,支持简称:s1(Simulation 1)、s2(Simulation 2)、p(ProMods)、a(Arcade) | 今日足迹 s1 |
111
110
 
112
111
  ## 📝 使用方法
113
112