koishi-plugin-ets2-tools-tmp 0.0.2 → 0.0.3

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.
Files changed (60) hide show
  1. package/lib/api/evmOpenApi.d.ts +33 -0
  2. package/lib/api/evmOpenApi.js +114 -0
  3. package/lib/api/truckersMpApi.d.ts +34 -0
  4. package/lib/api/truckersMpApi.js +133 -0
  5. package/lib/api/truckersMpMapApi.d.ts +6 -0
  6. package/lib/api/truckersMpMapApi.js +25 -0
  7. package/lib/api/truckyAppApi.d.ts +12 -0
  8. package/lib/api/truckyAppApi.js +48 -0
  9. package/lib/command/ets-app/queryPoint.js +74 -0
  10. package/lib/command/ets-app/resetPassword.js +174 -0
  11. package/lib/command/tmpBind.d.ts +2 -0
  12. package/lib/command/tmpBind.js +18 -0
  13. package/lib/command/tmpDlcMap.d.ts +3 -0
  14. package/lib/command/tmpDlcMap.js +33 -0
  15. package/lib/command/tmpMileageRanking.d.ts +3 -0
  16. package/lib/command/tmpMileageRanking.js +55 -0
  17. package/lib/command/tmpPosition.d.ts +3 -0
  18. package/lib/command/tmpPosition.js +107 -0
  19. package/lib/command/tmpQuery/tmpQuery.d.ts +2 -0
  20. package/lib/command/tmpQuery/tmpQuery.js +12 -0
  21. package/lib/command/tmpQuery/tmpQueryImg.d.ts +3 -0
  22. package/lib/command/tmpQuery/tmpQueryImg.js +103 -0
  23. package/lib/command/tmpQuery/tmpQueryText.d.ts +2 -0
  24. package/lib/command/tmpQuery/tmpQueryText.js +178 -0
  25. package/lib/command/tmpServer.d.ts +2 -0
  26. package/lib/command/tmpServer.js +41 -0
  27. package/lib/command/tmpTraffic/tmpTraffic.d.ts +2 -0
  28. package/lib/command/tmpTraffic/tmpTraffic.js +15 -0
  29. package/lib/command/tmpTraffic/tmpTrafficMap.d.ts +3 -0
  30. package/lib/command/tmpTraffic/tmpTrafficMap.js +167 -0
  31. package/lib/command/tmpTraffic/tmpTrafficText.d.ts +2 -0
  32. package/lib/command/tmpTraffic/tmpTrafficText.js +58 -0
  33. package/lib/command/tmpVersion.d.ts +2 -0
  34. package/lib/command/tmpVersion.js +14 -0
  35. package/lib/command/tmpVtc.js +29 -0
  36. package/lib/database/guildBind.d.ts +15 -0
  37. package/lib/database/guildBind.js +41 -0
  38. package/lib/database/model.d.ts +2 -0
  39. package/lib/database/model.js +65 -0
  40. package/lib/database/translateCache.d.ts +14 -0
  41. package/lib/database/translateCache.js +31 -0
  42. package/lib/index.d.ts +14 -0
  43. package/lib/index.js +75 -0
  44. package/lib/resource/dlc.html +115 -0
  45. package/lib/resource/mileage-leaderboard.html +363 -0
  46. package/lib/resource/package/SEGUIEMJ.TTF +0 -0
  47. package/lib/resource/package/leaflet/heatmap.min.js +9 -0
  48. package/lib/resource/package/leaflet/leaflet-heatmap.js +246 -0
  49. package/lib/resource/package/leaflet/leaflet.min.css +1 -0
  50. package/lib/resource/package/leaflet/leaflet.min.js +1 -0
  51. package/lib/resource/position.html +223 -0
  52. package/lib/resource/query.html +363 -0
  53. package/lib/resource/traffic.html +204 -0
  54. package/lib/util/baiduTranslate.d.ts +2 -0
  55. package/lib/util/baiduTranslate.js +30 -0
  56. package/lib/util/common.d.ts +1 -0
  57. package/lib/util/common.js +5 -0
  58. package/lib/util/constant.d.ts +8 -0
  59. package/lib/util/constant.js +16 -0
  60. package/package.json +3 -3
@@ -0,0 +1,167 @@
1
+ const truckyAppApi = require('../../api/truckyAppApi');
2
+ const evmOpenApi = require('../../api/evmOpenApi');
3
+ const baiduTranslate = require('../../util/baiduTranslate');
4
+ const { resolve } = require("path");
5
+ const common = require("../../util/common");
6
+ const { segment } = require("koishi");
7
+ /**
8
+ * 服务器别名
9
+ */
10
+ const serverAlias = {
11
+ 's1': {
12
+ name: 'sim1',
13
+ mapType: 'ets',
14
+ serverId: 2,
15
+ bounds: [[-94189, 93775], [79264, -78999]]
16
+ },
17
+ 's2': {
18
+ name: 'sim2',
19
+ mapType: 'ets',
20
+ serverId: 41,
21
+ bounds: [[-94189, 93775], [79264, -78999]]
22
+ },
23
+ 'p': {
24
+ name: 'eupromods1',
25
+ mapType: 'promods',
26
+ serverId: 50,
27
+ bounds: [[-96355, 16381], [205581, -70750]]
28
+ },
29
+ 'a': {
30
+ name: 'arc1',
31
+ mapType: 'ets',
32
+ serverId: 7,
33
+ bounds: [[-94189, 93775], [79264, -78999]]
34
+ }
35
+ };
36
+ /**
37
+ * 路况程度转中文
38
+ */
39
+ const severityToZh = {
40
+ 'Fluid': {
41
+ text: '畅通',
42
+ color: '#00d26a'
43
+ },
44
+ 'Moderate': {
45
+ text: '正常',
46
+ color: '#ff6723'
47
+ },
48
+ 'Congested': {
49
+ text: '缓慢',
50
+ color: '#f8312f'
51
+ },
52
+ 'Heavy': {
53
+ text: '拥堵',
54
+ color: '#8d67c5'
55
+ }
56
+ };
57
+ /**
58
+ * 位置类型转中文
59
+ */
60
+ const typeToZh = {
61
+ 'City': '城市',
62
+ 'Road': '公路',
63
+ 'Intersection': '十字路口'
64
+ };
65
+ /**
66
+ * 查询路况
67
+ */
68
+ module.exports = async (ctx, cfg, serverName) => {
69
+ if (!ctx.puppeteer) {
70
+ return '未启用 puppeteer 服务';
71
+ }
72
+ // 根据别名获取服务器信息
73
+ let serverInfo = serverAlias[serverName];
74
+ if (!serverInfo) {
75
+ return '请输入正确的服务器名称 (s1, s2, p, a)';
76
+ }
77
+ // 查询路况信息
78
+ let trafficData = await truckyAppApi.trafficTop(ctx.http, serverInfo.name);
79
+ if (trafficData.error) {
80
+ return '查询路况信息失败';
81
+ }
82
+ // 查询地图玩家数据
83
+ let mapData = await evmOpenApi.mapPlayerList(ctx.http, serverInfo.serverId, serverInfo.bounds[0][0], serverInfo.bounds[0][1], serverInfo.bounds[1][0], serverInfo.bounds[1][1]);
84
+
85
+ switch (serverName) {
86
+ case 's1':
87
+ case 's2':
88
+ case 'a': {
89
+ // 使用块级作用域包裹,避免变量重复声明
90
+ // 构建路况数据
91
+ let data = {
92
+ mapType: serverInfo.mapType,
93
+ trafficList: [],
94
+ playerCoordinateList: mapData.error && mapData.data ? [] : mapData.data.map(item => [item.axisX, item.axisY])
95
+ };
96
+ for (const traffic of trafficData.data) {
97
+ data.trafficList.push({
98
+ country: await baiduTranslate(ctx, cfg, traffic.country),
99
+ province: await baiduTranslate(ctx, cfg, traffic.name.substring(0, traffic.name.lastIndexOf('(') - 1)),
100
+ playerCount: traffic.players,
101
+ severity: severityToZh[traffic.newSeverity] || { text: '未知', color: '#ffffff' }
102
+ });
103
+ }
104
+ let page;
105
+ try {
106
+ page = await ctx.puppeteer.page();
107
+ await page.setViewport({ width: 1000, height: 1000 });
108
+ await page.goto(`file:///${resolve(__dirname, '../../resource/traffic.html')}`);
109
+ await page.evaluate(`setData(${JSON.stringify(data)})`);
110
+ await common.sleep(100);
111
+ await page.waitForNetworkIdle();
112
+ const element = await page.$("#container");
113
+ return (segment.image(await element.screenshot({
114
+ encoding: "binary"
115
+ }), "image/jpg"));
116
+ }
117
+ catch {
118
+ return '渲染异常,请重试';
119
+ }
120
+ finally {
121
+ if (page) {
122
+ await page.close();
123
+ }
124
+ }
125
+ break;
126
+ }
127
+ case 'p': {
128
+ // 使用块级作用域包裹,避免变量重复声明
129
+ // 构建路况数据
130
+ let data = {
131
+ mapType: serverInfo.mapType,
132
+ trafficList: [],
133
+ playerCoordinateList: mapData.error && mapData.data ? [] : mapData.data.map(item => [item.axisX, item.axisY])
134
+ };
135
+ for (const traffic of trafficData.data) {
136
+ data.trafficList.push({
137
+ country: await baiduTranslate(ctx, cfg, traffic.country),
138
+ province: await baiduTranslate(ctx, cfg, traffic.name.substring(0, traffic.name.lastIndexOf('(') - 1)),
139
+ playerCount: traffic.players,
140
+ severity: severityToZh[traffic.newSeverity] || { text: '未知', color: '#ffffff' }
141
+ });
142
+ }
143
+ let page;
144
+ try {
145
+ page = await ctx.puppeteer.page();
146
+ await page.setViewport({ width: 1200, height: 1200 });
147
+ await page.goto(`file:///${resolve(__dirname, '../../resource/traffic.html')}`);
148
+ await page.evaluate(`setData(${JSON.stringify(data)})`);
149
+ await common.sleep(100);
150
+ await page.waitForNetworkIdle();
151
+ const element = await page.$("#container");
152
+ return (segment.image(await element.screenshot({
153
+ encoding: "binary"
154
+ }), "image/jpg"));
155
+ }
156
+ catch {
157
+ return '渲染异常,请重试';
158
+ }
159
+ finally {
160
+ if (page) {
161
+ await page.close();
162
+ }
163
+ }
164
+ break;
165
+ }
166
+ }
167
+ };
@@ -0,0 +1,2 @@
1
+ declare function _exports(ctx: any, cfg: any, serverName: any): Promise<string>;
2
+ export = _exports;
@@ -0,0 +1,58 @@
1
+ const truckyAppApi = require('../../api/truckyAppApi');
2
+ const baiduTranslate = require('../../util/baiduTranslate');
3
+ /**
4
+ * 服务器别名
5
+ */
6
+ const serverNameAlias = {
7
+ 's1': 'sim1',
8
+ 's2': 'sim2',
9
+ 'p': 'eupromods1',
10
+ 'a': 'arc1'
11
+ };
12
+ /**
13
+ * 路况程度转中文
14
+ */
15
+ const severityToZh = {
16
+ 'Fluid': '🟢畅通',
17
+ 'Moderate': '🟠正常',
18
+ 'Congested': '🔴缓慢',
19
+ 'Heavy': '🟣拥堵'
20
+ };
21
+ /**
22
+ * 位置类型转中文
23
+ */
24
+ const typeToZh = {
25
+ 'City': '城市',
26
+ 'Road': '公路',
27
+ 'Intersection': '十字路口'
28
+ };
29
+ /**
30
+ * 查询路况
31
+ */
32
+ module.exports = async (ctx, cfg, serverName) => {
33
+ // 转换服务器别名
34
+ let serverQueryName = serverNameAlias[serverName];
35
+ if (!serverQueryName) {
36
+ return '请输入正确的服务器名称 (s1, s2, p, a)';
37
+ }
38
+ let trafficData = await truckyAppApi.trafficTop(ctx.http, serverQueryName);
39
+ if (trafficData.error) {
40
+ return '查询路况信息失败';
41
+ }
42
+ // 构建消息
43
+ let message = '';
44
+ for (const traffic of trafficData.data) {
45
+ // 如果已有内容,换行
46
+ if (message) {
47
+ message += '\n\n';
48
+ }
49
+ message += await baiduTranslate(ctx, cfg, traffic.country);
50
+ message += ' - ';
51
+ let name = traffic.name.substring(0, traffic.name.lastIndexOf('(') - 1);
52
+ let type = traffic.name.substring(traffic.name.lastIndexOf('(') + 1, traffic.name.lastIndexOf(')'));
53
+ message += await baiduTranslate(ctx, cfg, name) + ` (${typeToZh[type] || type})`;
54
+ message += '\n路况: ' + (severityToZh[traffic.newSeverity] || traffic.color);
55
+ message += ' | 人数: ' + traffic.players;
56
+ }
57
+ return message;
58
+ };
@@ -0,0 +1,2 @@
1
+ declare function _exports(ctx: any): Promise<string>;
2
+ export = _exports;
@@ -0,0 +1,14 @@
1
+ const truckersMpApi = require("../api/truckersMpApi");
2
+ module.exports = async (ctx) => {
3
+ // 查询版本信息
4
+ let result = await truckersMpApi.version(ctx.http);
5
+ if (result.error) {
6
+ return '查询失败,请稍后再试';
7
+ }
8
+ // 构建消息返回
9
+ let message = '';
10
+ message += `TMP版本:${result.data.name}\n`;
11
+ message += `欧卡支持版本: ${result.data.supported_game_version}\n`;
12
+ message += `美卡支持版本: ${result.data.supported_ats_game_version}`;
13
+ return message;
14
+ };
@@ -0,0 +1,29 @@
1
+ const truckersMpApi = require('../api/truckersMpApi')
2
+
3
+ /**
4
+ * 查询玩家信息
5
+ */
6
+ module.exports = async (ctx, cfg, session, vtcid) => {
7
+ if (!vtcid || isNaN(vtcid)) {
8
+ return `请输入正确的vtc编号`
9
+ }
10
+
11
+ // 查询玩家信息
12
+ let vtcInfo = await truckersMpApi.vtc(ctx.http, vtcid)
13
+ if (vtcInfo.error) {
14
+ return '查询vtc信息失败,请重试'
15
+ }
16
+
17
+ // 拼接消息模板
18
+ let message = ''
19
+ message += `<img src="${vtcInfo.data.logo}"/>\n`
20
+ message += '🆔VTC编号: ' + vtcInfo.data.id
21
+ message += '\n📑VTC名称: ' + vtcInfo.data.name
22
+ message += '\n📑VTC所有者id: ' + vtcInfo.data.owner_id
23
+ message += '\n📑VTC所有者名称: ' + vtcInfo.data.owner_username
24
+ message += '\n📑VTC创建日期: ' + vtcInfo.data.created + `(UTC)`
25
+ message += '\n🎮VTC人数: ' + vtcInfo.data.members_count
26
+ message += '\n🎮VTC前缀: ' + vtcInfo.data.tag
27
+ message += `\n💼VTC主页: ${vtcInfo.data.website}`
28
+ return message
29
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 获取绑定信息
3
+ * @param db 数据源
4
+ * @param platform 平台
5
+ * @param userId 用户编号
6
+ */
7
+ export function get(db: any, platform: any, userId: any): Promise<any>;
8
+ /**
9
+ * 新增或更新绑定信息
10
+ * @param db 数据源
11
+ * @param platform 平台
12
+ * @param userId 用户编号
13
+ * @param tmpId TMP ID
14
+ */
15
+ export function saveOrUpdate(db: any, platform: any, userId: any, tmpId: any): void;
@@ -0,0 +1,41 @@
1
+ module.exports = {
2
+ /**
3
+ * 获取绑定信息
4
+ * @param db 数据源
5
+ * @param platform 平台
6
+ * @param userId 用户编号
7
+ */
8
+ async get(db, platform, userId) {
9
+ const guildBindList = await db.get('tmp_guild_bind', {
10
+ platform,
11
+ user_id: userId
12
+ });
13
+ if (guildBindList && guildBindList.length > 0) {
14
+ return guildBindList[0];
15
+ }
16
+ return null;
17
+ },
18
+ /**
19
+ * 新增或更新绑定信息
20
+ * @param db 数据源
21
+ * @param platform 平台
22
+ * @param userId 用户编号
23
+ * @param tmpId TMP ID
24
+ */
25
+ saveOrUpdate(db, platform, userId, tmpId) {
26
+ this.get(db, platform, userId).then((data) => {
27
+ if (data) {
28
+ db.set('tmp_guild_bind', data.id, {
29
+ tmp_id: tmpId
30
+ });
31
+ }
32
+ else {
33
+ db.create('tmp_guild_bind', {
34
+ platform: platform,
35
+ user_id: userId,
36
+ tmp_id: tmpId
37
+ });
38
+ }
39
+ });
40
+ }
41
+ };
@@ -0,0 +1,2 @@
1
+ declare function _exports(ctx: any): void;
2
+ export = _exports;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * 数据表声明
3
+ */
4
+ const modelArray = {
5
+ tmp_guild_bind: {
6
+ id: {
7
+ type: 'unsigned',
8
+ length: 10,
9
+ nullable: false,
10
+ comment: '主键'
11
+ },
12
+ platform: {
13
+ type: 'string',
14
+ length: 50,
15
+ nullable: false,
16
+ comment: '所属平台'
17
+ },
18
+ user_id: {
19
+ type: 'string',
20
+ length: 50,
21
+ nullable: false,
22
+ comment: '用户编号'
23
+ },
24
+ tmp_id: {
25
+ type: 'unsigned',
26
+ length: 50,
27
+ nullable: false,
28
+ comment: 'TMP ID'
29
+ }
30
+ },
31
+ tmp_translate_cache: {
32
+ id: {
33
+ type: 'unsigned',
34
+ length: 10,
35
+ nullable: false,
36
+ comment: '主键'
37
+ },
38
+ content: {
39
+ type: 'string',
40
+ nullable: false,
41
+ length: 200,
42
+ comment: '原文文本'
43
+ },
44
+ content_md5: {
45
+ type: 'string',
46
+ nullable: false,
47
+ length: 32,
48
+ comment: '原文文本md5'
49
+ },
50
+ translate_content: {
51
+ type: 'string',
52
+ nullable: false,
53
+ length: 200,
54
+ comment: '翻译文本'
55
+ }
56
+ }
57
+ };
58
+ /**
59
+ * 初始化数据库
60
+ */
61
+ module.exports = (ctx) => {
62
+ for (let modelName in modelArray) {
63
+ ctx.model.extend(modelName, modelArray[modelName], { autoInc: true });
64
+ }
65
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 查询翻译
3
+ * @param db 数据源
4
+ * @param contentMd5 文本MD5
5
+ */
6
+ export function getTranslate(db: any, contentMd5: any): Promise<any>;
7
+ /**
8
+ * 保存翻译缓存信息
9
+ * @param db 数据源
10
+ * @param contentMd5 原文文本MD5
11
+ * @param content 原文文本
12
+ * @param translateContent 翻译文本
13
+ */
14
+ export function save(db: any, contentMd5: any, content: any, translateContent: any): void;
@@ -0,0 +1,31 @@
1
+ module.exports = {
2
+ /**
3
+ * 查询翻译
4
+ * @param db 数据源
5
+ * @param contentMd5 文本MD5
6
+ */
7
+ async getTranslate(db, contentMd5) {
8
+ const translateCacheList = await db.get('tmp_translate_cache', {
9
+ content_md5: contentMd5
10
+ });
11
+ // 如果查询到了缓存,直接返回翻译文本
12
+ if (translateCacheList && translateCacheList.length > 0) {
13
+ return translateCacheList[0].translate_content;
14
+ }
15
+ return null;
16
+ },
17
+ /**
18
+ * 保存翻译缓存信息
19
+ * @param db 数据源
20
+ * @param contentMd5 原文文本MD5
21
+ * @param content 原文文本
22
+ * @param translateContent 翻译文本
23
+ */
24
+ save(db, contentMd5, content, translateContent) {
25
+ db.create('tmp_translate_cache', {
26
+ content,
27
+ content_md5: contentMd5,
28
+ translate_content: translateContent
29
+ });
30
+ }
31
+ };
package/lib/index.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { Context, Schema } from 'koishi';
2
+ export declare const name = "tmp-bot";
3
+ export declare const inject: {
4
+ required: string[];
5
+ optional: string[];
6
+ };
7
+ export interface Config {
8
+ baiduTranslateEnable: boolean;
9
+ baiduTranslateAppId: string;
10
+ baiduTranslateKey: string;
11
+ baiduTranslateCacheEnable: boolean;
12
+ }
13
+ export declare const Config: Schema<Config>;
14
+ export declare function apply(ctx: Context, cfg: Config): void;
package/lib/index.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Config = exports.inject = exports.name = void 0;
4
+ exports.apply = apply;
5
+ const koishi_1 = require("koishi");
6
+ const model = require('./database/model');
7
+ const { MileageRankingType } = require('./util/constant');
8
+ const tmpQuery = require('./command/tmpQuery/tmpQuery');
9
+ const tmpServer = require('./command/tmpServer');
10
+ const tmpBind = require('./command/tmpBind');
11
+ const tmpTraffic = require('./command/tmpTraffic/tmpTraffic');
12
+ const tmpPosition = require('./command/tmpPosition');
13
+ const tmpVersion = require('./command/tmpVersion');
14
+ const tmpDlcMap = require('./command/tmpDlcMap');
15
+ const tmpMileageRanking = require('./command/tmpMileageRanking');
16
+ const resetPassword = require('./command/ets-app/resetPassword');
17
+ const queryPoint = require('./command/ets-app/queryPoint');
18
+ const tmpVtc = require('./command/tmpVtc');
19
+
20
+ exports.name = 'tmp-bot';
21
+ exports.inject = {
22
+ required: ['database'],
23
+ optional: ['puppeteer']
24
+ };
25
+ exports.Config = koishi_1.Schema.intersect([
26
+ koishi_1.Schema.object({
27
+ baiduTranslateEnable: koishi_1.Schema.boolean().default(false).description('启用百度翻译'),
28
+ baiduTranslateAppId: koishi_1.Schema.string().description('百度翻译APP ID'),
29
+ baiduTranslateKey: koishi_1.Schema.string().description('百度翻译秘钥'),
30
+ baiduTranslateCacheEnable: koishi_1.Schema.boolean().default(false).description('启用百度翻译缓存')
31
+ }).description('基本配置'),
32
+ koishi_1.Schema.object({
33
+ queryShowAvatarEnable: koishi_1.Schema.boolean().default(false).description('查询指令展示头像,部分玩家的擦边头像可能导致封号'),
34
+ tmpTrafficType: koishi_1.Schema.union([
35
+ koishi_1.Schema.const(1).description('文字'),
36
+ koishi_1.Schema.const(2).description('热力图')
37
+ ]).default(1).description('路况信息展示方式'),
38
+ tmpQueryType: koishi_1.Schema.union([
39
+ koishi_1.Schema.const(1).description('文字'),
40
+ koishi_1.Schema.const(2).description('图片')
41
+ ]).default(1).description('玩家信息展示方式'),
42
+ }).description('指令配置'),
43
+ koishi_1.Schema.object({
44
+ mainSettings: koishi_1.Schema.object({
45
+ url: koishi_1.Schema.string().description("API服务器地址").required(),
46
+ token: koishi_1.Schema.string().description("API认证令牌").required(),
47
+ logOutput: koishi_1.Schema.boolean().description("是否输出日志").default(true)
48
+ }).description("车队平台设置")
49
+ }),
50
+ koishi_1.Schema.object({
51
+ resetPassword: koishi_1.Schema.object({
52
+ adminUsers: koishi_1.Schema.array(koishi_1.Schema.string()).description("管理员用户ID(拥有重置任意teamId权限)").default([])
53
+ }).description("重置密码设置")
54
+ }),
55
+ ]);
56
+ function apply(ctx, cfg) {
57
+ // 初始化数据表
58
+ model(ctx);
59
+ // 注册指令
60
+ ctx.command('查询 <tmpId>').action(async ({ session }, tmpId) => await tmpQuery(ctx, cfg, session, tmpId));
61
+ ctx.command('美卡服务器').action(async () => await tmpServer(ctx, cfg, 'ATS'));
62
+ ctx.command('欧卡服务器').action(async () => await tmpServer(ctx, cfg, 'ETS2'));
63
+ ctx.command('绑定 <tmpId>').action(async ({ session }, tmpId) => await tmpBind(ctx, cfg, session, tmpId));
64
+ ctx.command('路况 <serverName>').action(async ({ session }, serverName) => await tmpTraffic(ctx, cfg, serverName));
65
+ ctx.command('定位 <tmpId>').action(async ({ session }, tmpId) => await tmpPosition(ctx, cfg, session, tmpId));
66
+ ctx.command('tmp版本').action(async () => await tmpVersion(ctx));
67
+ ctx.command('地图dlc价格').action(async ({ session }) => await tmpDlcMap(ctx, session));
68
+ ctx.command('里程排行榜').action(async ({ session }) => await tmpMileageRanking(ctx, session, MileageRankingType.total));
69
+ ctx.command('今日里程排行榜').action(async ({ session }) => await tmpMileageRanking(ctx, session, MileageRankingType.today));
70
+
71
+ ctx.command('vtc查询 <vtcid>').action(async ({ session }, vtcid) => await tmpVtc(ctx, cfg, session, vtcid));
72
+ ctx.command(`重置密码 [targetTeamId:string]`, "重置欧卡车队平台密码").usage("重置自己的密码,或管理员重置指定teamId的密码").example(`重置密码new - 重置自己的密码`).example(`重置密码new 123 - 管理员重置指定teamId的密码`).action(async ({ session }, targetTeamId) => await resetPassword(ctx, cfg, session, targetTeamId));
73
+ ctx.command(`查询积分 [targetQQ:string]`, "查询欧卡车队平台积分").usage("查询自己或指定QQ号的积分,在群聊中可@他人查询").example(`查询积分 - 查询自己的积分`).example(`查询积分 - 查询指定QQ号的积分`).action(async ({ session }, targetQQ) => await queryPoint(ctx, cfg, session, targetQQ));
74
+ ctx.command('规则查询').action(async ({ session }) => { return 'https://truckersmp.com/knowledge-base/article/746' })
75
+ }
@@ -0,0 +1,115 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>DLC</title>
6
+ <style>
7
+ #dlc-info-container {
8
+ width: 600px;
9
+ background-color: #222d33;
10
+ padding: 14px;
11
+ }
12
+
13
+ .dlc-box {
14
+ display: flex;
15
+ flex-direction: row;
16
+ box-sizing: border-box;
17
+ padding: 12px;
18
+ margin-top: 12px;
19
+ background-size: cover;
20
+ background-repeat: no-repeat;
21
+ background-position: center;
22
+ }
23
+ .dlc-box:nth-of-type(1) {
24
+ margin-top: 0;
25
+ }
26
+
27
+ .dlc-box .header-image {
28
+ width: 210px;
29
+ display: inline-block;
30
+ }
31
+
32
+ .dlc-box .dlc-info {
33
+ flex: 1;
34
+ width: 0;
35
+ //border: 1px solid red;
36
+ box-sizing: border-box;
37
+ padding: 2px 12px;
38
+ }
39
+ .dlc-info .name {
40
+ color: #ffffff;
41
+ font-size: 18px;
42
+ font-weight: 600;
43
+ overflow: hidden;
44
+ text-overflow: ellipsis;
45
+ white-space: nowrap;
46
+ }
47
+ .dlc-info .desc {
48
+ color: #e5e5e5;
49
+ font-size: 14px;
50
+ overflow: hidden;
51
+ text-overflow: ellipsis;
52
+ display: -webkit-box;
53
+ -webkit-line-clamp: 2;
54
+ -webkit-box-orient: vertical;
55
+ }
56
+ .dlc-info .price-box {
57
+ margin-top: 8px;
58
+ }
59
+
60
+ .dlc-info .price-box span {
61
+ display: inline-block;
62
+ color: #BEEE11;
63
+ font-size: 16px;
64
+ }
65
+ .dlc-info .price-box .discount-price {
66
+ color: #cbcbcb;
67
+ text-decoration: line-through;
68
+ }
69
+ .dlc-info .price-box .discount {
70
+ font-size: 14px;
71
+ color: #BEEE11;
72
+ background-color: #4c6b22;
73
+ padding: 2px 6px;
74
+ margin-left: 4px;
75
+ }
76
+ </style>
77
+ </head>
78
+ <body>
79
+ <div id="dlc-info-container">
80
+ </div>
81
+
82
+ <script>
83
+ function setData(dlcList) {
84
+ // 遍历渲染DLC列表
85
+ for (let dlc of dlcList) {
86
+ let dom = document.createElement(`div`);
87
+ dom.className = 'dlc-box';
88
+ dom.style.backgroundImage = `url('${dlc.backgroundImageUrl}')`;
89
+
90
+ let priceDiscountDom = ''
91
+ if (dlc.discount > 0) {
92
+ priceDiscountDom = `
93
+ <span class="discount-price">¥${Math.ceil(dlc.originalPrice / 100)}</span>
94
+ <span class="discount">-${dlc.discount}%</span>
95
+ `;
96
+ }
97
+
98
+ dom.innerHTML = `
99
+ <img class="header-image" src="${dlc.headerImageUrl}"/>
100
+ <div class="dlc-info">
101
+ <div class="name">${dlc.name}</div>
102
+ <div class="desc">${dlc.desc}</div>
103
+ <div class="price-box">
104
+ <span>¥${Math.ceil(dlc.finalPrice / 100)}</span>
105
+ ${priceDiscountDom}
106
+ </div>
107
+ </div>
108
+ `;
109
+
110
+ document.querySelector('#dlc-info-container').appendChild(dom);
111
+ }
112
+ }
113
+ </script>
114
+ </body>
115
+ </html>