koishi-plugin-ets2-tools-tmp 3.0.6 → 3.1.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/command/tmpActivityService/tmpActivityServiceV1.js +14 -4
- package/lib/command/tmpActivityService/tmpActivityServiceV2.js +14 -4
- package/lib/command/tmpActivityService.js +10 -5
- package/lib/command/tmpFootprint.js +3 -3
- package/lib/command/tmpQuery/tmpQueryImg.js +92 -2
- package/lib/command/tmpQuery/tmpQueryText.js +8 -1
- package/lib/index.js +7 -7
- package/lib/resource/query.html +651 -244
- package/package.json +1 -1
|
@@ -57,15 +57,25 @@ module.exports = {
|
|
|
57
57
|
|
|
58
58
|
if (response.code === 0 && response.data) {
|
|
59
59
|
const enableAutoClock = response.data.enableAutoClock;
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const serverId = response.data.serverId;
|
|
61
|
+
this.logger.debug(`活动 "${activity.themeName}" V1自动打卡状态: ${enableAutoClock}, serverId: ${serverId}`);
|
|
62
|
+
|
|
63
|
+
if (enableAutoClock === 1) {
|
|
64
|
+
if (serverId != null) {
|
|
65
|
+
return { status: 'set', message: '今日活动自动打卡已设置' };
|
|
66
|
+
} else {
|
|
67
|
+
return { status: 'no_server', message: '今日活动打卡服务器未设置' };
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
return { status: 'not_set', message: '今日活动打卡未设置' };
|
|
71
|
+
}
|
|
62
72
|
} else {
|
|
63
73
|
this.logger.error(`V1活动详情API返回错误: ${response.msg || '未知错误'} (代码: ${response.code || '无'})`);
|
|
64
|
-
return
|
|
74
|
+
return { status: 'not_set', message: '今日活动打卡未设置' };
|
|
65
75
|
}
|
|
66
76
|
} catch (error) {
|
|
67
77
|
this.logger.error(`检查V1活动 "${activity.themeName}" 自动打卡状态失败:`, error.message);
|
|
68
|
-
return
|
|
78
|
+
return { status: 'not_set', message: '今日活动打卡未设置' };
|
|
69
79
|
}
|
|
70
80
|
}
|
|
71
81
|
};
|
|
@@ -71,15 +71,25 @@ module.exports = {
|
|
|
71
71
|
|
|
72
72
|
if (response.code === 200 && response.data) {
|
|
73
73
|
const autoCheckInEnable = response.data.autoCheckInEnable;
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const serverId = response.data.serverId;
|
|
75
|
+
this.logger.debug(`活动 "${activity.themeName}" V2自动打卡状态: ${autoCheckInEnable}, serverId: ${serverId}`);
|
|
76
|
+
|
|
77
|
+
if (autoCheckInEnable === 1) {
|
|
78
|
+
if (serverId != null) {
|
|
79
|
+
return { status: 'set', message: '今日活动自动打卡已设置' };
|
|
80
|
+
} else {
|
|
81
|
+
return { status: 'no_server', message: '今日活动打卡服务器未设置' };
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
return { status: 'not_set', message: '今日活动打卡未设置' };
|
|
85
|
+
}
|
|
76
86
|
} else {
|
|
77
87
|
this.logger.error(`V2活动详情API返回错误: ${response.msg || '未知错误'} (代码: ${response.code || '无'})`);
|
|
78
|
-
return
|
|
88
|
+
return { status: 'not_set', message: '今日活动打卡未设置' };
|
|
79
89
|
}
|
|
80
90
|
} catch (error) {
|
|
81
91
|
this.logger.error(`检查V2活动 "${activity.themeName}" 自动打卡状态失败:`, error.message);
|
|
82
|
-
return
|
|
92
|
+
return { status: 'not_set', message: '今日活动打卡未设置' };
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
95
|
};
|
|
@@ -620,13 +620,18 @@ class ActivityService {
|
|
|
620
620
|
|
|
621
621
|
for (const activity of this.todayActivities) {
|
|
622
622
|
try {
|
|
623
|
-
const
|
|
623
|
+
const autoClockResult = await this.checkAutoClock(activity);
|
|
624
624
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
625
|
+
let message;
|
|
626
|
+
if (autoClockResult.status === 'set') {
|
|
627
|
+
message = `今日活动自动打卡已设置`;
|
|
628
|
+
} else if (autoClockResult.status === 'no_server') {
|
|
629
|
+
message = `请注意,今日活动打卡服务器未设置。\n 活动名称: ${activity.themeName || '未知活动'}`;
|
|
630
|
+
} else {
|
|
631
|
+
message = `请注意,今日活动打卡未设置。\n 活动名称: ${activity.themeName || '未知活动'}`;
|
|
632
|
+
}
|
|
628
633
|
|
|
629
|
-
this.logger.message(`自动打卡检查: "${activity.themeName || '未知活动'}" - ${
|
|
634
|
+
this.logger.message(`自动打卡检查: "${activity.themeName || '未知活动'}" - ${autoClockResult.message}`);
|
|
630
635
|
|
|
631
636
|
for (const groupId of this.cfg.admin.groups) {
|
|
632
637
|
try {
|
|
@@ -68,7 +68,7 @@ module.exports = async (ctx, session, serverType, tmpId, date) => {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (date === 'tenday') {
|
|
71
|
-
startTime = dayjs().subtract(
|
|
71
|
+
startTime = dayjs().subtract(7, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss');
|
|
72
72
|
endTime = dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss');
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -98,8 +98,8 @@ module.exports = async (ctx, session, serverType, tmpId, date) => {
|
|
|
98
98
|
if (date === 'today') {
|
|
99
99
|
return `今日暂无数据`;
|
|
100
100
|
}
|
|
101
|
-
if (date === '
|
|
102
|
-
return
|
|
101
|
+
if (date === 'sevenday') {
|
|
102
|
+
return `近七日暂无数据`;
|
|
103
103
|
}
|
|
104
104
|
if (date === 'lastMonth') {
|
|
105
105
|
return `上月暂无数据`;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const dayjs = require('dayjs');
|
|
2
|
+
const dayjsRelativeTime = require('dayjs/plugin/relativeTime');
|
|
3
|
+
const dayjsLocaleZhCn = require('dayjs/locale/zh-cn');
|
|
2
4
|
const guildBind = require('../../database/guildBind');
|
|
3
5
|
const truckyAppApi = require('../../api/truckyAppApi');
|
|
4
6
|
const evmOpenApi = require('../../api/evmOpenApi');
|
|
@@ -6,6 +8,8 @@ const baiduTranslate = require('../../util/baiduTranslate');
|
|
|
6
8
|
const { resolve } = require("path");
|
|
7
9
|
const common = require("../../util/common");
|
|
8
10
|
const { segment } = require("koishi");
|
|
11
|
+
dayjs.extend(dayjsRelativeTime);
|
|
12
|
+
dayjs.locale(dayjsLocaleZhCn);
|
|
9
13
|
/**
|
|
10
14
|
* 用户组
|
|
11
15
|
*/
|
|
@@ -21,6 +25,7 @@ const userGroup = {
|
|
|
21
25
|
* 查询玩家信息
|
|
22
26
|
*/
|
|
23
27
|
module.exports = async (ctx, cfg, session, tmpId) => {
|
|
28
|
+
const { vtcId } = cfg.tmpActivityService?.api || {};
|
|
24
29
|
if (!ctx.puppeteer) {
|
|
25
30
|
return '未启用 puppeteer 服务';
|
|
26
31
|
}
|
|
@@ -50,27 +55,36 @@ module.exports = async (ctx, cfg, session, tmpId) => {
|
|
|
50
55
|
data.tmpId = playerInfo.data.tmpId;
|
|
51
56
|
data.name = playerInfo.data.name;
|
|
52
57
|
data.steamId = playerInfo.data.steamId;
|
|
53
|
-
|
|
58
|
+
let registerDate = dayjs(playerInfo.data.registerTime);
|
|
59
|
+
data.registerDate = registerDate.format('YYYY年MM月DD日');
|
|
60
|
+
data.registerDays = dayjs().diff(registerDate, 'day');
|
|
54
61
|
data.avatarUrl = playerInfo.data.avatarUrl;
|
|
55
62
|
data.groupColor = playerInfo.data.groupColor;
|
|
56
63
|
data.groupName = (userGroup[playerInfo.data.groupName] || playerInfo.data.groupName);
|
|
57
64
|
data.isJoinVtc = playerInfo.data.isJoinVtc;
|
|
58
65
|
data.vtcName = playerInfo.data.vtcName;
|
|
59
66
|
data.vtcRole = playerInfo.data.vtcRole;
|
|
67
|
+
data.vtcHistory = playerInfo.data.vtcHistory || [];
|
|
60
68
|
data.isSponsor = playerInfo.data.isSponsor;
|
|
61
69
|
data.sponsorAmount = playerInfo.data.sponsorAmount;
|
|
62
70
|
data.sponsorCumulativeAmount = playerInfo.data.sponsorCumulativeAmount;
|
|
63
71
|
data.sponsorHide = playerInfo.data.sponsorHide;
|
|
72
|
+
data.mileage = playerInfo.data.mileage;
|
|
73
|
+
data.todayMileage = playerInfo.data.todayMileage;
|
|
64
74
|
data.isOnline = false;
|
|
75
|
+
data.onlineStatus = '离线';
|
|
65
76
|
if (playerMapInfo && !playerMapInfo.error) {
|
|
66
77
|
data.isOnline = playerMapInfo.data.online;
|
|
67
78
|
if (data.isOnline) {
|
|
79
|
+
data.onlineStatus = '在线';
|
|
68
80
|
data.onlineServerName = playerMapInfo.data.serverDetails.name;
|
|
69
81
|
data.onlineCountry = await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.country);
|
|
70
82
|
data.onlineCity = await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.realName);
|
|
71
83
|
data.onlineX = playerMapInfo.data.x;
|
|
72
84
|
data.onlineY = playerMapInfo.data.y;
|
|
73
85
|
data.onlineMapType = playerMapInfo.data.serverDetails.id === 50 ? 'promods' : 'ets';
|
|
86
|
+
} else if (playerInfo.data.lastOnlineTime) {
|
|
87
|
+
data.lastOnlineTime = dayjs(playerInfo.data.lastOnlineTime).fromNow(false);
|
|
74
88
|
}
|
|
75
89
|
}
|
|
76
90
|
data.isBan = playerInfo.data.isBan;
|
|
@@ -79,10 +93,86 @@ module.exports = async (ctx, cfg, session, tmpId) => {
|
|
|
79
93
|
data.banReasonZh = playerInfo.data.banReasonZh;
|
|
80
94
|
data.banCount = playerInfo.data.banCount;
|
|
81
95
|
data.banHide = playerInfo.data.banHide;
|
|
96
|
+
// 查询VTC积分(仅主群/管理群显示)
|
|
97
|
+
data.rewardPoints = 0;
|
|
98
|
+
if (playerInfo.data.isJoinVtc && cfg.commands?.mainSettings) {
|
|
99
|
+
const mainGroups = cfg.tmpActivityService?.mainGroup?.groups || [];
|
|
100
|
+
const adminGroups = cfg.tmpActivityService?.admin?.groups || [];
|
|
101
|
+
const allowedGroups = [...new Set([...mainGroups, ...adminGroups])];
|
|
102
|
+
const currentGroupId = session.channelId || '';
|
|
103
|
+
const isInAllowedGroup = allowedGroups.some(g => currentGroupId.includes(g));
|
|
104
|
+
|
|
105
|
+
if (isInAllowedGroup && playerInfo.data.vtcId == vtcId) {
|
|
106
|
+
const { url, token, logOutput, platformVersion } = cfg.mainSettings?.settings || {};
|
|
107
|
+
const platform = (platformVersion || "v1").toLowerCase();
|
|
108
|
+
try {
|
|
109
|
+
if (platform === "v2") {
|
|
110
|
+
const baseUrl = url;
|
|
111
|
+
const userInfoUrl = `https://${baseUrl}/members/get?token=${token}&tmpId=${tmpId}`;
|
|
112
|
+
if (logOutput) {
|
|
113
|
+
ctx.logger.info(`[TMP_BOT] tmpQueryImg:开始查询TmpID ${tmpId} 的V2.0积分`);
|
|
114
|
+
ctx.logger.info(`[TMP_BOT] 请求V2.0用户信息: ${userInfoUrl}`);
|
|
115
|
+
}
|
|
116
|
+
const userInfoResponse = await ctx.http.get(userInfoUrl);
|
|
117
|
+
if (logOutput) {
|
|
118
|
+
ctx.logger.info(`[TMP_BOT] V2.0用户信息响应: ${JSON.stringify(userInfoResponse)}`);
|
|
119
|
+
}
|
|
120
|
+
if (userInfoResponse.code === 200 && userInfoResponse.data) {
|
|
121
|
+
data.rewardPoints = userInfoResponse.data.point || 0;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
if (logOutput) {
|
|
125
|
+
ctx.logger.info(`[TMP_BOT] tmpQueryImg:开始查询TmpID ${tmpId} 的V1.0积分`);
|
|
126
|
+
}
|
|
127
|
+
const userInfoUrl = `https://${url}/api/user/info/list?token=${token}&page=0&limit=7&tmpId=${tmpId}&tmpName=&teamId=&qq=&state=0&teamRole=`;
|
|
128
|
+
if (logOutput) {
|
|
129
|
+
ctx.logger.info(`[TMP_BOT] 请求V1.0用户信息: ${userInfoUrl}`);
|
|
130
|
+
}
|
|
131
|
+
const userInfoResponse = await ctx.http.post(userInfoUrl);
|
|
132
|
+
if (logOutput) {
|
|
133
|
+
ctx.logger.info(`[TMP_BOT] V1.0用户信息响应: ${JSON.stringify(userInfoResponse)}`);
|
|
134
|
+
}
|
|
135
|
+
const userList = userInfoResponse.page?.list || [];
|
|
136
|
+
const userInfo = userList[0];
|
|
137
|
+
data.rewardPoints = userInfo.rewardPoints || 0;
|
|
138
|
+
}
|
|
139
|
+
} catch (error) {
|
|
140
|
+
ctx.logger.error(`积分查询过程出错: ${error}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// 查询Steam游戏时长
|
|
145
|
+
data.ets2GameTime = null;
|
|
146
|
+
data.atsGameTime = null;
|
|
147
|
+
if (cfg.commands?.tmpQueryGameTime) {
|
|
148
|
+
try {
|
|
149
|
+
const steamApiKey = cfg.steamApi?.key;
|
|
150
|
+
if (steamApiKey) {
|
|
151
|
+
const steamId = playerInfo.data.steamId;
|
|
152
|
+
const url = `https://api.114512.xyz/steam/IPlayerService/GetOwnedGames/v1?key=${steamApiKey}&steamid=${steamId}&appids_filter[0]=227300&appids_filter[1]=270880&include_played_free_games=1`;
|
|
153
|
+
const response = await ctx.http.get(url);
|
|
154
|
+
if (response.response && response.response.game_count > 0) {
|
|
155
|
+
for (const game of response.response.games) {
|
|
156
|
+
const playtimeMinutes = game.playtime_forever;
|
|
157
|
+
const hours = Math.floor(playtimeMinutes / 60);
|
|
158
|
+
const minutes = playtimeMinutes % 60;
|
|
159
|
+
const playtime = `${hours}小时${minutes}分钟`;
|
|
160
|
+
if (game.appid === 227300) {
|
|
161
|
+
data.ets2GameTime = playtime;
|
|
162
|
+
} else if (game.appid === 270880) {
|
|
163
|
+
data.atsGameTime = playtime;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
ctx.logger.error(`查询Steam游戏时长出错: ${error}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
82
172
|
let page;
|
|
83
173
|
try {
|
|
84
174
|
page = await ctx.puppeteer.page();
|
|
85
|
-
await page.setViewport({ width:
|
|
175
|
+
await page.setViewport({ width: 520, height: 1000 });
|
|
86
176
|
await page.goto(`file:///${resolve(__dirname, '../../resource/query.html')}`);
|
|
87
177
|
await page.evaluate(`init(${JSON.stringify(data)})`);
|
|
88
178
|
await common.sleep(100);
|
|
@@ -81,7 +81,14 @@ module.exports = async (ctx, cfg, session, tmpId) => {
|
|
|
81
81
|
}
|
|
82
82
|
message += '\n🚚车队角色: ' + playerInfo.data.vtcRole;
|
|
83
83
|
if (cfg.commands?.mainSettings) {
|
|
84
|
-
|
|
84
|
+
// 仅在主群或管理群中显示车队积分
|
|
85
|
+
const mainGroups = cfg.tmpActivityService?.mainGroup?.groups || [];
|
|
86
|
+
const adminGroups = cfg.tmpActivityService?.admin?.groups || [];
|
|
87
|
+
const allowedGroups = [...new Set([...mainGroups, ...adminGroups])];
|
|
88
|
+
const currentGroupId = session.channelId || '';
|
|
89
|
+
const isInAllowedGroup = allowedGroups.some(g => currentGroupId.includes(g));
|
|
90
|
+
|
|
91
|
+
if (isInAllowedGroup && playerInfo.data.vtcId == vtcId) {
|
|
85
92
|
const { url, token, logOutput, platformVersion } = cfg.mainSettings?.settings || {};
|
|
86
93
|
const platform = (platformVersion || "v1").toLowerCase();
|
|
87
94
|
try {
|
package/lib/index.js
CHANGED
|
@@ -312,15 +312,15 @@ function registerBaseCommands(ctx, cfg) {
|
|
|
312
312
|
if (cfg.commands?.tmpFootprint) {
|
|
313
313
|
ctx.command('近十日足迹 [tmpId:string]')
|
|
314
314
|
.usage("查询ETS服务器今日足迹")
|
|
315
|
-
.example("
|
|
316
|
-
.example("
|
|
317
|
-
.action(async ({ session }, tmpId) => await commands.tmpFootprint(ctx, session, ServerType.ets, tmpId, '
|
|
315
|
+
.example("近七日足迹")
|
|
316
|
+
.example("近七日足迹 12345")
|
|
317
|
+
.action(async ({ session }, tmpId) => await commands.tmpFootprint(ctx, session, ServerType.ets, tmpId, 'sevenday'));
|
|
318
318
|
|
|
319
|
-
ctx.command('
|
|
319
|
+
ctx.command('近七日足迹p [tmpId:string]')
|
|
320
320
|
.usage("查询Promods服务器今日足迹")
|
|
321
|
-
.example("
|
|
322
|
-
.example("
|
|
323
|
-
.action(async ({ session }, tmpId) => await commands.tmpFootprint(ctx, session, ServerType.promods, tmpId, '
|
|
321
|
+
.example("近七日足迹p")
|
|
322
|
+
.example("近七日足迹p 12345")
|
|
323
|
+
.action(async ({ session }, tmpId) => await commands.tmpFootprint(ctx, session, ServerType.promods, tmpId, 'sevenday'));
|
|
324
324
|
|
|
325
325
|
ctx.command('昨日足迹 [tmpId:string]')
|
|
326
326
|
.usage("查询ETS服务器今日足迹")
|
package/lib/resource/query.html
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="
|
|
2
|
+
<html lang="zh-CN">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
|
-
<title>
|
|
5
|
+
<title>Player Info Card</title>
|
|
6
6
|
<link href="./package/leaflet/leaflet.min.css" rel="stylesheet">
|
|
7
7
|
<script src="./package/leaflet/leaflet.min.js"></script>
|
|
8
8
|
<style>
|
|
@@ -12,350 +12,757 @@
|
|
|
12
12
|
font-weight: normal;
|
|
13
13
|
font-style: normal;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
* {
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
box-sizing: border-box;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
body {
|
|
23
|
+
font-family: 'segui-emj', 'Segoe UI', -apple-system, sans-serif;
|
|
24
|
+
background: #080c20;
|
|
25
|
+
-webkit-font-smoothing: antialiased;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
#container {
|
|
24
|
-
|
|
29
|
+
width: 480px;
|
|
30
|
+
background: linear-gradient(160deg, #0a0e27 0%, #151338 30%, #0d1a3a 60%, #080c20 100%);
|
|
31
|
+
padding: 0 0 16px;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
position: relative;
|
|
25
34
|
}
|
|
26
35
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
/* Ambient glow orbs */
|
|
37
|
+
.ambient-orb {
|
|
38
|
+
position: absolute;
|
|
39
|
+
border-radius: 50%;
|
|
40
|
+
pointer-events: none;
|
|
41
|
+
filter: blur(60px);
|
|
42
|
+
z-index: 0;
|
|
30
43
|
}
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
|
|
45
|
+
.ambient-orb.orb1 {
|
|
46
|
+
top: -40px;
|
|
47
|
+
right: -30px;
|
|
48
|
+
width: 180px;
|
|
49
|
+
height: 180px;
|
|
50
|
+
background: rgba(99, 102, 241, 0.18);
|
|
33
51
|
}
|
|
34
|
-
|
|
35
|
-
|
|
52
|
+
|
|
53
|
+
.ambient-orb.orb2 {
|
|
54
|
+
top: 200px;
|
|
55
|
+
left: -50px;
|
|
56
|
+
width: 140px;
|
|
57
|
+
height: 140px;
|
|
58
|
+
background: rgba(168, 85, 247, 0.12);
|
|
36
59
|
}
|
|
37
60
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
.ambient-orb.orb3 {
|
|
62
|
+
bottom: 80px;
|
|
63
|
+
right: -20px;
|
|
64
|
+
width: 120px;
|
|
65
|
+
height: 120px;
|
|
66
|
+
background: rgba(59, 130, 246, 0.1);
|
|
42
67
|
}
|
|
43
68
|
|
|
69
|
+
/* ===== HEADER ===== */
|
|
44
70
|
.header {
|
|
45
|
-
|
|
46
|
-
background-color: rgba(0, 0, 0, .1);
|
|
71
|
+
padding: 24px 24px 18px;
|
|
47
72
|
display: flex;
|
|
48
73
|
align-items: center;
|
|
49
|
-
|
|
50
|
-
|
|
74
|
+
gap: 16px;
|
|
75
|
+
position: relative;
|
|
76
|
+
z-index: 1;
|
|
77
|
+
background: linear-gradient(180deg, rgba(139, 92, 246, 0.08) 0%, transparent 100%);
|
|
78
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
|
51
79
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
80
|
+
|
|
81
|
+
.avatar-wrapper {
|
|
82
|
+
position: relative;
|
|
83
|
+
flex-shrink: 0;
|
|
55
84
|
}
|
|
56
|
-
|
|
85
|
+
|
|
86
|
+
.avatar {
|
|
87
|
+
width: 72px;
|
|
88
|
+
height: 72px;
|
|
89
|
+
border-radius: 50%;
|
|
90
|
+
border: 2.5px solid rgba(139, 92, 246, 0.5);
|
|
91
|
+
box-shadow:
|
|
92
|
+
0 0 20px rgba(139, 92, 246, 0.35),
|
|
93
|
+
0 0 40px rgba(139, 92, 246, 0.15),
|
|
94
|
+
inset 0 0 12px rgba(139, 92, 246, 0.1);
|
|
95
|
+
object-fit: cover;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.online-dot {
|
|
99
|
+
position: absolute;
|
|
100
|
+
bottom: 2px;
|
|
101
|
+
right: 2px;
|
|
102
|
+
width: 14px;
|
|
103
|
+
height: 14px;
|
|
104
|
+
border-radius: 50%;
|
|
105
|
+
border: 2.5px solid #0a0e27;
|
|
106
|
+
z-index: 2;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.online-dot.online {
|
|
110
|
+
background: #22c55e;
|
|
111
|
+
box-shadow: 0 0 8px rgba(34, 197, 94, 0.6);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.online-dot.offline {
|
|
115
|
+
background: #6b7280;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.header-info {
|
|
57
119
|
flex: 1;
|
|
58
|
-
|
|
120
|
+
min-width: 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.player-name {
|
|
124
|
+
font-size: 20px;
|
|
125
|
+
font-weight: 700;
|
|
126
|
+
color: #f0f0ff;
|
|
127
|
+
white-space: nowrap;
|
|
128
|
+
overflow: hidden;
|
|
129
|
+
text-overflow: ellipsis;
|
|
130
|
+
text-shadow: 0 0 20px rgba(139, 92, 246, 0.3);
|
|
59
131
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
132
|
+
|
|
133
|
+
.player-meta {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: 8px;
|
|
137
|
+
margin-top: 6px;
|
|
138
|
+
flex-wrap: wrap;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.tmp-id {
|
|
142
|
+
font-size: 13px;
|
|
143
|
+
color: #94a3b8;
|
|
144
|
+
font-weight: 500;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.group-badge {
|
|
148
|
+
font-size: 11px;
|
|
63
149
|
font-weight: 600;
|
|
150
|
+
padding: 2px 8px;
|
|
151
|
+
border-radius: 10px;
|
|
152
|
+
color: #fff;
|
|
153
|
+
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
|
|
154
|
+
letter-spacing: 0.3px;
|
|
64
155
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
font-size:
|
|
68
|
-
|
|
156
|
+
|
|
157
|
+
.status-badge {
|
|
158
|
+
font-size: 11px;
|
|
159
|
+
font-weight: 600;
|
|
160
|
+
padding: 2px 8px;
|
|
161
|
+
border-radius: 10px;
|
|
162
|
+
letter-spacing: 0.3px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.status-badge.online {
|
|
166
|
+
background: rgba(34, 197, 94, 0.2);
|
|
167
|
+
color: #4ade80;
|
|
168
|
+
border: 1px solid rgba(34, 197, 94, 0.3);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.status-badge.offline {
|
|
172
|
+
background: rgba(107, 114, 128, 0.2);
|
|
173
|
+
color: #9ca3af;
|
|
174
|
+
border: 1px solid rgba(107, 114, 128, 0.3);
|
|
69
175
|
}
|
|
70
|
-
|
|
71
|
-
|
|
176
|
+
|
|
177
|
+
/* ===== GLASS SECTIONS ===== */
|
|
178
|
+
.section {
|
|
179
|
+
margin: 10px 16px;
|
|
180
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.02) 100%);
|
|
181
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
182
|
+
border-radius: 16px;
|
|
183
|
+
padding: 14px 16px;
|
|
184
|
+
backdrop-filter: blur(20px) saturate(1.2);
|
|
185
|
+
-webkit-backdrop-filter: blur(20px) saturate(1.2);
|
|
186
|
+
position: relative;
|
|
187
|
+
z-index: 1;
|
|
188
|
+
box-shadow:
|
|
189
|
+
0 4px 16px rgba(0, 0, 0, 0.15),
|
|
190
|
+
0 1px 2px rgba(255, 255, 255, 0.05) inset;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Glass highlight on top */
|
|
195
|
+
.section::before {
|
|
196
|
+
content: '';
|
|
197
|
+
position: absolute;
|
|
198
|
+
top: 0;
|
|
199
|
+
left: 0;
|
|
200
|
+
right: 0;
|
|
201
|
+
height: 1px;
|
|
202
|
+
background: linear-gradient(90deg, transparent 5%, rgba(255, 255, 255, 0.12) 50%, transparent 95%);
|
|
203
|
+
z-index: 2;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.section-title {
|
|
72
207
|
font-size: 12px;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
208
|
+
font-weight: 700;
|
|
209
|
+
color: #c4b5fd;
|
|
210
|
+
text-transform: uppercase;
|
|
211
|
+
letter-spacing: 1.2px;
|
|
212
|
+
margin-bottom: 10px;
|
|
213
|
+
display: flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
gap: 6px;
|
|
216
|
+
position: relative;
|
|
217
|
+
z-index: 1;
|
|
78
218
|
}
|
|
79
219
|
|
|
80
|
-
.
|
|
81
|
-
|
|
220
|
+
.section-title::after {
|
|
221
|
+
content: '';
|
|
222
|
+
flex: 1;
|
|
223
|
+
height: 1px;
|
|
224
|
+
background: linear-gradient(90deg, rgba(139, 92, 246, 0.4), rgba(139, 92, 246, 0.05), transparent);
|
|
225
|
+
margin-left: 8px;
|
|
82
226
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
227
|
+
|
|
228
|
+
/* ===== INFO ROWS ===== */
|
|
229
|
+
.info-row {
|
|
230
|
+
display: flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
justify-content: space-between;
|
|
233
|
+
padding: 5px 0;
|
|
234
|
+
position: relative;
|
|
235
|
+
z-index: 1;
|
|
86
236
|
}
|
|
87
|
-
|
|
88
|
-
|
|
237
|
+
|
|
238
|
+
.info-row + .info-row {
|
|
239
|
+
border-top: 1px solid rgba(255, 255, 255, 0.04);
|
|
89
240
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
241
|
+
|
|
242
|
+
.info-label {
|
|
243
|
+
font-size: 13px;
|
|
244
|
+
color: #94a3b8;
|
|
245
|
+
display: flex;
|
|
246
|
+
align-items: center;
|
|
247
|
+
gap: 6px;
|
|
248
|
+
flex-shrink: 0;
|
|
94
249
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
250
|
+
|
|
251
|
+
.info-value {
|
|
252
|
+
font-size: 13px;
|
|
253
|
+
color: #e2e8f0;
|
|
254
|
+
text-align: right;
|
|
255
|
+
word-break: break-all;
|
|
256
|
+
max-width: 60%;
|
|
98
257
|
}
|
|
99
258
|
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
259
|
+
.info-value.gold {
|
|
260
|
+
color: #fbbf24;
|
|
261
|
+
font-weight: 600;
|
|
262
|
+
text-shadow: 0 0 8px rgba(251, 191, 36, 0.3);
|
|
103
263
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
box-sizing: border-box;
|
|
108
|
-
padding: 0 12px;
|
|
109
|
-
color: #ffffff;
|
|
110
|
-
font-size: 14px;
|
|
111
|
-
line-height: 30px;
|
|
112
|
-
background-color: rgba(227, 92, 92, 0.6);
|
|
264
|
+
|
|
265
|
+
.info-value.green {
|
|
266
|
+
color: #4ade80;
|
|
113
267
|
}
|
|
114
|
-
|
|
115
|
-
|
|
268
|
+
|
|
269
|
+
.info-value.red {
|
|
270
|
+
color: #f87171;
|
|
116
271
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
font-
|
|
121
|
-
text-align: center;
|
|
272
|
+
|
|
273
|
+
.info-value.dim {
|
|
274
|
+
color: #6b7280;
|
|
275
|
+
font-size: 12px;
|
|
122
276
|
}
|
|
123
|
-
|
|
277
|
+
|
|
278
|
+
/* ===== VTC HISTORY ===== */
|
|
279
|
+
.vtc-history-item {
|
|
280
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.04) 0%, rgba(255, 255, 255, 0.01) 100%);
|
|
281
|
+
border: 1px solid rgba(255, 255, 255, 0.06);
|
|
282
|
+
border-radius: 10px;
|
|
283
|
+
padding: 10px 12px;
|
|
124
284
|
margin-top: 8px;
|
|
285
|
+
backdrop-filter: blur(10px);
|
|
286
|
+
-webkit-backdrop-filter: blur(10px);
|
|
287
|
+
position: relative;
|
|
288
|
+
z-index: 1;
|
|
125
289
|
}
|
|
126
|
-
|
|
127
|
-
.
|
|
128
|
-
margin-top:
|
|
290
|
+
|
|
291
|
+
.vtc-history-item + .vtc-history-item {
|
|
292
|
+
margin-top: 6px;
|
|
129
293
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
font-size:
|
|
294
|
+
|
|
295
|
+
.vtc-history-name {
|
|
296
|
+
font-size: 13px;
|
|
297
|
+
color: #fbbf24;
|
|
298
|
+
font-weight: 600;
|
|
299
|
+
margin-bottom: 4px;
|
|
133
300
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
font-size:
|
|
137
|
-
|
|
138
|
-
|
|
301
|
+
|
|
302
|
+
.vtc-history-dates {
|
|
303
|
+
font-size: 11px;
|
|
304
|
+
color: #64748b;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* ===== BAN SECTION ===== */
|
|
308
|
+
.section.ban-section {
|
|
309
|
+
background: linear-gradient(135deg, rgba(239, 68, 68, 0.1) 0%, rgba(239, 68, 68, 0.03) 100%);
|
|
310
|
+
border-color: rgba(239, 68, 68, 0.15);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.section.ban-section .section-title {
|
|
314
|
+
color: #f87171;
|
|
139
315
|
}
|
|
140
316
|
|
|
141
|
-
.
|
|
142
|
-
|
|
317
|
+
.section.ban-section .section-title::after {
|
|
318
|
+
background: linear-gradient(90deg, rgba(248, 113, 113, 0.4), rgba(248, 113, 113, 0.05), transparent);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.ban-hidden-text {
|
|
322
|
+
color: #6b7280;
|
|
323
|
+
font-size: 13px;
|
|
324
|
+
font-style: italic;
|
|
325
|
+
text-align: center;
|
|
326
|
+
padding: 4px 0;
|
|
143
327
|
}
|
|
144
|
-
|
|
328
|
+
|
|
329
|
+
/* ===== MAP SECTION ===== */
|
|
330
|
+
.section.map-section {
|
|
331
|
+
padding: 0;
|
|
332
|
+
overflow: hidden;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.map-section .section-title {
|
|
336
|
+
padding: 14px 16px 0;
|
|
337
|
+
margin-bottom: 10px;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.map-section #map {
|
|
145
341
|
width: 100%;
|
|
146
|
-
height:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
342
|
+
height: 180px;
|
|
343
|
+
border-radius: 0 0 16px 16px;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* ===== SPONSOR SECTION ===== */
|
|
347
|
+
.section.sponsor-section {
|
|
348
|
+
background: linear-gradient(135deg, rgba(250, 204, 21, 0.08) 0%, rgba(250, 204, 21, 0.02) 100%);
|
|
349
|
+
border-color: rgba(250, 204, 21, 0.15);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.section.sponsor-section .section-title {
|
|
353
|
+
color: #facc15;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.section.sponsor-section .section-title::after {
|
|
357
|
+
background: linear-gradient(90deg, rgba(250, 204, 21, 0.4), rgba(250, 204, 21, 0.05), transparent);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* ===== GAME TIME SECTION ===== */
|
|
361
|
+
.section.game-section {
|
|
362
|
+
background: linear-gradient(135deg, rgba(59, 130, 246, 0.08) 0%, rgba(59, 130, 246, 0.02) 100%);
|
|
363
|
+
border-color: rgba(59, 130, 246, 0.15);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.section.game-section .section-title {
|
|
367
|
+
color: #60a5fa;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.section.game-section .section-title::after {
|
|
371
|
+
background: linear-gradient(90deg, rgba(96, 165, 250, 0.4), rgba(96, 165, 250, 0.05), transparent);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* ===== MILEAGE SECTION ===== */
|
|
375
|
+
.section.mileage-section {
|
|
376
|
+
background: linear-gradient(135deg, rgba(16, 185, 129, 0.08) 0%, rgba(16, 185, 129, 0.02) 100%);
|
|
377
|
+
border-color: rgba(16, 185, 129, 0.15);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.section.mileage-section .section-title {
|
|
381
|
+
color: #34d399;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.section.mileage-section .section-title::after {
|
|
385
|
+
background: linear-gradient(90deg, rgba(52, 211, 153, 0.4), rgba(52, 211, 153, 0.05), transparent);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* ===== GLASS BAR (ban count, last online) ===== */
|
|
389
|
+
.glass-bar {
|
|
390
|
+
margin: 10px 16px;
|
|
391
|
+
display: flex;
|
|
392
|
+
align-items: center;
|
|
393
|
+
justify-content: space-between;
|
|
394
|
+
padding: 10px 16px;
|
|
395
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
|
|
396
|
+
border: 1px solid rgba(255, 255, 255, 0.07);
|
|
397
|
+
border-radius: 12px;
|
|
398
|
+
backdrop-filter: blur(16px) saturate(1.1);
|
|
399
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.1);
|
|
400
|
+
position: relative;
|
|
401
|
+
z-index: 1;
|
|
402
|
+
box-shadow:
|
|
403
|
+
0 2px 8px rgba(0, 0, 0, 0.1),
|
|
404
|
+
0 1px 1px rgba(255, 255, 255, 0.04) inset;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.glass-bar::before {
|
|
408
|
+
content: '';
|
|
409
|
+
position: absolute;
|
|
410
|
+
top: 0;
|
|
411
|
+
left: 0;
|
|
412
|
+
right: 0;
|
|
413
|
+
height: 1px;
|
|
414
|
+
background: linear-gradient(90deg, transparent 10%, rgba(255, 255, 255, 0.08) 50%, transparent 90%);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.glass-bar .info-label {
|
|
418
|
+
font-size: 13px;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.glass-bar .info-value {
|
|
150
422
|
font-size: 14px;
|
|
151
|
-
|
|
152
|
-
background-color: rgba(0, 0, 0, 0.4);
|
|
423
|
+
font-weight: 700;
|
|
153
424
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
425
|
+
|
|
426
|
+
.glass-bar .info-value.has-bans {
|
|
427
|
+
color: #f87171;
|
|
428
|
+
text-shadow: 0 0 6px rgba(248, 113, 113, 0.3);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.glass-bar .info-value.no-bans {
|
|
432
|
+
color: #4ade80;
|
|
158
433
|
}
|
|
159
434
|
</style>
|
|
160
435
|
</head>
|
|
161
436
|
<body>
|
|
162
437
|
<div id="container">
|
|
438
|
+
<!-- Ambient light orbs -->
|
|
439
|
+
<div class="ambient-orb orb1"></div>
|
|
440
|
+
<div class="ambient-orb orb2"></div>
|
|
441
|
+
<div class="ambient-orb orb3"></div>
|
|
442
|
+
|
|
443
|
+
<!-- Header -->
|
|
163
444
|
<div class="header">
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
<div class="
|
|
167
|
-
<div class="tmp-id" id="tmp-id"></div>
|
|
445
|
+
<div class="avatar-wrapper">
|
|
446
|
+
<img class="avatar" id="tmp-avatar" src="" alt="avatar"/>
|
|
447
|
+
<div class="online-dot" id="online-dot"></div>
|
|
168
448
|
</div>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
<
|
|
174
|
-
<
|
|
175
|
-
</div>
|
|
176
|
-
<div class="form-item full">
|
|
177
|
-
<div class="label">📑注册日期</div>
|
|
178
|
-
<div class="value" id="tmp-register-date"></div>
|
|
179
|
-
</div>
|
|
180
|
-
<div class="form-item full" id="tmp-vtc-box">
|
|
181
|
-
<div class="label">🚚所属车队</div>
|
|
182
|
-
<div class="value" id="tmp-vtc-name"></div>
|
|
183
|
-
</div>
|
|
184
|
-
<div class="form-item full" id="tmp-vtc-role-box">
|
|
185
|
-
<div class="label">🚚车队角色</div>
|
|
186
|
-
<div class="value" id="tmp-vtc-role"></div>
|
|
187
|
-
</div>
|
|
188
|
-
<div class="form-item" id="tmp-sponsor-box">
|
|
189
|
-
<div class="label">🎁赞助用户</div>
|
|
190
|
-
<div class="value" id="tmp-sponsor-amount"></div>
|
|
191
|
-
</div>
|
|
192
|
-
<div class="form-item" id="tmp-sponsor-cumulative-box">
|
|
193
|
-
<div class="label">🎁累计赞助</div>
|
|
194
|
-
<div class="value" id="tmp-sponsor-cumulative"></div>
|
|
449
|
+
<div class="header-info">
|
|
450
|
+
<div class="player-name" id="tmp-name">-</div>
|
|
451
|
+
<div class="player-meta">
|
|
452
|
+
<span class="tmp-id" id="tmp-id"></span>
|
|
453
|
+
<span class="group-badge" id="group-badge"></span>
|
|
454
|
+
<span class="status-badge" id="status-badge"></span>
|
|
195
455
|
</div>
|
|
196
456
|
</div>
|
|
197
457
|
</div>
|
|
198
|
-
|
|
199
|
-
|
|
458
|
+
|
|
459
|
+
<!-- Basic Info -->
|
|
460
|
+
<div class="section">
|
|
461
|
+
<div class="section-title">📋 基本信息</div>
|
|
462
|
+
<div class="info-row">
|
|
463
|
+
<div class="info-label">🆔 SteamID</div>
|
|
464
|
+
<div class="info-value" id="tmp-steam-id"></div>
|
|
465
|
+
</div>
|
|
466
|
+
<div class="info-row">
|
|
467
|
+
<div class="info-label">📑 注册日期</div>
|
|
468
|
+
<div class="info-value" id="tmp-register-date"></div>
|
|
469
|
+
</div>
|
|
470
|
+
<div class="info-row">
|
|
471
|
+
<div class="info-label">💼 所属分组</div>
|
|
472
|
+
<div class="info-value" id="tmp-group-name"></div>
|
|
473
|
+
</div>
|
|
474
|
+
</div>
|
|
475
|
+
|
|
476
|
+
<!-- VTC Section (only if isJoinVtc) -->
|
|
477
|
+
<div class="section" id="vtc-section" style="display:none;">
|
|
478
|
+
<div class="section-title">🚚 车队信息</div>
|
|
479
|
+
<div class="info-row">
|
|
480
|
+
<div class="info-label">🚚 所属车队</div>
|
|
481
|
+
<div class="info-value gold" id="tmp-vtc-name"></div>
|
|
482
|
+
</div>
|
|
483
|
+
<div class="info-row">
|
|
484
|
+
<div class="info-label">🚚 车队角色</div>
|
|
485
|
+
<div class="info-value" id="tmp-vtc-role"></div>
|
|
486
|
+
</div>
|
|
487
|
+
<div id="vtc-history-container"></div>
|
|
488
|
+
<div class="info-row" id="reward-points-row" style="display:none;">
|
|
489
|
+
<div class="info-label">⭐ 当前车队积分</div>
|
|
490
|
+
<div class="info-value gold" id="tmp-reward-points"></div>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
|
|
494
|
+
<!-- Online Status -->
|
|
495
|
+
<div class="section" id="status-section">
|
|
496
|
+
<div class="section-title">📶 在线状态</div>
|
|
497
|
+
<div class="info-row">
|
|
498
|
+
<div class="info-label">📶 状态</div>
|
|
499
|
+
<div class="info-value" id="tmp-online-status"></div>
|
|
500
|
+
</div>
|
|
501
|
+
<div class="info-row" id="online-location-row" style="display:none;">
|
|
502
|
+
<div class="info-label">🌍 线上位置</div>
|
|
503
|
+
<div class="info-value" id="tmp-online-location"></div>
|
|
504
|
+
</div>
|
|
505
|
+
</div>
|
|
506
|
+
|
|
507
|
+
<!-- Last Online (only when offline) -->
|
|
508
|
+
<div class="glass-bar" id="last-online-bar" style="display:none;">
|
|
509
|
+
<div class="info-label">📶 上次在线</div>
|
|
510
|
+
<div class="info-value dim" id="tmp-last-online"></div>
|
|
511
|
+
</div>
|
|
512
|
+
|
|
513
|
+
<!-- Map Section (only when online) -->
|
|
514
|
+
<div class="section map-section" id="map-section" style="display:none;">
|
|
515
|
+
<div class="section-title" id="map-title">🗺️ 位置地图</div>
|
|
200
516
|
<div id="map"></div>
|
|
201
517
|
</div>
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
518
|
+
|
|
519
|
+
<!-- Ban Section (only when banned) -->
|
|
520
|
+
<div class="section ban-section" id="ban-section" style="display:none;">
|
|
521
|
+
<div class="section-title">🚫 封禁信息</div>
|
|
522
|
+
<div id="ban-content"></div>
|
|
523
|
+
</div>
|
|
524
|
+
|
|
525
|
+
<!-- Ban Count (always shown) -->
|
|
526
|
+
<div class="glass-bar" id="ban-count-bar">
|
|
527
|
+
<div class="info-label">🚫 封禁次数</div>
|
|
528
|
+
<div class="info-value" id="tmp-ban-count"></div>
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
<!-- Mileage Section -->
|
|
532
|
+
<div class="section mileage-section" id="mileage-section" style="display:none;">
|
|
533
|
+
<div class="section-title">🚩 里程信息</div>
|
|
534
|
+
<div class="info-row" id="mileage-row" style="display:none;">
|
|
535
|
+
<div class="info-label">🚩 历史里程</div>
|
|
536
|
+
<div class="info-value" id="tmp-mileage"></div>
|
|
537
|
+
</div>
|
|
538
|
+
<div class="info-row" id="today-mileage-row" style="display:none;">
|
|
539
|
+
<div class="info-label">🚩 今日里程</div>
|
|
540
|
+
<div class="info-value" id="tmp-today-mileage"></div>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
<!-- Game Time Section -->
|
|
545
|
+
<div class="section game-section" id="game-section" style="display:none;">
|
|
546
|
+
<div class="section-title">🎮 游戏时长</div>
|
|
547
|
+
<div class="info-row" id="ets2-time-row" style="display:none;">
|
|
548
|
+
<div class="info-label">🎮 欧卡游戏时长</div>
|
|
549
|
+
<div class="info-value" id="tmp-ets2-time"></div>
|
|
550
|
+
</div>
|
|
551
|
+
<div class="info-row" id="ats-time-row" style="display:none;">
|
|
552
|
+
<div class="info-label">🎮 美卡游戏时长</div>
|
|
553
|
+
<div class="info-value" id="tmp-ats-time"></div>
|
|
554
|
+
</div>
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
<!-- Sponsor Section -->
|
|
558
|
+
<div class="section sponsor-section" id="sponsor-section" style="display:none;">
|
|
559
|
+
<div class="section-title">🌟 赞助信息</div>
|
|
560
|
+
<div class="info-row">
|
|
561
|
+
<div class="info-label">🌟 Patreon支持者</div>
|
|
562
|
+
<div class="info-value" id="tmp-sponsor-status"></div>
|
|
563
|
+
</div>
|
|
564
|
+
<div class="info-row">
|
|
565
|
+
<div class="info-label">💰 当前赞助金额</div>
|
|
566
|
+
<div class="info-value" id="tmp-sponsor-amount"></div>
|
|
567
|
+
</div>
|
|
568
|
+
<div class="info-row">
|
|
569
|
+
<div class="info-label">💰 全部赞助金额</div>
|
|
570
|
+
<div class="info-value" id="tmp-sponsor-cumulative"></div>
|
|
220
571
|
</div>
|
|
221
572
|
</div>
|
|
222
573
|
</div>
|
|
574
|
+
|
|
223
575
|
<script>
|
|
224
576
|
let mapConfig = {
|
|
225
577
|
ets: {
|
|
226
578
|
tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/ets2/05102019/{z}/{x}/{y}.png',
|
|
227
|
-
multipliers: {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
},
|
|
231
|
-
breakpoints: {
|
|
232
|
-
uk: {
|
|
233
|
-
x: -31056.8,
|
|
234
|
-
y: -5832.867
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
bounds: {
|
|
238
|
-
y: 131072,
|
|
239
|
-
x: 131072
|
|
240
|
-
},
|
|
579
|
+
multipliers: { x: 71282, y: 56532 },
|
|
580
|
+
breakpoints: { uk: { x: -31056.8, y: -5832.867 } },
|
|
581
|
+
bounds: { y: 131072, x: 131072 },
|
|
241
582
|
maxZoom: 8,
|
|
242
583
|
minZoom: 2,
|
|
243
|
-
// 游戏地转地图坐标
|
|
244
584
|
calculateMapCoordinate (x, y) {
|
|
245
|
-
return [
|
|
246
|
-
x / 1.325928 + mapConfig.ets.multipliers.x,
|
|
247
|
-
y / 1.325928 + mapConfig.ets.multipliers.y
|
|
248
|
-
];
|
|
585
|
+
return [x / 1.325928 + mapConfig.ets.multipliers.x, y / 1.325928 + mapConfig.ets.multipliers.y];
|
|
249
586
|
}
|
|
250
587
|
},
|
|
251
588
|
promods: {
|
|
252
589
|
tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/promods/05102019/{z}/{x}/{y}.png',
|
|
253
|
-
multipliers: {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
},
|
|
257
|
-
breakpoints: {
|
|
258
|
-
uk: {
|
|
259
|
-
x: -31056.8,
|
|
260
|
-
y: -5832.867
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
bounds: {
|
|
264
|
-
y: 131072,
|
|
265
|
-
x: 131072
|
|
266
|
-
},
|
|
590
|
+
multipliers: { x: 51953, y: 76024 },
|
|
591
|
+
breakpoints: { uk: { x: -31056.8, y: -5832.867 } },
|
|
592
|
+
bounds: { y: 131072, x: 131072 },
|
|
267
593
|
maxZoom: 8,
|
|
268
594
|
minZoom: 2,
|
|
269
|
-
// 游戏地转地图坐标
|
|
270
595
|
calculateMapCoordinate (x, y) {
|
|
271
|
-
return [
|
|
272
|
-
x / 2.598541 + mapConfig.promods.multipliers.x,
|
|
273
|
-
y / 2.598541 + mapConfig.promods.multipliers.y
|
|
274
|
-
]
|
|
596
|
+
return [x / 2.598541 + mapConfig.promods.multipliers.x, y / 2.598541 + mapConfig.promods.multipliers.y];
|
|
275
597
|
}
|
|
276
598
|
}
|
|
277
599
|
}
|
|
278
600
|
|
|
601
|
+
function formatMileage(val) {
|
|
602
|
+
if (!val) return null;
|
|
603
|
+
if (val > 1000) return (val / 1000).toFixed(1) + ' 公里';
|
|
604
|
+
return val + ' 米';
|
|
605
|
+
}
|
|
606
|
+
|
|
279
607
|
function init(data) {
|
|
280
|
-
|
|
281
|
-
document.getElementById('tmp-avatar').src = data.avatarUrl
|
|
282
|
-
|
|
283
|
-
document.getElementById('tmp-
|
|
284
|
-
document.getElementById('
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
608
|
+
// Header
|
|
609
|
+
document.getElementById('tmp-avatar').src = data.avatarUrl;
|
|
610
|
+
document.getElementById('tmp-name').innerText = data.name;
|
|
611
|
+
document.getElementById('tmp-id').innerText = 'TMP#' + data.tmpId;
|
|
612
|
+
document.getElementById('group-badge').innerText = data.groupName;
|
|
613
|
+
document.getElementById('group-badge').style.backgroundColor = '#' + data.groupColor;
|
|
614
|
+
|
|
615
|
+
// Online dot & status badge
|
|
616
|
+
const dot = document.getElementById('online-dot');
|
|
617
|
+
const badge = document.getElementById('status-badge');
|
|
618
|
+
if (data.isOnline) {
|
|
619
|
+
dot.className = 'online-dot online';
|
|
620
|
+
badge.className = 'status-badge online';
|
|
621
|
+
badge.innerText = '在线';
|
|
288
622
|
} else {
|
|
289
|
-
|
|
290
|
-
|
|
623
|
+
dot.className = 'online-dot offline';
|
|
624
|
+
badge.className = 'status-badge offline';
|
|
625
|
+
badge.innerText = '离线';
|
|
291
626
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
627
|
+
|
|
628
|
+
// Basic Info
|
|
629
|
+
document.getElementById('tmp-steam-id').innerText = data.steamId;
|
|
630
|
+
document.getElementById('tmp-register-date').innerText = data.registerDate + ' (' + data.registerDays + '天)';
|
|
631
|
+
document.getElementById('tmp-group-name').innerText = data.groupName;
|
|
632
|
+
|
|
633
|
+
// VTC Section
|
|
634
|
+
if (data.isJoinVtc) {
|
|
635
|
+
document.getElementById('vtc-section').style.display = '';
|
|
636
|
+
document.getElementById('tmp-vtc-name').innerText = data.vtcName;
|
|
637
|
+
document.getElementById('tmp-vtc-role').innerText = data.vtcRole;
|
|
638
|
+
|
|
639
|
+
if (data.vtcHistory && data.vtcHistory.length > 0) {
|
|
640
|
+
const historyContainer = document.getElementById('vtc-history-container');
|
|
641
|
+
data.vtcHistory.forEach(function(vtc) {
|
|
642
|
+
const item = document.createElement('div');
|
|
643
|
+
item.className = 'vtc-history-item';
|
|
644
|
+
item.innerHTML =
|
|
645
|
+
'<div class="vtc-history-name">📜 ' + vtc.vtcName + '</div>' +
|
|
646
|
+
'<div class="vtc-history-dates">加入: ' + formatDate(vtc.joinDate) + ' · 离开: ' + formatDate(vtc.quitDate) + '</div>';
|
|
647
|
+
historyContainer.appendChild(item);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (data.rewardPoints > 0) {
|
|
652
|
+
document.getElementById('reward-points-row').style.display = '';
|
|
653
|
+
document.getElementById('tmp-reward-points').innerText = data.rewardPoints;
|
|
654
|
+
}
|
|
298
655
|
}
|
|
656
|
+
|
|
657
|
+
// Online Status Section
|
|
658
|
+
const statusEl = document.getElementById('tmp-online-status');
|
|
299
659
|
if (data.isOnline) {
|
|
300
|
-
|
|
301
|
-
|
|
660
|
+
statusEl.innerHTML = '<span style="color:#4ade80;">在线 🟢</span> <span style="color:#94a3b8;font-size:12px;">(' + data.onlineServerName + ')</span>';
|
|
661
|
+
if (data.onlineCountry && data.onlineCity) {
|
|
662
|
+
document.getElementById('online-location-row').style.display = '';
|
|
663
|
+
document.getElementById('tmp-online-location').innerText = data.onlineCountry + ' - ' + data.onlineCity;
|
|
664
|
+
}
|
|
302
665
|
} else {
|
|
303
|
-
|
|
666
|
+
statusEl.innerHTML = '<span style="color:#9ca3af;">离线 ⚫</span>';
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Last Online
|
|
670
|
+
if (!data.isOnline && data.lastOnlineTime) {
|
|
671
|
+
document.getElementById('last-online-bar').style.display = '';
|
|
672
|
+
document.getElementById('tmp-last-online').innerText = data.lastOnlineTime;
|
|
304
673
|
}
|
|
674
|
+
|
|
675
|
+
// Map
|
|
676
|
+
if (data.isOnline && data.onlineX !== undefined) {
|
|
677
|
+
document.getElementById('map-section').style.display = '';
|
|
678
|
+
if (data.onlineCountry && data.onlineCity) {
|
|
679
|
+
document.getElementById('map-title').innerText = '🗺️ ' + data.onlineCountry + ' - ' + data.onlineCity;
|
|
680
|
+
}
|
|
681
|
+
map(data.onlineMapType, data.onlineX, data.onlineY);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Ban Section
|
|
305
685
|
if (data.isBan) {
|
|
686
|
+
document.getElementById('ban-section').style.display = '';
|
|
687
|
+
const banContent = document.getElementById('ban-content');
|
|
306
688
|
if (data.banHide) {
|
|
307
|
-
|
|
689
|
+
banContent.innerHTML = '<div class="ban-hidden-text">玩家隐藏了封禁信息</div>';
|
|
308
690
|
} else {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
691
|
+
let until = '永久';
|
|
692
|
+
if (data.banUntil) until = formatDate(data.banUntil);
|
|
693
|
+
banContent.innerHTML =
|
|
694
|
+
'<div class="info-row"><div class="info-label">截止时间</div><div class="info-value red">' + until + '</div></div>' +
|
|
695
|
+
'<div class="info-row"><div class="info-label">封禁原因</div><div class="info-value red">' + (data.banReasonZh || data.banReason) + '</div></div>';
|
|
313
696
|
}
|
|
314
|
-
}
|
|
315
|
-
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Ban Count
|
|
700
|
+
const banCountEl = document.getElementById('tmp-ban-count');
|
|
701
|
+
const banCount = data.banCount || 0;
|
|
702
|
+
banCountEl.innerText = banCount + '次';
|
|
703
|
+
banCountEl.className = banCount > 0 ? 'info-value has-bans' : 'info-value no-bans';
|
|
704
|
+
|
|
705
|
+
// Mileage
|
|
706
|
+
const mileage = formatMileage(data.mileage);
|
|
707
|
+
const todayMileage = formatMileage(data.todayMileage);
|
|
708
|
+
if (mileage || todayMileage) {
|
|
709
|
+
document.getElementById('mileage-section').style.display = '';
|
|
710
|
+
if (mileage) {
|
|
711
|
+
document.getElementById('mileage-row').style.display = '';
|
|
712
|
+
document.getElementById('tmp-mileage').innerText = mileage;
|
|
713
|
+
}
|
|
714
|
+
if (todayMileage) {
|
|
715
|
+
document.getElementById('today-mileage-row').style.display = '';
|
|
716
|
+
document.getElementById('tmp-today-mileage').innerText = todayMileage;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Game Time
|
|
721
|
+
if (data.ets2GameTime || data.atsGameTime) {
|
|
722
|
+
document.getElementById('game-section').style.display = '';
|
|
723
|
+
if (data.ets2GameTime) {
|
|
724
|
+
document.getElementById('ets2-time-row').style.display = '';
|
|
725
|
+
document.getElementById('tmp-ets2-time').innerText = data.ets2GameTime;
|
|
726
|
+
}
|
|
727
|
+
if (data.atsGameTime) {
|
|
728
|
+
document.getElementById('ats-time-row').style.display = '';
|
|
729
|
+
document.getElementById('tmp-ats-time').innerText = data.atsGameTime;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Sponsor
|
|
734
|
+
if (data.isSponsor && !data.sponsorHide) {
|
|
735
|
+
document.getElementById('sponsor-section').style.display = '';
|
|
736
|
+
document.getElementById('tmp-sponsor-status').innerHTML = '<span style="color:#facc15;">是</span>';
|
|
737
|
+
const currentAmount = data.sponsorAmount == 'null' ? '0' : (data.sponsorAmount / 100).toFixed(0);
|
|
738
|
+
const cumulativeAmount = data.sponsorCumulativeAmount == 'null' ? '0' : (data.sponsorCumulativeAmount / 100).toFixed(0);
|
|
739
|
+
document.getElementById('tmp-sponsor-amount').innerText = '$' + currentAmount;
|
|
740
|
+
document.getElementById('tmp-sponsor-cumulative').innerText = '$' + cumulativeAmount;
|
|
316
741
|
}
|
|
317
742
|
}
|
|
318
743
|
|
|
744
|
+
function formatDate(dateStr) {
|
|
745
|
+
if (!dateStr) return '-';
|
|
746
|
+
const d = new Date(dateStr);
|
|
747
|
+
return d.getFullYear() + '年' + String(d.getMonth() + 1).padStart(2, '0') + '月' + String(d.getDate()).padStart(2, '0') + '日 ' + String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
|
|
748
|
+
}
|
|
749
|
+
|
|
319
750
|
function map(mapType, x, y) {
|
|
320
|
-
|
|
321
|
-
let map = L.map('map', {
|
|
322
|
-
attributionControl: false,
|
|
323
|
-
crs: L.CRS.Simple,
|
|
324
|
-
zoomControl: false
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
// 边界
|
|
751
|
+
let map = L.map('map', { attributionControl: false, crs: L.CRS.Simple, zoomControl: false });
|
|
328
752
|
let bounds = L.latLngBounds(
|
|
329
753
|
map.unproject([0, mapConfig[mapType].bounds.y], mapConfig[mapType].maxZoom),
|
|
330
754
|
map.unproject([mapConfig[mapType].bounds.x, 0], mapConfig[mapType].maxZoom)
|
|
331
755
|
);
|
|
332
|
-
|
|
333
|
-
// 瓦片地图
|
|
334
756
|
L.tileLayer(mapConfig[mapType].tileUrl, {
|
|
335
|
-
minZoom: 2,
|
|
336
|
-
maxZoom: 10,
|
|
337
|
-
maxNativeZoom: 8,
|
|
338
|
-
tileSize: 512,
|
|
339
|
-
bounds: bounds,
|
|
340
|
-
reuseTiles: true
|
|
757
|
+
minZoom: 2, maxZoom: 10, maxNativeZoom: 8, tileSize: 512, bounds: bounds, reuseTiles: true
|
|
341
758
|
}).addTo(map);
|
|
342
|
-
map.setMaxBounds(
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
)
|
|
347
|
-
);
|
|
348
|
-
|
|
759
|
+
map.setMaxBounds(new L.LatLngBounds(
|
|
760
|
+
map.unproject([0, mapConfig[mapType].bounds.y], mapConfig[mapType].maxZoom),
|
|
761
|
+
map.unproject([mapConfig[mapType].bounds.x, 0], mapConfig[mapType].maxZoom)
|
|
762
|
+
));
|
|
349
763
|
L.circleMarker(map.unproject(mapConfig[mapType].calculateMapCoordinate(x, y), 8), {
|
|
350
|
-
color: '#2f2f2f',
|
|
351
|
-
weight: 2, // 标记点边框大小
|
|
352
|
-
fillColor: '#1cb715', // 标记点填充颜色
|
|
353
|
-
fillOpacity: 1, // 标记点填充不透明度(0到1之间的值)
|
|
354
|
-
radius: 5, // 标记点半径(以像素为单位)
|
|
355
|
-
zIndex: 1000
|
|
764
|
+
color: '#2f2f2f', weight: 2, fillColor: '#1cb715', fillOpacity: 1, radius: 5, zIndex: 1000
|
|
356
765
|
}).addTo(map);
|
|
357
|
-
|
|
358
|
-
// 设置中心点
|
|
359
766
|
map.setView(map.unproject(mapConfig[mapType].calculateMapCoordinate(x, y), 8), 5);
|
|
360
767
|
}
|
|
361
768
|
</script>
|