@sjtdev/koishi-plugin-dota2tracker 1.5.0-pre.2 → 1.5.0-pre.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +14 -9
- package/package.json +1 -1
- package/queries/MatchInfo.graphql +4 -0
- package/template/match/match_2/original.css +7 -7
- package/template/match/match_2+/extra.css +131 -0
- package/template/match/match_2+/lane_outcome.ejs +143 -0
- package/template/match/match_2+.ejs +3 -2
- package/template/match/match_2/extra.css +0 -51
- /package/template/match/{match_2 → match_2+}/charts.ejs +0 -0
package/lib/index.js
CHANGED
|
@@ -38,14 +38,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
38
38
|
// src/locales/en-US.schema.yml
|
|
39
39
|
var require_en_US_schema = __commonJS({
|
|
40
40
|
"src/locales/en-US.schema.yml"(exports2, module2) {
|
|
41
|
-
module2.exports = { _config: { base: { $desc: "Basic Settings", STRATZ_API_TOKEN: "Required. API TOKEN from stratz.com, available at https://stratz.com/api.", dataParsingTimeoutMinutes: "Time to wait for match data parsing (in minutes). If the data parsing time exceeds the waiting time, the report will be generated directly without waiting for the parsing to complete.", urlInMessageType: { $desc: "Include links in messages, <br/>please select the message type:", $inner: ["Include stratz match page link in match query and report messages", "Include stratz player page link in player information query messages", "Include Dota Encyclopedia hero page link in hero data query messages"] } }, rank: { rankBroadSwitch: "Rank change broadcast", rankBroadStar: "Star change broadcast", rankBroadLeader: "Leaderboard rank change broadcast", rankBroadFun: "Fun broadcast template" }, report: { $desc: "Summary Settings", dailyReportSwitch: "Daily Report Function", dailyReportHours: "Daily report time in hours", dailyReportShowCombi: "Show combinations in daily report", weeklyReportSwitch: "Weekly Report Function", weeklyReportDayHours: "Weekly report published on (day) at (hour)", weeklyReportShowCombi: "Show combinations in weekly report" }, template: { $desc: "Template Settings", template_match: "Template used to generate match information images, see https://sjtdev.github.io/koishi-plugin-dota2tracker/template-match.html for template display.", template_player: "Template used to generate player information images. (Currently only one template available)", template_hero: "Template used to generate hero information images. (Currently only one template available)", playerRankEstimate: "Estimate the rank of players without a rank in the player template <br>Estimated rank will be displayed as a gray image" } } };
|
|
41
|
+
module2.exports = { _config: { base: { $desc: "Basic Settings", STRATZ_API_TOKEN: "Required. API TOKEN from stratz.com, available at https://stratz.com/api.", dataParsingTimeoutMinutes: "Time to wait for match data parsing (in minutes). If the data parsing time exceeds the waiting time, the report will be generated directly without waiting for the parsing to complete.", urlInMessageType: { $desc: "Include links in messages, <br/>please select the message type:", $inner: ["Include stratz match page link in match query and report messages", "Include stratz player page link in player information query messages", "Include Dota Encyclopedia hero page link in hero data query messages"] }, proxyAddress: "Proxy address. Leave blank to disable the proxy." }, rank: { rankBroadSwitch: "Rank change broadcast", rankBroadStar: "Star change broadcast", rankBroadLeader: "Leaderboard rank change broadcast", rankBroadFun: "Fun broadcast template" }, report: { $desc: "Summary Settings", dailyReportSwitch: "Daily Report Function", dailyReportHours: "Daily report time in hours", dailyReportShowCombi: "Show combinations in daily report", weeklyReportSwitch: "Weekly Report Function", weeklyReportDayHours: "Weekly report published on (day) at (hour)", weeklyReportShowCombi: "Show combinations in weekly report" }, template: { $desc: "Template Settings", template_match: "Template used to generate match information images, see https://sjtdev.github.io/koishi-plugin-dota2tracker/template-match.html for template display.", template_player: "Template used to generate player information images. (Currently only one template available)", template_hero: "Template used to generate hero information images. (Currently only one template available)", playerRankEstimate: "Estimate the rank of players without a rank in the player template <br>Estimated rank will be displayed as a gray image" } } };
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
// src/locales/zh-CN.schema.yml
|
|
46
46
|
var require_zh_CN_schema = __commonJS({
|
|
47
47
|
"src/locales/zh-CN.schema.yml"(exports2, module2) {
|
|
48
|
-
module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", urlInMessageType: { $desc: "在消息中附带链接,<br/>请选择消息类型:", $inner: ["在查询比赛与战报消息中附带stratz比赛页面链接", "在查询玩家信息消息中附带stratz玩家页面链接", "在查询英雄数据消息中附带刀塔百科对应英雄页面链接"] } }, rank: { rankBroadSwitch: "段位变动播报", rankBroadStar: "星级变动播报", rankBroadLeader: "冠绝名次变动播报", rankBroadFun: "整活播报模板" }, report: { $desc: "总结设置", dailyReportSwitch: "日报功能", dailyReportHours: "日报时间小时", dailyReportShowCombi: "日报是否显示组合", weeklyReportSwitch: "周报功能", weeklyReportDayHours: "周报发布于周(几)的(几)点", weeklyReportShowCombi: "周报是否显示组合" }, template: { $desc: "模板设置", template_match: "生成比赛信息图片使用的模板,见 https://sjtdev.github.io/koishi-plugin-dota2tracker/template-match.html 有模板展示。", template_player: "生成玩家信息图片使用的模板。(目前仅有一张模板)", template_hero: "生成英雄信息图片使用的模板。(目前仅有一张模板)", playerRankEstimate: "在player模板中对没有段位的玩家进行段位估算 <br>估算的段位将以灰色图片显示" } } };
|
|
48
|
+
module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", urlInMessageType: { $desc: "在消息中附带链接,<br/>请选择消息类型:", $inner: ["在查询比赛与战报消息中附带stratz比赛页面链接", "在查询玩家信息消息中附带stratz玩家页面链接", "在查询英雄数据消息中附带刀塔百科对应英雄页面链接"] }, proxyAddress: "代理地址,留空时不使用代理" }, rank: { rankBroadSwitch: "段位变动播报", rankBroadStar: "星级变动播报", rankBroadLeader: "冠绝名次变动播报", rankBroadFun: "整活播报模板" }, report: { $desc: "总结设置", dailyReportSwitch: "日报功能", dailyReportHours: "日报时间小时", dailyReportShowCombi: "日报是否显示组合", weeklyReportSwitch: "周报功能", weeklyReportDayHours: "周报发布于周(几)的(几)点", weeklyReportShowCombi: "周报是否显示组合" }, template: { $desc: "模板设置", template_match: "生成比赛信息图片使用的模板,见 https://sjtdev.github.io/koishi-plugin-dota2tracker/template-match.html 有模板展示。", template_player: "生成玩家信息图片使用的模板。(目前仅有一张模板)", template_hero: "生成英雄信息图片使用的模板。(目前仅有一张模板)", playerRankEstimate: "在player模板中对没有段位的玩家进行段位估算 <br>估算的段位将以灰色图片显示" } } };
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
@@ -610,7 +610,7 @@ var require_zh_CN_command = __commonJS({
|
|
|
610
610
|
// src/locales/zh-CN.template.yml
|
|
611
611
|
var require_zh_CN_template = __commonJS({
|
|
612
612
|
"src/locales/zh-CN.template.yml"(exports2, module2) {
|
|
613
|
-
module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率", anonymous_player_1: "数据未公开", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。", rank_fun_up_message: "热烈祝贺群友 {avatar}{name} 在天梯中再获进步,<br/>由 {prev} 升为 {curr},再接再厉,再创辉煌!", rank_fun_down_message: "{avatar}<br/>寄", titles: { MVP: "MVP-#FFA500", Soul: "魂-#66CCFF", Rich: "富-#FFD700", Wise: "睿-#8888FF", Controller: "控-#FF00FF", Nuker: "爆-#CC0088", Breaker: "破-#DD0000", Ghost: "鬼-#CCCCCC", Assister: "助-#006400", Demolisher: "拆-#FEDCBA", Healer: "奶-#00FF00", Tank: "耐-#84A1C7", Idle: "摸-#DDDDDD" }, situation: "局势", networth: "财产总和", experience: "经验" } } };
|
|
613
|
+
module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率", anonymous_player_1: "数据未公开", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。", rank_fun_up_message: "热烈祝贺群友 {avatar}{name} 在天梯中再获进步,<br/>由 {prev} 升为 {curr},再接再厉,再创辉煌!", rank_fun_down_message: "{avatar}<br/>寄", titles: { MVP: "MVP-#FFA500", Soul: "魂-#66CCFF", Rich: "富-#FFD700", Wise: "睿-#8888FF", Controller: "控-#FF00FF", Nuker: "爆-#CC0088", Breaker: "破-#DD0000", Ghost: "鬼-#CCCCCC", Assister: "助-#006400", Demolisher: "拆-#FEDCBA", Healer: "奶-#00FF00", Tank: "耐-#84A1C7", Idle: "摸-#DDDDDD" }, situation: "局势", networth: "财产总和", experience: "经验", OUTCOME_MAP: { RADIANT_VICTORY: "天辉优势", RADIANT_STOMP: "天辉碾压", DIRE_VICTORY: "夜魇优势", DIRE_STOMP: "夜魇碾压", TIE: "势均力敌" }, lane_top: "上路", lane_mid: "中路", lane_bottom: "下路" } } };
|
|
614
614
|
}
|
|
615
615
|
});
|
|
616
616
|
|
|
@@ -665,8 +665,9 @@ var pluginDir = import_path.default.join(__dirname, "..");
|
|
|
665
665
|
var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
|
|
666
666
|
var http = null;
|
|
667
667
|
var setTimeout;
|
|
668
|
+
var proxyAddress;
|
|
668
669
|
function init(params) {
|
|
669
|
-
({ http, setTimeout, APIKEY: CONFIGS.STRATZ_API.TOKEN } = params);
|
|
670
|
+
({ http, setTimeout, APIKEY: CONFIGS.STRATZ_API.TOKEN, proxyAddress } = params);
|
|
670
671
|
}
|
|
671
672
|
__name(init, "init");
|
|
672
673
|
async function fetchData(query2) {
|
|
@@ -676,7 +677,8 @@ async function fetchData(query2) {
|
|
|
676
677
|
"User-Agent": "STRATZ_API",
|
|
677
678
|
"Content-Type": "application/json",
|
|
678
679
|
Authorization: `Bearer ${CONFIGS.STRATZ_API.TOKEN}`
|
|
679
|
-
}
|
|
680
|
+
},
|
|
681
|
+
proxyAgent: proxyAddress || void 0
|
|
680
682
|
});
|
|
681
683
|
}
|
|
682
684
|
__name(fetchData, "fetchData");
|
|
@@ -1382,7 +1384,9 @@ var globRequire_locales_template_yml = __glob({
|
|
|
1382
1384
|
// src/index.ts
|
|
1383
1385
|
var name = "dota2tracker";
|
|
1384
1386
|
var usage = "";
|
|
1385
|
-
var inject =
|
|
1387
|
+
var inject = {
|
|
1388
|
+
required: ["http", "database", "cron", "puppeteer", "cache"]
|
|
1389
|
+
};
|
|
1386
1390
|
var pluginDir2 = import_path2.default.resolve(__dirname, "..");
|
|
1387
1391
|
var pluginVersion = require(import_path2.default.join(pluginDir2, "package.json")).version;
|
|
1388
1392
|
var GraphqlLanguageEnum = /* @__PURE__ */ ((GraphqlLanguageEnum2) => {
|
|
@@ -1394,7 +1398,8 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
1394
1398
|
import_koishi2.Schema.object({
|
|
1395
1399
|
STRATZ_API_TOKEN: import_koishi2.Schema.string().required().role("secret"),
|
|
1396
1400
|
dataParsingTimeoutMinutes: import_koishi2.Schema.number().default(60).min(0).max(1440),
|
|
1397
|
-
urlInMessageType: import_koishi2.Schema.array(import_koishi2.Schema.union([import_koishi2.Schema.const("match"), import_koishi2.Schema.const("player"), import_koishi2.Schema.const("hero")])).role("checkbox")
|
|
1401
|
+
urlInMessageType: import_koishi2.Schema.array(import_koishi2.Schema.union([import_koishi2.Schema.const("match"), import_koishi2.Schema.const("player"), import_koishi2.Schema.const("hero")])).role("checkbox"),
|
|
1402
|
+
proxyAddress: import_koishi2.Schema.string()
|
|
1398
1403
|
}).i18n(Object.keys(GraphqlLanguageEnum).reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.base, acc), {})),
|
|
1399
1404
|
import_koishi2.Schema.intersect([
|
|
1400
1405
|
import_koishi2.Schema.object({
|
|
@@ -1446,7 +1451,7 @@ var random = new import_koishi3.Random(() => Math.random());
|
|
|
1446
1451
|
var days_30 = 2592e6;
|
|
1447
1452
|
var constantLocales = {};
|
|
1448
1453
|
async function apply(ctx, config) {
|
|
1449
|
-
init({ http: ctx.http, setTimeout: ctx.setTimeout, APIKEY: config.STRATZ_API_TOKEN });
|
|
1454
|
+
init({ http: ctx.http, setTimeout: ctx.setTimeout, APIKEY: config.STRATZ_API_TOKEN, proxyAddress: config.proxyAddress });
|
|
1450
1455
|
for (const supportLanguageTag of Object.keys(GraphqlLanguageEnum)) {
|
|
1451
1456
|
constantLocales[supportLanguageTag] = globRequire_locales_constants_json(`./locales/${supportLanguageTag}.constants.json`);
|
|
1452
1457
|
ctx.i18n.define(supportLanguageTag, globRequire_locales_yml(`./locales/${supportLanguageTag}.yml`));
|
|
@@ -1711,7 +1716,7 @@ async function apply(ctx, config) {
|
|
|
1711
1716
|
}).then((response) => ctx.logger.info($t(GlobalLanguageTag, `dota2tracker.logger.parse_request_${response.stratz.matchRetry ? "sent" : "failed"}`, { matchId: matchQuery.match.id })));
|
|
1712
1717
|
}
|
|
1713
1718
|
} catch (error) {
|
|
1714
|
-
session.send(session.text(".query_failed"));
|
|
1719
|
+
session.send(session.text("commands.dota2tracker.query-match.messages.query_failed"));
|
|
1715
1720
|
ctx.logger.error(error);
|
|
1716
1721
|
}
|
|
1717
1722
|
});
|
package/package.json
CHANGED
|
@@ -89,11 +89,11 @@ nav > .rank > img {
|
|
|
89
89
|
flex-direction: column;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
.panel {
|
|
92
|
+
.players .panel {
|
|
93
93
|
padding: 0 10px;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
.panel {
|
|
96
|
+
.players .panel {
|
|
97
97
|
padding-top: 4px;
|
|
98
98
|
height: 40px;
|
|
99
99
|
border-top: 3px solid #fff;
|
|
@@ -101,21 +101,21 @@ nav > .rank > img {
|
|
|
101
101
|
display: grid;
|
|
102
102
|
grid-template-columns: 32px 56px 378px repeat(4,1fr);
|
|
103
103
|
}
|
|
104
|
-
.panel.radiant {
|
|
104
|
+
.players .panel.radiant {
|
|
105
105
|
border-color: #3c9028;
|
|
106
106
|
}
|
|
107
|
-
.panel.dire {
|
|
107
|
+
.players .panel.dire {
|
|
108
108
|
border-color: #9c3628;
|
|
109
109
|
}
|
|
110
|
-
.panel p{
|
|
110
|
+
.players .panel p{
|
|
111
111
|
line-height: 16px;
|
|
112
112
|
margin-left: 8px;
|
|
113
113
|
}
|
|
114
|
-
.panel .win{
|
|
114
|
+
.players .panel .win{
|
|
115
115
|
font-size: 20px;
|
|
116
116
|
line-height: 32px;
|
|
117
117
|
}
|
|
118
|
-
.panel .data{
|
|
118
|
+
.players .panel .data{
|
|
119
119
|
color: #aaa;
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
html {
|
|
2
|
+
overflow: visible;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
body {
|
|
6
|
+
/* width: 1200px; */
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
overflow: visible;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#regular {
|
|
13
|
+
width: 800px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#extra {
|
|
17
|
+
display: flex;
|
|
18
|
+
width: 800px;
|
|
19
|
+
flex-direction: row;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#charts {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
width: 50%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#charts > svg {
|
|
29
|
+
font-size: 10px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#charts > .title {
|
|
33
|
+
width: 100%;
|
|
34
|
+
display: flex;
|
|
35
|
+
justify-content: space-between;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#charts > .title > .logo {
|
|
39
|
+
display: flex;
|
|
40
|
+
padding: 0 25px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#charts > .title > .logo > img {
|
|
44
|
+
width: 20px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#extra > .tip {
|
|
48
|
+
width: 100%;
|
|
49
|
+
line-height: 4;
|
|
50
|
+
text-align: center;
|
|
51
|
+
color: #ccc;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.lane_outcome {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
width: 386px;
|
|
58
|
+
margin-right: 14px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.lane_outcome > .title {
|
|
62
|
+
width: 100%;
|
|
63
|
+
text-align: center;
|
|
64
|
+
padding: 0;
|
|
65
|
+
margin: 0;
|
|
66
|
+
line-height: 50px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.lane_outcome .panel {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
height: 100%;
|
|
73
|
+
justify-content: space-evenly;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.lane_outcome .panel .lane {
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
width: 100%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.lane_outcome .panel .lane > .title {
|
|
83
|
+
width: 100%;
|
|
84
|
+
text-align: center;
|
|
85
|
+
height: 32px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.lane_outcome .panel .lane > .title > p:nth-child(1){
|
|
89
|
+
font-size: 12px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.lane_outcome .panel .lane > .title > p:nth-child(2){
|
|
93
|
+
font-size: 14px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.lane_outcome .panel .details {
|
|
97
|
+
display: grid;
|
|
98
|
+
grid-template-columns: 24px 32px 44px auto 44px 32px 24px;
|
|
99
|
+
grid-template-rows: 1fr;
|
|
100
|
+
gap: 1px;
|
|
101
|
+
font-size: 12px;
|
|
102
|
+
height: 32px;
|
|
103
|
+
line-height: 32px;
|
|
104
|
+
align-items: center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.lane_outcome .panel .lane img.hero{
|
|
108
|
+
width: 24px;
|
|
109
|
+
height: 24px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.lane_outcome .panel .lane .kda {
|
|
113
|
+
height: 100%;
|
|
114
|
+
line-height: 32px;
|
|
115
|
+
text-align: center;
|
|
116
|
+
font-size: 10px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.lane_outcome .panel .lane .graph {
|
|
120
|
+
height: 32px;
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.graph svg {
|
|
126
|
+
shape-rendering: crispEdges;
|
|
127
|
+
}
|
|
128
|
+
.graph text {
|
|
129
|
+
dominant-baseline: middle; /* 垂直居中 */
|
|
130
|
+
white-space: nowrap; /* 防止换行 */
|
|
131
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<% const match = data; %>
|
|
2
|
+
<%
|
|
3
|
+
function generateLevelCircle(xp) {
|
|
4
|
+
const XP_LEVELS = dotaconstants.xp_level;
|
|
5
|
+
let level = XP_LEVELS.findIndex(l => xp < l) - 1;
|
|
6
|
+
if (level < 0) level = XP_LEVELS.length - 1;
|
|
7
|
+
const currentXP = xp - XP_LEVELS[level];
|
|
8
|
+
const nextXP = XP_LEVELS[level+1] - XP_LEVELS[level];
|
|
9
|
+
const percentage = currentXP / nextXP * 100;
|
|
10
|
+
// return { level, progress: currentXP / nextXP };
|
|
11
|
+
const config = {
|
|
12
|
+
radius: 12,
|
|
13
|
+
strokeColor: '#ffd700',
|
|
14
|
+
bgColor: '#eee',
|
|
15
|
+
strokeWidth: 2,
|
|
16
|
+
svgSize: 32,
|
|
17
|
+
showBackground: true,
|
|
18
|
+
// 新增文字配置
|
|
19
|
+
showText: true, // 是否显示文字
|
|
20
|
+
textColor: '#333', // 文字颜色
|
|
21
|
+
fontSize: 12 * 0.8,
|
|
22
|
+
fontWeight: 'bold', // 字体粗细
|
|
23
|
+
// ...options
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const center = config.svgSize / 2;
|
|
27
|
+
const circumference = 2 * Math.PI * config.radius;
|
|
28
|
+
const progress = circumference * (percentage / 100);
|
|
29
|
+
const gap = circumference - progress;
|
|
30
|
+
|
|
31
|
+
return `
|
|
32
|
+
<svg width="${config.svgSize}" height="${config.svgSize}" viewBox="0 0 ${config.svgSize} ${config.svgSize}">
|
|
33
|
+
${config.showBackground ? `
|
|
34
|
+
<circle cx="${center}" cy="${center}" r="${config.radius}"
|
|
35
|
+
fill="none" stroke="${config.bgColor}"
|
|
36
|
+
stroke-width="${config.strokeWidth}"/>
|
|
37
|
+
` : ''}
|
|
38
|
+
|
|
39
|
+
<circle cx="${center}" cy="${center}" r="${config.radius}"
|
|
40
|
+
fill="none" stroke="${config.strokeColor}"
|
|
41
|
+
stroke-width="${config.strokeWidth}"
|
|
42
|
+
stroke-dasharray="${progress} ${gap}"
|
|
43
|
+
stroke-linecap="round"
|
|
44
|
+
transform="rotate(-90 ${center} ${center})"/>
|
|
45
|
+
|
|
46
|
+
${config.showText ? `
|
|
47
|
+
<!-- 居中文字 -->
|
|
48
|
+
<text x="${center}" y="${center}"
|
|
49
|
+
text-anchor="middle" // 水平居中
|
|
50
|
+
dominant-baseline="middle" // 垂直居中
|
|
51
|
+
fill="${config.textColor}"
|
|
52
|
+
font-size="${config.fontSize}px"
|
|
53
|
+
font-weight="${config.fontWeight}"
|
|
54
|
+
font-family="Arial, sans-serif">
|
|
55
|
+
${level}
|
|
56
|
+
</text>
|
|
57
|
+
` : ''}
|
|
58
|
+
</svg>`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function generateDetails(rivals) {
|
|
62
|
+
const svgHeight = 32;
|
|
63
|
+
|
|
64
|
+
rivals.sort((a, b) => b.isRadiant - a.isRadiant);
|
|
65
|
+
const gold = { radiant: rivals[0].stats.networthPerMinute.at(Math.min(10, rivals[0].stats.networthPerMinute.length - 1)), dire: rivals[1].stats.networthPerMinute.at(Math.min(10, rivals[1].stats.networthPerMinute.length - 1)) };
|
|
66
|
+
const kills = { radiant: rivals[0].stats.killEvents?.filter(e => e.time <= 600).length || 0, dire: rivals[1].stats.killEvents?.filter(e => e.time <= 600).length || 0 }
|
|
67
|
+
const deaths = { radiant: rivals[0].stats.deathEvents?.filter(e => e.time <= 600).length || 0, dire: rivals[1].stats.deathEvents?.filter(e => e.time <= 600).length || 0 }
|
|
68
|
+
const assists = { radiant: rivals[0].stats.assistEvents?.filter(e => e.time <= 600).length || 0, dire: rivals[1].stats.assistEvents?.filter(e => e.time <= 600).length || 0 }
|
|
69
|
+
const goldSplit = gold.radiant / (gold.radiant + gold.dire);
|
|
70
|
+
return `
|
|
71
|
+
<div class="details">
|
|
72
|
+
<img src="${utils.getImageUrl(rivals[0].hero.shortName, ImageType.HeroIcons)}" class="hero radiant" />
|
|
73
|
+
${generateLevelCircle(rivals[0].stats.experiencePerMinute.slice(0, Math.min(11, rivals[0].stats.experiencePerMinute.length - 1)).reduce((a, b) => a + b, 0))}
|
|
74
|
+
<p class="kda">${kills.radiant}/${deaths.radiant}/${assists.radiant}</p>
|
|
75
|
+
<div class="graph">
|
|
76
|
+
<svg width="100%" height="${svgHeight}" viewBox="0 0 180 ${svgHeight}">
|
|
77
|
+
|
|
78
|
+
<!-- 经济差 -->
|
|
79
|
+
<g transform="translate(0,0)">
|
|
80
|
+
<rect y="9" width="180" height="14" fill="#9c3628"/>
|
|
81
|
+
<rect y="9" width="${180 * goldSplit}" height="14" fill="#3c9028"/>
|
|
82
|
+
<line x1="${180 * goldSplit}" y1="9" x2="${180 * goldSplit}" y2="25"
|
|
83
|
+
stroke="#fff" stroke-width="1"/>
|
|
84
|
+
|
|
85
|
+
<!-- 左侧数值(天辉) -->
|
|
86
|
+
<text x="5" y="50%"
|
|
87
|
+
dominant-baseline="middle"
|
|
88
|
+
fill="#fff"
|
|
89
|
+
font-size="10"
|
|
90
|
+
text-anchor="start">${gold.radiant}</text>
|
|
91
|
+
|
|
92
|
+
<!-- 右侧数值(夜魇) -->
|
|
93
|
+
<text x="175" y="50%"
|
|
94
|
+
dominant-baseline="middle"
|
|
95
|
+
fill="#fff"
|
|
96
|
+
font-size="10"
|
|
97
|
+
text-anchor="end">${gold.dire}</text>
|
|
98
|
+
|
|
99
|
+
<!-- 差值(上方) -->
|
|
100
|
+
<text x="${180 * goldSplit}"
|
|
101
|
+
y="5px"
|
|
102
|
+
dominant-baseline="middle"
|
|
103
|
+
fill="${gold.radiant > gold.dire ? "#3c9028" : "#9c3628"}"
|
|
104
|
+
font-size="10"
|
|
105
|
+
text-anchor="middle">+${Math.abs(gold.dire - gold.radiant)}</text>
|
|
106
|
+
</g>
|
|
107
|
+
</svg>
|
|
108
|
+
</div>
|
|
109
|
+
<p class="kda">${kills.dire}/${deaths.dire}/${assists.dire}</p>
|
|
110
|
+
${generateLevelCircle(rivals[1].stats.experiencePerMinute.slice(0, Math.min(11, rivals[1].stats.experiencePerMinute.length - 1)).reduce((a, b) => a + b, 0))}
|
|
111
|
+
<img src="${utils.getImageUrl(rivals[1].hero.shortName, ImageType.HeroIcons)}" class="hero dire" />
|
|
112
|
+
</div>
|
|
113
|
+
`
|
|
114
|
+
}
|
|
115
|
+
%>
|
|
116
|
+
<div class="lane_outcome">
|
|
117
|
+
<h4 class="title">对线</h4>
|
|
118
|
+
<div class="panel">
|
|
119
|
+
<div class="lane">
|
|
120
|
+
<div class="title">
|
|
121
|
+
<p><%= $t("dota2tracker.template.lane_top") %></p>
|
|
122
|
+
<p class="<%= match.topLaneOutcome.split("_")[0].toLowerCase() %>"><%= $t("dota2tracker.template.OUTCOME_MAP."+match.topLaneOutcome) %></p>
|
|
123
|
+
</div>
|
|
124
|
+
<%- generateDetails(match.players.filter(p => (p.position.slice(-1) == 3 && p.isRadiant) || (p.position.slice(-1) == 1 && !p.isRadiant))) %>
|
|
125
|
+
<%- generateDetails(match.players.filter(p => (p.position.slice(-1) == 4 && p.isRadiant) || (p.position.slice(-1) == 5 && !p.isRadiant))) %>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="lane">
|
|
128
|
+
<div class="title">
|
|
129
|
+
<p><%= $t("dota2tracker.template.lane_mid") %></p>
|
|
130
|
+
<p class="<%= match.midLaneOutcome.split("_")[0].toLowerCase() %>"><%= $t("dota2tracker.template.OUTCOME_MAP."+match.midLaneOutcome) %></p>
|
|
131
|
+
</div>
|
|
132
|
+
<%- generateDetails(match.players.filter(p => p.position.slice(-1) == 2)) %>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="lane">
|
|
135
|
+
<div class="title">
|
|
136
|
+
<p><%= $t("dota2tracker.template.lane_bottom") %></p>
|
|
137
|
+
<p class="<%= match.bottomLaneOutcome.split("_")[0].toLowerCase() %>"><%= $t("dota2tracker.template.OUTCOME_MAP."+match.bottomLaneOutcome) %></p>
|
|
138
|
+
</div>
|
|
139
|
+
<%- generateDetails(match.players.filter(p => (p.position.slice(-1) == 1 && p.isRadiant) || (p.position.slice(-1) == 3 && !p.isRadiant))) %>
|
|
140
|
+
<%- generateDetails(match.players.filter(p => (p.position.slice(-1) == 5 && p.isRadiant) || (p.position.slice(-1) == 4 && !p.isRadiant))) %>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" />
|
|
8
8
|
<%- "<style>" %>
|
|
9
9
|
<%- include("./match_2/original.css") %>
|
|
10
|
-
<%- include("./match_2
|
|
10
|
+
<%- include("./match_2+/extra.css") %>
|
|
11
11
|
<%- "</style>" %>
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<section id="regular"><%- include('./match_2/original') %></section>
|
|
15
15
|
<section id="extra">
|
|
16
16
|
<% if (data.parsedDateTime && data.radiantNetworthLeads && data.radiantExperienceLeads) { %>
|
|
17
|
-
<%- include('./match_2
|
|
17
|
+
<%- include('./match_2+/charts') %>
|
|
18
|
+
<%- include('./match_2+/lane_outcome') %>
|
|
18
19
|
<% } else { %>
|
|
19
20
|
<div class="tip">比赛未解析或无局势信息,无法展示更多数据。</div>
|
|
20
21
|
<% } %>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
html {
|
|
2
|
-
overflow: visible;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
body {
|
|
6
|
-
/* width: 1200px; */
|
|
7
|
-
display: flex;
|
|
8
|
-
flex-direction: column;
|
|
9
|
-
overflow: visible;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
#regular {
|
|
13
|
-
width: 800px;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
#extra {
|
|
17
|
-
display: flex;
|
|
18
|
-
width: 800px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
#charts {
|
|
22
|
-
display: flex;
|
|
23
|
-
flex-direction: row;
|
|
24
|
-
width: 100%;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
#charts > svg {
|
|
28
|
-
font-size: 10px;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#charts > .title {
|
|
32
|
-
width: 100%;
|
|
33
|
-
display: flex;
|
|
34
|
-
justify-content: space-between;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
#charts > .title > .logo {
|
|
38
|
-
display: flex;
|
|
39
|
-
padding: 0 25px;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
#charts > .title > .logo > img{
|
|
43
|
-
width: 20px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
#extra > .tip {
|
|
47
|
-
width: 100%;
|
|
48
|
-
line-height: 4;
|
|
49
|
-
text-align: center;
|
|
50
|
-
color: #ccc;
|
|
51
|
-
}
|
|
File without changes
|