koishi-plugin-haulmp-tools 1.0.0 → 1.0.2
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/announce.js +10 -10
- package/lib/command/bind.js +16 -16
- package/lib/command/changelog.js +11 -11
- package/lib/command/company.js +37 -37
- package/lib/command/locate.js +67 -16
- package/lib/command/login.js +29 -29
- package/lib/command/menu.js +12 -12
- package/lib/command/query.js +33 -33
- package/lib/command/ranking.js +24 -24
- package/lib/command/status.js +15 -15
- package/lib/command/traffic.js +13 -13
- package/lib/command/version.js +21 -21
- package/lib/util/common.js +13 -13
- package/package.json +1 -1
package/lib/command/announce.js
CHANGED
|
@@ -38,17 +38,17 @@ function annCard(row, ann, titleCn, bodyCn) {
|
|
|
38
38
|
const body = bodyCn || ann.body || ''
|
|
39
39
|
const tag = row.tag || 'VTC'
|
|
40
40
|
const initial = String(tag.replace(/[^A-Za-z0-9\u4e00-\u9fa5]/g, '')[0] || 'V').toUpperCase()
|
|
41
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
42
|
-
.head{display:flex;align-items:center;gap:14px;padding-bottom:16px;border-bottom:1px solid
|
|
43
|
-
.ava{width:
|
|
41
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#d97706', '#f59e0b', 720)}
|
|
42
|
+
.head{display:flex;align-items:center;gap:14px;padding-bottom:16px;border-bottom:1px solid var(--edge)}
|
|
43
|
+
.ava{width:56px;height:56px;border-radius:18px;background:linear-gradient(150deg,rgba(255,255,255,.95),rgba(255,247,232,.7));border:1px solid rgba(217,119,6,.35);color:#92400e;font-weight:700;font-size:22px;display:flex;align-items:center;justify-content:center;flex:none;box-shadow:var(--panel-shadow)}
|
|
44
44
|
.who{flex:1;min-width:0}
|
|
45
|
-
.kicker{font-size:13px;color
|
|
46
|
-
.cname{font-size:20px;font-weight:700;color
|
|
47
|
-
.cname .tag{color:#
|
|
48
|
-
.stamp{width:
|
|
49
|
-
.title{margin-top:20px;font-size:20px;font-weight:700;color
|
|
50
|
-
.body{margin-top:12px;font-size:14.5px;line-height:1.95;color
|
|
51
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid
|
|
45
|
+
.kicker{font-size:13px;color:var(--t3);letter-spacing:1px}
|
|
46
|
+
.cname{font-size:20px;font-weight:700;color:var(--t1);margin-top:3px}
|
|
47
|
+
.cname .tag{color:#9a6b1f;font-size:13px;font-weight:600;margin-left:8px}
|
|
48
|
+
.stamp{width:62px;height:62px;border:2px solid rgba(217,119,6,.55);border-radius:50%;color:#b45309;font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center;letter-spacing:3px;transform:rotate(-12deg);background:rgba(255,255,255,.55);box-shadow:var(--panel-shadow);flex:none}
|
|
49
|
+
.title{margin-top:20px;font-size:20px;font-weight:700;color:var(--t1);line-height:1.5;padding-left:14px;border-left:4px solid rgba(217,119,6,.65)}
|
|
50
|
+
.body{margin-top:12px;font-size:14.5px;line-height:1.95;color:var(--t2);white-space:pre-wrap;padding:13px 17px;background:var(--glass-2);border:1px solid var(--stroke);border-radius:16px;box-shadow:var(--panel-shadow)}
|
|
51
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
52
52
|
</style></head><body><div id="card">${CARD_DECO}
|
|
53
53
|
<div class="head"><div class="ava">${esc(initial)}</div><div class="who"><div class="kicker">车队公告</div><div class="cname">${esc(row.name || row.slug)}<span class="tag">${esc(tag)}</span></div></div><div class="stamp">公告</div></div>
|
|
54
54
|
<div class="title">${esc(title)}</div>
|
package/lib/command/bind.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
const { bindingQuery, esc, avatarUrl, resolveAvatar, renderCard, isText, cardTheme, CARD_DECO } = require('../util/common')
|
|
2
2
|
const { fetchProfile } = require('../api/forumApi')
|
|
3
3
|
|
|
4
|
-
// 🎨
|
|
5
|
-
//
|
|
6
|
-
const CARD_CSS = cardTheme('#
|
|
7
|
-
.hero{position:relative;height:150px;margin:-26px -28px 0;background:linear-gradient(120deg,rgba(
|
|
8
|
-
.hero::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at 50%
|
|
9
|
-
.avatar{width:104px;height:104px;border-radius:50%;object-fit:cover;border:
|
|
10
|
-
.avatar.ph{display:flex;align-items:center;justify-content:center;margin:0 auto;font-size:40px;font-weight:700;color:#
|
|
11
|
-
h1{color
|
|
12
|
-
.uline{width:60px;height:3px;margin:11px auto 0;border-radius:2px;background:linear-gradient(90deg,transparent,var(--ac),transparent)
|
|
13
|
-
.name{margin-top:16px;font-size:25px;color
|
|
14
|
-
.handle{font-size:14px;color:#
|
|
4
|
+
// 🎨 设计提示词(绑定成功):入会证。薄荷绿柔光自顶部漫下 + 白色磨砂玻璃卡面,
|
|
5
|
+
// 头像用白色描边浮起,像一张清透的会员卡;文字全部深色,干净、明亮、有质感。
|
|
6
|
+
const CARD_CSS = cardTheme('#10b981', '#38bdf8', 640) + `
|
|
7
|
+
.hero{position:relative;height:150px;margin:-26px -28px 0;background:linear-gradient(120deg,rgba(16,185,129,.26),rgba(56,189,248,.20) 58%,rgba(255,255,255,.06));overflow:hidden}
|
|
8
|
+
.hero::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at 50% 132%,rgba(255,255,255,.78),transparent 62%)}
|
|
9
|
+
.avatar{width:104px;height:104px;border-radius:50%;object-fit:cover;border:4px solid rgba(255,255,255,.95);background:#eef3f9;box-shadow:0 16px 34px -14px rgba(13,124,88,.5),0 0 0 1px rgba(124,144,196,.14)}
|
|
10
|
+
.avatar.ph{display:flex;align-items:center;justify-content:center;margin:0 auto;font-size:40px;font-weight:700;color:#0b7a5b;background:linear-gradient(150deg,rgba(16,185,129,.34),rgba(56,189,248,.26))}
|
|
11
|
+
h1{color:var(--t1);font-size:26px;margin-top:16px;letter-spacing:6px;text-align:center}
|
|
12
|
+
.uline{width:60px;height:3px;margin:11px auto 0;border-radius:2px;background:linear-gradient(90deg,transparent,var(--ac),transparent)}
|
|
13
|
+
.name{margin-top:16px;font-size:25px;color:var(--t1);font-weight:700;text-align:center}
|
|
14
|
+
.handle{font-size:14px;color:#3d7fbe;text-align:center;margin-top:4px}
|
|
15
15
|
.ribbon{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:18px}
|
|
16
|
-
.rchip{font-size:12.5px;color:#
|
|
17
|
-
.rchip b{color
|
|
18
|
-
.hint{margin-top:18px;font-size:13px;color
|
|
19
|
-
.hint b{color
|
|
20
|
-
.foot{margin-top:22px;padding-top:13px;border-top:1px solid
|
|
16
|
+
.rchip{font-size:12.5px;color:#42536f;background:var(--glass-2);border:1px solid var(--stroke);border-radius:999px;padding:5px 14px;box-shadow:var(--panel-shadow)}
|
|
17
|
+
.rchip b{color:var(--t1)}
|
|
18
|
+
.hint{margin-top:18px;font-size:13px;color:var(--t3);line-height:1.85;text-align:center}
|
|
19
|
+
.hint b{color:var(--t2)}
|
|
20
|
+
.foot{margin-top:22px;padding-top:13px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:12px;color:var(--t3)}
|
|
21
21
|
`
|
|
22
22
|
|
|
23
23
|
function successCard(member, session, avatarSrc) {
|
package/lib/command/changelog.js
CHANGED
|
@@ -48,18 +48,18 @@ function updateCard(status, notesCn, oldVersion) {
|
|
|
48
48
|
const notes = notesCn || status.notes || '(本次更新无说明)'
|
|
49
49
|
const nm = String(status.notes || '').match(/HaulMP\s+([\d.]+)/i)
|
|
50
50
|
const verName = nm ? nm[1] : ''
|
|
51
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
52
|
-
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid
|
|
53
|
-
.title{font-size:24px;font-weight:700;color
|
|
54
|
-
.brand{color:#
|
|
51
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#0284c7', '#06b6d4', 720)}
|
|
52
|
+
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
53
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
54
|
+
.brand{color:#2b6f96;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
55
55
|
.verline{display:flex;align-items:center;gap:14px;margin-top:18px}
|
|
56
|
-
.vold{color
|
|
57
|
-
.arrow{color:#
|
|
58
|
-
.vname{font-size:15px;font-weight:700;color:#
|
|
59
|
-
.vnew{font-size:22px;font-weight:800;color:#
|
|
60
|
-
.vinfo{margin-left:auto;color
|
|
61
|
-
.notes{margin-top:16px;padding:14px 18px;background:var(--glass-
|
|
62
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid
|
|
56
|
+
.vold{color:var(--t3);font-size:15px;padding:6px 13px;border:1px solid var(--edge);border-radius:12px;background:var(--glass-3)}
|
|
57
|
+
.arrow{color:#0284c7;font-size:19px;font-weight:700}
|
|
58
|
+
.vname{font-size:15px;font-weight:700;color:#075985;background:var(--glass-2);border:1px solid rgba(2,132,199,.35);border-radius:999px;padding:5px 13px;box-shadow:var(--panel-shadow)}
|
|
59
|
+
.vnew{font-size:22px;font-weight:800;color:#075985;padding:6px 17px;background:linear-gradient(180deg,rgba(255,255,255,.92),rgba(224,242,254,.75));border:1px solid rgba(2,132,199,.4);border-radius:16px;box-shadow:var(--panel-shadow)}
|
|
60
|
+
.vinfo{margin-left:auto;color:var(--t3);font-size:12.5px;text-align:right;line-height:1.7}
|
|
61
|
+
.notes{margin-top:16px;padding:14px 18px;background:var(--glass-2);border:1px solid var(--stroke);border-left:4px solid rgba(2,132,199,.75);border-radius:14px;font-size:14.5px;line-height:1.9;color:var(--t2);white-space:pre-wrap;box-shadow:var(--panel-shadow)}
|
|
62
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
63
63
|
</style></head><body><div id="card">${CARD_DECO}
|
|
64
64
|
<div class="head"><span class="title">HaulMP 客户端更新</span><span class="brand">RELEASE</span></div>
|
|
65
65
|
<div class="verline">${oldVersion ? `<span class="vold">v${oldVersion}</span><span class="arrow">→</span>` : ''}<span class="vnew">v${status.version}</span>${verName ? `<span class="vname">HaulMP ${verName}</span>` : ''}<span class="vinfo">发布于 ${fmtPublished(status.publishedAt) || '—'}<br>${fmtBytes(status.bytes)}</span></div>
|
package/lib/command/company.js
CHANGED
|
@@ -2,37 +2,37 @@ const { esc, fmtTime, renderCard, bindingQuery, isText, cardTheme, CARD_DECO } =
|
|
|
2
2
|
const { fetchCompany } = require('../api/vtcApi')
|
|
3
3
|
const { loadSnap, saveSnap, makeSnap, rotateSnapshots, todayStr, fmtKm } = require('../database/companySnap')
|
|
4
4
|
|
|
5
|
-
const cardCssFor = (accent) => cardTheme(accent || '#
|
|
5
|
+
const cardCssFor = (accent) => cardTheme(accent || '#0d9488', '#38bdf8', 780) + `
|
|
6
6
|
.head{display:flex;align-items:baseline;justify-content:space-between}
|
|
7
|
-
.title{font-size:23px;font-weight:700;color
|
|
8
|
-
.brand{color:#
|
|
9
|
-
.sub{font-size:12.5px;color
|
|
7
|
+
.title{font-size:23px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
8
|
+
.brand{color:#5a6a8c;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
9
|
+
.sub{font-size:12.5px;color:var(--t3);margin-top:6px}
|
|
10
10
|
.podium{display:flex;align-items:flex-end;justify-content:center;gap:14px;margin-top:24px;padding:0 8px}
|
|
11
11
|
.pod{flex:1;max-width:220px;text-align:center;min-width:0}
|
|
12
|
-
.podium .pname{color
|
|
13
|
-
.podium .phandle{color:#
|
|
14
|
-
.podium .pkm{color:#
|
|
15
|
-
.pbase{border-radius:
|
|
16
|
-
.pod1 .pbase{height:76px;background:linear-gradient(180deg,rgba(
|
|
17
|
-
.pod2 .pbase{height:54px;background:linear-gradient(180deg,rgba(
|
|
18
|
-
.pod3 .pbase{height:42px;background:linear-gradient(180deg,rgba(
|
|
19
|
-
.board{margin-top:18px;background:var(--glass);border:1px solid var(--stroke);border-radius:
|
|
12
|
+
.podium .pname{color:var(--t1);font-weight:700;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
13
|
+
.podium .phandle{color:#6b7ba0;font-size:11.5px;margin-top:2px}
|
|
14
|
+
.podium .pkm{color:#0f766e;font-weight:700;font-size:14px;margin:9px 0 9px}
|
|
15
|
+
.pbase{border-radius:14px 14px 0 0;display:flex;align-items:flex-start;justify-content:center;padding-top:9px;font-size:21px;font-weight:800;box-shadow:var(--panel-shadow)}
|
|
16
|
+
.pod1 .pbase{height:76px;background:linear-gradient(180deg,rgba(251,191,36,.85),rgba(255,255,255,.7));color:#8a4b06}
|
|
17
|
+
.pod2 .pbase{height:54px;background:linear-gradient(180deg,rgba(203,213,225,.9),rgba(255,255,255,.7));color:#475569}
|
|
18
|
+
.pod3 .pbase{height:42px;background:linear-gradient(180deg,rgba(251,146,60,.7),rgba(255,255,255,.7));color:#9a3412}
|
|
19
|
+
.board{margin-top:18px;background:var(--glass-2);border:1px solid var(--stroke);border-radius:18px;overflow:hidden;box-shadow:var(--panel-shadow)}
|
|
20
20
|
.row{display:flex;align-items:center;gap:12px;padding:10px 16px}
|
|
21
|
-
.row + .row{border-top:1px solid
|
|
22
|
-
.row.me{background:linear-gradient(90deg,rgba(
|
|
23
|
-
.pos{width:34px;text-align:center;font-weight:700;font-size:14.5px;color:#
|
|
21
|
+
.row + .row{border-top:1px solid var(--edge-2)}
|
|
22
|
+
.row.me{background:linear-gradient(90deg,rgba(13,148,136,.20),rgba(129,140,248,.16))}
|
|
23
|
+
.pos{width:34px;text-align:center;font-weight:700;font-size:14.5px;color:#5a6a8c;flex:none}
|
|
24
24
|
.who{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
25
|
-
.who b{color
|
|
26
|
-
.who span{color:#
|
|
27
|
-
.km{font-size:14.5px;font-weight:700;color:#
|
|
28
|
-
.km small{color
|
|
29
|
-
.you{display:inline-block;font-size:11px;color:#
|
|
30
|
-
.empty{padding:16px;color
|
|
31
|
-
.mine{margin-top:18px;background:linear-gradient(180deg,rgba(
|
|
32
|
-
.mine .lab{font-size:13px;color:#
|
|
33
|
-
.mine b{color
|
|
34
|
-
.mine .note{font-size:12.5px;color
|
|
35
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid
|
|
25
|
+
.who b{color:var(--t1);font-size:14.5px;font-weight:600}
|
|
26
|
+
.who span{color:#6b7ba0;font-size:12.5px;margin-left:7px}
|
|
27
|
+
.km{font-size:14.5px;font-weight:700;color:#0f766e;flex:none}
|
|
28
|
+
.km small{color:var(--t3);font-size:11.5px;font-weight:400;margin-left:8px}
|
|
29
|
+
.you{display:inline-block;font-size:11px;color:#0b7a5b;border:1px solid rgba(16,185,129,.45);background:rgba(255,255,255,.72);border-radius:999px;padding:1px 8px;margin-left:8px}
|
|
30
|
+
.empty{padding:16px;color:var(--t3);font-size:13px;text-align:center}
|
|
31
|
+
.mine{margin-top:18px;background:linear-gradient(180deg,rgba(255,255,255,.85),rgba(232,250,244,.62));border:1px solid rgba(13,148,136,.28);border-radius:18px;padding:14px 16px;display:flex;align-items:center;justify-content:space-between;gap:12px;box-shadow:var(--panel-shadow)}
|
|
32
|
+
.mine .lab{font-size:13px;color:#0f766e;flex:none;letter-spacing:1px;font-weight:600}
|
|
33
|
+
.mine b{color:var(--t1);font-size:17px}
|
|
34
|
+
.mine .note{font-size:12.5px;color:var(--t3)}
|
|
35
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:12px;color:var(--t3)}
|
|
36
36
|
`
|
|
37
37
|
|
|
38
38
|
function keyOf(session) {
|
|
@@ -162,19 +162,19 @@ function bindCard(company, rosterCount) {
|
|
|
162
162
|
const founded = fmtDate(c.createdAt)
|
|
163
163
|
const acc = c.accent || '#4a90d9'
|
|
164
164
|
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme(acc, '#7fb4e6', 720)}
|
|
165
|
-
.head{display:flex;align-items:center;gap:16px;padding-bottom:16px;border-bottom:1px solid var(--
|
|
166
|
-
.ava{width:
|
|
165
|
+
.head{display:flex;align-items:center;gap:16px;padding-bottom:16px;border-bottom:1px solid var(--edge)}
|
|
166
|
+
.ava{width:66px;height:66px;border-radius:20px;background:linear-gradient(150deg,rgba(255,255,255,.95),rgba(255,255,255,.6));border:1px solid var(--stroke);color:var(--t1);font-weight:800;font-size:26px;display:flex;align-items:center;justify-content:center;flex:none;box-shadow:var(--panel-shadow)}
|
|
167
167
|
.who{flex:1;min-width:0}
|
|
168
|
-
.kicker{font-size:13px;color
|
|
169
|
-
.cname{font-size:24px;font-weight:800;color
|
|
170
|
-
.cname .tag{color:#
|
|
171
|
-
.ok{flex:none;background:
|
|
172
|
-
.facts{display:flex;margin-top:18px;background:
|
|
168
|
+
.kicker{font-size:13px;color:var(--t3);letter-spacing:1px}
|
|
169
|
+
.cname{font-size:24px;font-weight:800;color:var(--t1);margin-top:3px;letter-spacing:.5px}
|
|
170
|
+
.cname .tag{color:#5a6a8c;font-size:13px;font-weight:600;margin-left:8px}
|
|
171
|
+
.ok{flex:none;background:rgba(255,255,255,.8);border:1px solid rgba(16,185,129,.45);color:#0b7a5b;font-weight:700;font-size:13.5px;border-radius:999px;padding:7px 14px;box-shadow:0 10px 22px -12px rgba(13,124,88,.6)}
|
|
172
|
+
.facts{display:flex;margin-top:18px;background:var(--glass-2);border:1px solid var(--stroke);border-radius:20px;overflow:hidden;box-shadow:var(--panel-shadow)}
|
|
173
173
|
.fact{flex:1;text-align:center;padding:15px 8px;min-width:0}
|
|
174
|
-
.fact + .fact{border-left:1px solid
|
|
175
|
-
.fact b{display:block;font-size:22px;color
|
|
176
|
-
.fact span{display:block;font-size:12px;color
|
|
177
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--
|
|
174
|
+
.fact + .fact{border-left:1px solid var(--edge-2)}
|
|
175
|
+
.fact b{display:block;font-size:22px;color:var(--t1);font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
176
|
+
.fact span{display:block;font-size:12px;color:var(--t3);margin-top:4px;letter-spacing:.5px}
|
|
177
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
178
178
|
</style></head><body><div id="card">${CARD_DECO}
|
|
179
179
|
<div class="head"><div class="ava">${esc(initial)}</div><div class="who"><div class="kicker">车队绑定成功</div><div class="cname">${esc(c.name)}<span class="tag">${esc(tag)}</span></div></div><div class="ok">已绑定本群</div></div>
|
|
180
180
|
<div class="facts">
|
package/lib/command/locate.js
CHANGED
|
@@ -42,18 +42,26 @@ async function syncTileVersion(ctx, force) {
|
|
|
42
42
|
const mVer = js.match(/\/tiles\/\{z\}\/\{x\}\/\{y\}\.pbf\?v=([^"'`]+)/)
|
|
43
43
|
if (!mVer) return
|
|
44
44
|
const version = mVer[1]
|
|
45
|
-
const current = await page.evaluate(() => window.getTileUrl())
|
|
46
|
-
if (current
|
|
45
|
+
const current = await page.evaluate(() => (typeof window.getTileUrl === 'function' ? window.getTileUrl() : ''))
|
|
46
|
+
if (!current) {
|
|
47
|
+
ctx.logger('haulmp').warn('地图版本同步跳过:页面瓦片源为空(底图资源可能未加载)')
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
if (current.includes(version)) return
|
|
47
51
|
const newUrl = `/proxy/tiles/{z}/{x}/{y}.pbf?v=${version}`
|
|
48
52
|
const ok = await page.evaluate((u) => window.setTileUrl(u), newUrl)
|
|
49
|
-
ctx.logger('haulmp').info('地图瓦片版本同步: %s -> %s (%s)', current
|
|
53
|
+
ctx.logger('haulmp').info('地图瓦片版本同步: %s -> %s (%s)', current.split('v=')[1] || current, version, ok ? 'ok' : 'fail')
|
|
50
54
|
} catch (e) {
|
|
51
55
|
ctx.logger('haulmp').warn('地图版本同步失败: %s', e.message)
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
let httpServer = null
|
|
60
|
+
let httpPort = 0
|
|
56
61
|
let mapPage = null
|
|
62
|
+
let mapPageReady = false
|
|
63
|
+
let mapPageInit = null
|
|
64
|
+
let mapPageLock = Promise.resolve()
|
|
57
65
|
|
|
58
66
|
function withTimeout(promise, ms, onTimeout) {
|
|
59
67
|
let timer
|
|
@@ -68,8 +76,8 @@ function withTimeout(promise, ms, onTimeout) {
|
|
|
68
76
|
])
|
|
69
77
|
}
|
|
70
78
|
|
|
71
|
-
function startStaticServer() {
|
|
72
|
-
if (httpServer) return
|
|
79
|
+
async function startStaticServer(ctx) {
|
|
80
|
+
if (httpServer) return httpPort
|
|
73
81
|
// lib/command/locate.js → lib/resource/map;src/command/locate.js → src/resource/map(相对层级一致)
|
|
74
82
|
const root = path.join(__dirname, '..', 'resource', 'map')
|
|
75
83
|
httpServer = http.createServer((req, res) => {
|
|
@@ -116,34 +124,75 @@ function startStaticServer() {
|
|
|
116
124
|
res.end('not found')
|
|
117
125
|
}
|
|
118
126
|
})
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
// 端口随机分配(0 = 系统分配),避免 12665 被残留进程占用时静默失效
|
|
128
|
+
await new Promise((resolve) => {
|
|
129
|
+
httpServer.once('error', (e) => {
|
|
130
|
+
ctx.logger('haulmp').warn('地图本地服务启动失败: %s', e.message)
|
|
131
|
+
resolve(0)
|
|
132
|
+
})
|
|
133
|
+
httpServer.listen(0, '127.0.0.1', () => {
|
|
134
|
+
httpPort = httpServer.address().port
|
|
135
|
+
resolve(httpPort)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
return httpPort
|
|
121
139
|
}
|
|
122
140
|
|
|
123
141
|
async function getMapPage(ctx) {
|
|
142
|
+
// 排队锁:并发调用(启动预热 / 版本同步 / 定位)串行初始化,避免拿到半成品页面
|
|
143
|
+
const run = mapPageLock.then(() => doGetMapPage(ctx), () => doGetMapPage(ctx))
|
|
144
|
+
mapPageLock = run.then(() => {}, () => {})
|
|
145
|
+
return run
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function doGetMapPage(ctx) {
|
|
124
149
|
let puppeteer = null
|
|
125
150
|
try {
|
|
126
151
|
puppeteer = ctx.get('puppeteer')
|
|
127
152
|
} catch (e) { /* ignore */ }
|
|
128
153
|
if (!puppeteer) return null
|
|
129
|
-
startStaticServer()
|
|
130
|
-
if (
|
|
154
|
+
const port = await startStaticServer(ctx)
|
|
155
|
+
if (!port) return null
|
|
156
|
+
if (mapPage && mapPageReady) {
|
|
131
157
|
try {
|
|
132
158
|
if (!mapPage.isClosed()) {
|
|
133
159
|
ctx.logger('haulmp').info('使用已就绪地图页面')
|
|
134
160
|
return mapPage
|
|
135
161
|
}
|
|
136
162
|
} catch (e) { /* ignore */ }
|
|
163
|
+
mapPage = null
|
|
164
|
+
mapPageReady = false
|
|
137
165
|
}
|
|
166
|
+
if (mapPage) {
|
|
167
|
+
// 上一次初始化失败残留的半成品页面,丢弃重建
|
|
168
|
+
try { mapPage.close().catch(() => {}) } catch (e) { /* ignore */ }
|
|
169
|
+
mapPage = null
|
|
170
|
+
mapPageReady = false
|
|
171
|
+
}
|
|
172
|
+
|
|
138
173
|
ctx.logger('haulmp').info('重建地图页面…')
|
|
139
|
-
mapPage = await puppeteer.page()
|
|
140
174
|
const t0 = Date.now()
|
|
141
|
-
|
|
142
|
-
await
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
175
|
+
mapPageReady = false
|
|
176
|
+
mapPage = await puppeteer.page()
|
|
177
|
+
try {
|
|
178
|
+
mapPage.on('pageerror', (err) => {
|
|
179
|
+
ctx.logger('haulmp').warn('地图页面脚本错误: %s', err && err.message ? err.message : String(err))
|
|
180
|
+
})
|
|
181
|
+
await mapPage.setViewport({ width: 720, height: 500, deviceScaleFactor: 2 })
|
|
182
|
+
await mapPage.goto(`http://127.0.0.1:${port}/`, { waitUntil: 'domcontentloaded', timeout: 30000 })
|
|
183
|
+
// __ready(底图 load 事件)与 getTileUrl(模块执行完成)都满足才算就绪
|
|
184
|
+
await mapPage.waitForFunction(() => window.__ready === true && typeof window.getTileUrl === 'function', { timeout: 30000 })
|
|
185
|
+
mapPageReady = true
|
|
186
|
+
ctx.logger('haulmp').info('地图页面构建完成 %dms', Date.now() - t0)
|
|
187
|
+
preloadEurope(mapPage).catch(() => {})
|
|
188
|
+
return mapPage
|
|
189
|
+
} catch (e) {
|
|
190
|
+
ctx.logger('haulmp').warn('地图页面初始化失败: %s', e.message)
|
|
191
|
+
try { mapPage.close().catch(() => {}) } catch (err) { /* ignore */ }
|
|
192
|
+
mapPage = null
|
|
193
|
+
mapPageReady = false
|
|
194
|
+
return null
|
|
195
|
+
}
|
|
147
196
|
}
|
|
148
197
|
|
|
149
198
|
async function preloadEurope(page) {
|
|
@@ -176,6 +225,7 @@ async function doMapShot(ctx, info, p, nearby) {
|
|
|
176
225
|
const resetPage = () => {
|
|
177
226
|
try { page.close().catch(() => {}) } catch (e) { /* ignore */ }
|
|
178
227
|
mapPage = null
|
|
228
|
+
mapPageReady = false
|
|
179
229
|
}
|
|
180
230
|
const t1 = Date.now()
|
|
181
231
|
await withTimeout(
|
|
@@ -199,6 +249,7 @@ async function doMapShot(ctx, info, p, nearby) {
|
|
|
199
249
|
if (mapPage) {
|
|
200
250
|
try { mapPage.close().catch(() => {}) } catch (err) { /* ignore */ }
|
|
201
251
|
mapPage = null
|
|
252
|
+
mapPageReady = false
|
|
202
253
|
}
|
|
203
254
|
return null
|
|
204
255
|
}
|
package/lib/command/login.js
CHANGED
|
@@ -78,18 +78,18 @@ function notifyCard(row, items, unread) {
|
|
|
78
78
|
const unreadCls = i.readAt ? '' : ' on'
|
|
79
79
|
return `<div class="nrow${unreadCls}"><span class="nk">${esc(kind)}</span><span class="nt">${esc(actor)}:${esc(i.title || '')}</span><span class="nw">${fmtWhen(i.createdAt)}</span></div>`
|
|
80
80
|
}).join('')
|
|
81
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
82
|
-
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid
|
|
83
|
-
.title{font-size:24px;font-weight:700;color
|
|
84
|
-
.badge{background:linear-gradient(180deg,rgba(
|
|
81
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#4f46e5', '#7c3aed', 720)}
|
|
82
|
+
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
83
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
84
|
+
.badge{background:linear-gradient(180deg,rgba(255,255,255,.92),rgba(238,242,255,.7));border:1px solid rgba(79,70,229,.32);color:#3730a3;font-weight:700;font-size:14px;border-radius:999px;padding:5px 14px;box-shadow:var(--panel-shadow)}
|
|
85
85
|
.rows{margin-top:14px}
|
|
86
|
-
.nrow{display:flex;align-items:center;gap:12px;padding:11px 4px;border-bottom:1px solid
|
|
87
|
-
.nrow.on .nk{color:#
|
|
88
|
-
.nk{color:#
|
|
89
|
-
.nt{flex:1;min-width:0;color
|
|
90
|
-
.nw{color
|
|
91
|
-
.empty{padding:22px;text-align:center;color
|
|
92
|
-
.foot{margin-top:16px;padding-top:12px;border-top:1px solid
|
|
86
|
+
.nrow{display:flex;align-items:center;gap:12px;padding:11px 4px;border-bottom:1px solid var(--edge-2)}
|
|
87
|
+
.nrow.on .nk{color:#047857}
|
|
88
|
+
.nk{color:#4a3fc0;font-weight:700;font-size:13px;flex:none;width:118px}
|
|
89
|
+
.nt{flex:1;min-width:0;color:var(--t2);font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
90
|
+
.nw{color:var(--t3);font-size:12px;flex:none}
|
|
91
|
+
.empty{padding:22px;text-align:center;color:var(--t3);font-size:14px}
|
|
92
|
+
.foot{margin-top:16px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
93
93
|
</style></head><body><div id="card">${CARD_DECO}
|
|
94
94
|
<div class="head"><span class="title">我的通知</span><span class="badge">${unread} 条未读</span></div>
|
|
95
95
|
<div class="rows">${rows || '<div class="empty">暂无通知</div>'}</div>
|
|
@@ -118,24 +118,24 @@ function driveCard(row, me, game) {
|
|
|
118
118
|
const span = x.closed_at ? `${fmtWhen(x.started_at)} → ${fmtWhen(x.closed_at)}` : `${fmtWhen(x.started_at)} · 进行中`
|
|
119
119
|
return `<div class="srow"><span class="sspan">${esc(span)}</span><span class="ssrv">${esc(x.server_name || '')}</span><span class="skm">${fmtKm(x.distance_km)} km</span><span class="sdur">${dur}</span></div>`
|
|
120
120
|
}).join('')
|
|
121
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
122
|
-
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid
|
|
123
|
-
.title{font-size:24px;font-weight:700;color
|
|
121
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#059669', '#0284c7', 760)}
|
|
122
|
+
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
123
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
124
124
|
.state{font-size:13px;font-weight:700;border-radius:999px;padding:5px 13px}
|
|
125
|
-
.state.on{color:#
|
|
126
|
-
.state.off{color
|
|
125
|
+
.state.on{color:#0b7a5b;background:rgba(255,255,255,.85);border:1px solid rgba(16,185,129,.42);box-shadow:var(--panel-shadow)}
|
|
126
|
+
.state.off{color:var(--t3);background:var(--glass-3);border:1px solid var(--edge)}
|
|
127
127
|
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:18px}
|
|
128
|
-
.st{background:var(--glass-
|
|
129
|
-
.st b{display:block;font-size:20px;color
|
|
130
|
-
.st span{display:block;font-size:11.5px;color
|
|
131
|
-
.sec{margin-top:18px;font-size:12.5px;color:#
|
|
132
|
-
.srow{display:flex;align-items:center;gap:12px;padding:10px 4px;border-bottom:1px solid
|
|
133
|
-
.sspan{flex:1;min-width:0;color
|
|
134
|
-
.ssrv{color:#
|
|
135
|
-
.skm{color:#
|
|
136
|
-
.sdur{color
|
|
137
|
-
.empty{padding:18px;text-align:center;color
|
|
138
|
-
.foot{margin-top:16px;padding-top:12px;border-top:1px solid
|
|
128
|
+
.st{background:var(--glass-2);border:1px solid var(--stroke);border-radius:18px;padding:12px 8px;text-align:center;box-shadow:var(--panel-shadow)}
|
|
129
|
+
.st b{display:block;font-size:20px;color:var(--t1);font-weight:800}
|
|
130
|
+
.st span{display:block;font-size:11.5px;color:var(--t3);margin-top:4px}
|
|
131
|
+
.sec{margin-top:18px;font-size:12.5px;color:#0f766e;font-weight:700;letter-spacing:2px}
|
|
132
|
+
.srow{display:flex;align-items:center;gap:12px;padding:10px 4px;border-bottom:1px solid var(--edge-2);font-size:13px}
|
|
133
|
+
.sspan{flex:1;min-width:0;color:var(--t2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
134
|
+
.ssrv{color:#5a6a8c;flex:none}
|
|
135
|
+
.skm{color:#047857;font-weight:700;flex:none}
|
|
136
|
+
.sdur{color:var(--t3);flex:none;width:90px;text-align:right}
|
|
137
|
+
.empty{padding:18px;text-align:center;color:var(--t3);font-size:13.5px}
|
|
138
|
+
.foot{margin-top:16px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
139
139
|
</style></head><body><div id="card">${CARD_DECO}
|
|
140
140
|
<div class="head"><span class="title">我的行驶记录</span><span class="state ${recording ? 'on' : 'off'}">${recording ? `正在录制 · ${esc(recording.server_name || '')}` : '未连接驾驶'}</span></div>
|
|
141
141
|
<div class="stats">
|
|
@@ -318,7 +318,7 @@ function apply(ctx, config) {
|
|
|
318
318
|
})
|
|
319
319
|
|
|
320
320
|
ctx.command('找回密码', '私信重置 HaulMP 密码(恢复码,无邮件重置)')
|
|
321
|
-
.alias('找回密码h', '找回密码H'
|
|
321
|
+
.alias('找回密码h', '找回密码H')
|
|
322
322
|
.action(async ({ session }) => {
|
|
323
323
|
if (!session) return
|
|
324
324
|
if (!isPrivate(session)) return '请私聊机器人发送「找回密码」'
|
|
@@ -384,4 +384,4 @@ function apply(ctx, config) {
|
|
|
384
384
|
})
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
module.exports = { apply }
|
|
387
|
+
module.exports = { apply, notifyCard, notifyText, driveCard, driveText }
|
package/lib/command/menu.js
CHANGED
|
@@ -38,18 +38,18 @@ function menuCard() {
|
|
|
38
38
|
const rows = items.map(([cmd, desc]) => `<div class="mrow"><span class="cmd">${cmd}</span><span class="desc">${desc}</span></div>`).join('')
|
|
39
39
|
return `<div class="mtitle">${title}</div>${rows}`
|
|
40
40
|
}).join('')
|
|
41
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#6366f1', '#
|
|
42
|
-
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid
|
|
43
|
-
.title{font-size:24px;font-weight:700;color
|
|
44
|
-
.brand{color:#
|
|
41
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#6366f1', '#a855f7', 780)}
|
|
42
|
+
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
43
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
44
|
+
.brand{color:#6b6fd0;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
45
45
|
.mgrid{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-top:14px}
|
|
46
|
-
.mtitle{grid-column:1 / -1;display:flex;align-items:center;gap:9px;font-size:12.5px;color:#
|
|
46
|
+
.mtitle{grid-column:1 / -1;display:flex;align-items:center;gap:9px;font-size:12.5px;color:#4a4fb0;font-weight:700;letter-spacing:2px;margin-top:10px}
|
|
47
47
|
.mtitle:first-child{margin-top:0}
|
|
48
|
-
.mtitle::before{content:'';width:3px;height:
|
|
49
|
-
.mrow{background:
|
|
50
|
-
.cmd{display:block;font-size:13px;color:#
|
|
51
|
-
.desc{display:block;font-size:11.5px;color
|
|
52
|
-
.foot{margin-top:17px;padding-top:12px;border-top:1px solid
|
|
48
|
+
.mtitle::before{content:'';width:3px;height:13px;border-radius:2px;background:linear-gradient(180deg,var(--ac),var(--ac2))}
|
|
49
|
+
.mrow{background:var(--glass-2);border:1px solid var(--stroke);border-radius:16px;padding:9px 12px;min-width:0;box-shadow:var(--panel-shadow)}
|
|
50
|
+
.cmd{display:block;font-size:13px;color:#3f43a8;font-weight:700;font-family:Consolas,"Cascadia Mono",monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
51
|
+
.desc{display:block;font-size:11.5px;color:var(--t3);margin-top:3px;line-height:1.45}
|
|
52
|
+
.foot{margin-top:17px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
53
53
|
</style></head><body><div id="card">${CARD_DECO}
|
|
54
54
|
<div class="head"><span class="title">HaulMP 功能菜单</span><span class="brand">MENU</span></div>
|
|
55
55
|
<div class="mgrid">${sections}</div>
|
|
@@ -69,8 +69,8 @@ function menuText() {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
function apply(ctx, config) {
|
|
72
|
-
ctx.command('菜单', 'HaulMP 功能菜单')
|
|
73
|
-
.alias('menuh'
|
|
72
|
+
ctx.command('菜单h', 'HaulMP 功能菜单')
|
|
73
|
+
.alias('menuh')
|
|
74
74
|
.action(async ({ session }) => {
|
|
75
75
|
if (!session) return
|
|
76
76
|
if (!isText(config, 'menu')) {
|
package/lib/command/query.js
CHANGED
|
@@ -65,51 +65,51 @@ const BADGES = [
|
|
|
65
65
|
['still_truckin', '初心不改', (m, now) => !!m.memberSince && now - new Date(m.memberSince).getTime() >= 365 * 864e5 && !!m.lastActive && now - new Date(m.lastActive).getTime() < 30 * 864e5],
|
|
66
66
|
]
|
|
67
67
|
|
|
68
|
-
const CARD_CSS = cardTheme('#
|
|
69
|
-
.hero{position:relative;margin:-26px -28px 0;height:112px;background:linear-gradient(120deg,rgba(
|
|
70
|
-
.hero::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at
|
|
68
|
+
const CARD_CSS = cardTheme('#4f46e5', '#0ea5e9', 820) + `
|
|
69
|
+
.hero{position:relative;margin:-26px -28px 0;height:112px;background:linear-gradient(120deg,rgba(99,102,241,.28),rgba(14,165,233,.22) 62%,rgba(255,255,255,.06))}
|
|
70
|
+
.hero::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at 78% -28%,rgba(255,255,255,.82),transparent 58%)}
|
|
71
71
|
.hero-row{position:relative;display:block;height:100%;padding:0;z-index:2}
|
|
72
|
-
.avatar{position:absolute;left:28px;top:10px;width:92px;height:92px;border-radius:24px;object-fit:cover;border:
|
|
73
|
-
.avatar.ph{display:flex;align-items:center;justify-content:center;font-size:38px;font-weight:700;color:#
|
|
72
|
+
.avatar{position:absolute;left:28px;top:10px;width:92px;height:92px;border-radius:24px;object-fit:cover;border:4px solid rgba(255,255,255,.95);background:#eef3f9;box-shadow:0 16px 32px -14px rgba(49,60,120,.5)}
|
|
73
|
+
.avatar.ph{display:flex;align-items:center;justify-content:center;font-size:38px;font-weight:700;color:#3730a3;background:linear-gradient(150deg,rgba(99,102,241,.32),rgba(14,165,233,.28))}
|
|
74
74
|
.hero-who{position:absolute;left:140px;right:170px;top:50%;transform:translateY(-50%);min-width:0}
|
|
75
|
-
.name{font-size:26px;font-weight:700;color
|
|
76
|
-
.handle{font-size:14px;color:#
|
|
75
|
+
.name{font-size:26px;font-weight:700;color:var(--t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
76
|
+
.handle{font-size:14px;color:#6b7ba0;font-weight:400;margin-left:8px}
|
|
77
77
|
.hero-right{position:absolute;top:12px;right:28px;display:flex;gap:10px;align-items:center}
|
|
78
|
-
.brand{color:rgba(
|
|
79
|
-
.bound{display:inline-block;font-size:12px;color:#
|
|
80
|
-
.status{font-size:13.5px;color
|
|
81
|
-
.dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:7px;background:#
|
|
82
|
-
.dot.on{background:#
|
|
78
|
+
.brand{color:rgba(60,74,120,.55);font-size:13px;font-weight:700;letter-spacing:2px}
|
|
79
|
+
.bound{display:inline-block;font-size:12px;color:#0b7a5b;border:1px solid rgba(16,185,129,.45);background:rgba(255,255,255,.72);border-radius:999px;padding:2px 10px;box-shadow:0 8px 18px -10px rgba(13,124,88,.55)}
|
|
80
|
+
.status{font-size:13.5px;color:var(--t2);margin-top:6px}
|
|
81
|
+
.dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:7px;background:#a8b3c7}
|
|
82
|
+
.dot.on{background:#10b981;box-shadow:0 0 0 4px rgba(16,185,129,.18)}
|
|
83
83
|
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
|
|
84
|
-
.chip{font-size:12.5px;color:#
|
|
85
|
-
.chip.gold{color:#
|
|
84
|
+
.chip{font-size:12.5px;color:#3730a3;background:linear-gradient(180deg,rgba(255,255,255,.88),rgba(255,255,255,.58));border:1px solid rgba(99,102,241,.28);border-radius:999px;padding:3px 12px;white-space:nowrap;box-shadow:0 8px 18px -12px rgba(58,76,140,.55),inset 0 1px 0 rgba(255,255,255,.9)}
|
|
85
|
+
.chip.gold{color:#9a5b06;background:linear-gradient(180deg,rgba(255,255,255,.88),rgba(255,248,232,.62));border-color:rgba(217,119,6,.32)}
|
|
86
86
|
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:16px}
|
|
87
|
-
.stat{position:relative;overflow:hidden;background:
|
|
88
|
-
.stat::before{content:'';position:absolute;top:0;left:
|
|
89
|
-
.stat b{display:block;font-size:23px;color
|
|
90
|
-
.stat span{display:block;font-size:12px;color
|
|
87
|
+
.stat{position:relative;overflow:hidden;background:var(--glass-2);border:1px solid var(--stroke);border-radius:18px;padding:13px 8px 11px;text-align:center;box-shadow:var(--panel-shadow)}
|
|
88
|
+
.stat::before{content:'';position:absolute;top:0;left:22%;right:22%;height:3px;border-radius:0 0 3px 3px;background:linear-gradient(90deg,transparent,var(--ac),var(--ac2),transparent)}
|
|
89
|
+
.stat b{display:block;font-size:23px;color:var(--t1);font-weight:700}
|
|
90
|
+
.stat span{display:block;font-size:12px;color:var(--t3);margin-top:4px;letter-spacing:.5px}
|
|
91
91
|
.top{display:flex;gap:26px;margin-top:20px;align-items:flex-start}
|
|
92
92
|
.tcol{flex:1;min-width:0}
|
|
93
93
|
.tcol.wide{flex:1.35}
|
|
94
94
|
.section{margin-top:20px}
|
|
95
95
|
.top .section{margin-top:0}
|
|
96
96
|
.section:first-child{margin-top:20px}
|
|
97
|
-
.section h3{display:flex;align-items:center;gap:9px;font-size:12.5px;color:#
|
|
98
|
-
.section h3::before{content:'';width:3px;height:
|
|
97
|
+
.section h3{display:flex;align-items:center;gap:9px;font-size:12.5px;color:#3f4f7a;font-weight:700;letter-spacing:2px;margin-bottom:10px}
|
|
98
|
+
.section h3::before{content:'';width:3px;height:13px;border-radius:2px;background:linear-gradient(180deg,var(--ac),var(--ac2))}
|
|
99
99
|
.kv{font-size:13.5px;line-height:1.85}
|
|
100
100
|
.kv .row{white-space:normal;word-break:break-all}
|
|
101
|
-
.kv b{color
|
|
102
|
-
.haul{background:var(--glass);border:1px solid
|
|
101
|
+
.kv b{color:var(--t2);font-weight:600;margin-right:7px}
|
|
102
|
+
.haul{background:var(--glass-2);border:1px solid var(--stroke);border-radius:16px;overflow:hidden;box-shadow:var(--panel-shadow)}
|
|
103
103
|
.haul-row{display:flex;align-items:center;gap:12px;padding:10px 14px}
|
|
104
|
-
.haul-row + .haul-row{border-top:1px solid
|
|
104
|
+
.haul-row + .haul-row{border-top:1px solid var(--edge-2)}
|
|
105
105
|
.haul-main{flex:1;min-width:0}
|
|
106
|
-
.haul-route{color
|
|
107
|
-
.haul-cargo{color
|
|
108
|
-
.haul-meta{text-align:right;font-size:12px;color
|
|
109
|
-
.ok{color:#
|
|
110
|
-
.cancel{color:#
|
|
111
|
-
.empty{color
|
|
112
|
-
.foot{margin-top:4px;padding-top:13px;border-top:1px solid
|
|
106
|
+
.haul-route{color:var(--t1);font-weight:600;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
107
|
+
.haul-cargo{color:var(--t3);font-size:12px;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
108
|
+
.haul-meta{text-align:right;font-size:12px;color:var(--t3);flex:none;line-height:1.55}
|
|
109
|
+
.ok{color:#0b9a6b;font-weight:600}
|
|
110
|
+
.cancel{color:#dc2626;font-weight:600}
|
|
111
|
+
.empty{color:var(--t3);font-size:13px;padding:12px 14px;background:var(--glass-3);border:1px solid var(--stroke);border-radius:14px}
|
|
112
|
+
.foot{margin-top:4px;padding-top:13px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:12px;color:var(--t3)}
|
|
113
113
|
`
|
|
114
114
|
|
|
115
115
|
function computeBadges(m, staff, now) {
|
|
@@ -253,7 +253,7 @@ function profileCard(data, extras, opts) {
|
|
|
253
253
|
const rs = (data.recent || []).slice(0, 3)
|
|
254
254
|
let postsHtml = ''
|
|
255
255
|
if (rs.length) {
|
|
256
|
-
postsHtml = `<div class="section"><h3>最近发帖</h3><div class="kv">${rs.map((p) => `<div class="row full">「${esc(p.title)}」<span style="color
|
|
256
|
+
postsHtml = `<div class="section"><h3>最近发帖</h3><div class="kv">${rs.map((p) => `<div class="row full">「${esc(p.title)}」<span style="color:var(--t3)">${esc(p.categoryName || '')} · ${fmtTime(p.createdAt)}</span></div>`).join('')}</div></div>`
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
return `<!doctype html><html><head><meta charset="utf-8"><style>${CARD_CSS}</style></head><body><div id="card">${CARD_DECO}
|
|
@@ -431,7 +431,7 @@ function apply(ctx, config) {
|
|
|
431
431
|
|
|
432
432
|
ctx.command('查询H [handle]', '查询 HaulMP 账号信息')
|
|
433
433
|
.alias('queryh', '查询h')
|
|
434
|
-
.usage('不填时查询已绑定的账号;例如:查询H / 查询H
|
|
434
|
+
.usage('不填时查询已绑定的账号;例如:查询H / 查询H @群友')
|
|
435
435
|
.action(async ({ session }, handle) => {
|
|
436
436
|
if (!session) return
|
|
437
437
|
const raw = String(handle || '').trim()
|
|
@@ -480,7 +480,7 @@ function apply(ctx, config) {
|
|
|
480
480
|
if (data) target = resolved
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
|
-
if (!data) return `没找到「${target}
|
|
483
|
+
if (!data) return `没找到「${target}」。你可以试试:私聊注册账号`
|
|
484
484
|
|
|
485
485
|
let extras = {}
|
|
486
486
|
let avatarSrc = ''
|
package/lib/command/ranking.js
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
const { esc, fmtTime, bindingQuery, renderCard, isText, cardTheme, CARD_DECO } = require('../util/common')
|
|
2
2
|
const { ensureCache } = require('../database/rankCache')
|
|
3
3
|
|
|
4
|
-
const CARD_CSS = cardTheme('#
|
|
4
|
+
const CARD_CSS = cardTheme('#d97706', '#f59e0b', 760) + `
|
|
5
5
|
.head{display:flex;align-items:baseline;justify-content:space-between}
|
|
6
|
-
.title{font-size:24px;font-weight:700;color
|
|
7
|
-
.brand{color:#
|
|
8
|
-
.sub{font-size:12.5px;color
|
|
6
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
7
|
+
.brand{color:#9a6b1f;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
8
|
+
.sub{font-size:12.5px;color:var(--t3);margin-top:6px}
|
|
9
9
|
.podium{display:flex;align-items:flex-end;justify-content:center;gap:14px;margin-top:26px;padding:0 8px}
|
|
10
10
|
.pod{flex:1;max-width:215px;text-align:center;min-width:0}
|
|
11
|
-
.podium .pname{color
|
|
12
|
-
.podium .phandle{color:#
|
|
13
|
-
.podium .pkm{color:#
|
|
14
|
-
.pbase{border-radius:
|
|
15
|
-
.pod1 .pbase{height:76px;background:linear-gradient(180deg,rgba(
|
|
16
|
-
.pod2 .pbase{height:54px;background:linear-gradient(180deg,rgba(
|
|
17
|
-
.pod3 .pbase{height:42px;background:linear-gradient(180deg,rgba(
|
|
18
|
-
.board{margin-top:20px;background:var(--glass);border:1px solid
|
|
11
|
+
.podium .pname{color:var(--t1);font-weight:700;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
12
|
+
.podium .phandle{color:#6b7ba0;font-size:11.5px;margin-top:2px}
|
|
13
|
+
.podium .pkm{color:#b45309;font-weight:700;font-size:14px;margin:9px 0 9px}
|
|
14
|
+
.pbase{border-radius:14px 14px 0 0;display:flex;align-items:flex-start;justify-content:center;padding-top:9px;font-size:21px;font-weight:800;box-shadow:var(--panel-shadow)}
|
|
15
|
+
.pod1 .pbase{height:76px;background:linear-gradient(180deg,rgba(251,191,36,.85),rgba(255,255,255,.7));color:#8a4b06}
|
|
16
|
+
.pod2 .pbase{height:54px;background:linear-gradient(180deg,rgba(203,213,225,.9),rgba(255,255,255,.7));color:#475569}
|
|
17
|
+
.pod3 .pbase{height:42px;background:linear-gradient(180deg,rgba(251,146,60,.7),rgba(255,255,255,.7));color:#9a3412}
|
|
18
|
+
.board{margin-top:20px;background:var(--glass-2);border:1px solid var(--stroke);border-radius:18px;overflow:hidden;box-shadow:var(--panel-shadow)}
|
|
19
19
|
.row{display:flex;align-items:center;gap:12px;padding:10px 16px}
|
|
20
|
-
.row + .row{border-top:1px solid
|
|
21
|
-
.row.me{background:linear-gradient(90deg,rgba(
|
|
22
|
-
.pos{width:34px;text-align:center;font-weight:700;font-size:14.5px;color:#
|
|
20
|
+
.row + .row{border-top:1px solid var(--edge-2)}
|
|
21
|
+
.row.me{background:linear-gradient(90deg,rgba(251,191,36,.22),rgba(129,140,248,.16))}
|
|
22
|
+
.pos{width:34px;text-align:center;font-weight:700;font-size:14.5px;color:#9a6b1f;flex:none}
|
|
23
23
|
.who{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
24
|
-
.who b{color
|
|
25
|
-
.who span{color:#
|
|
26
|
-
.km{font-size:14.5px;font-weight:700;color:#
|
|
27
|
-
.you{display:inline-block;font-size:11px;color:#
|
|
28
|
-
.mine{margin-top:18px;background:linear-gradient(180deg,rgba(
|
|
29
|
-
.mine .lab{font-size:13px;color:#
|
|
30
|
-
.mine b{color
|
|
31
|
-
.mine .note{font-size:12.5px;color
|
|
32
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid
|
|
24
|
+
.who b{color:var(--t1);font-size:14.5px;font-weight:600}
|
|
25
|
+
.who span{color:#6b7ba0;font-size:12.5px;margin-left:7px}
|
|
26
|
+
.km{font-size:14.5px;font-weight:700;color:#b45309;flex:none}
|
|
27
|
+
.you{display:inline-block;font-size:11px;color:#0b7a5b;border:1px solid rgba(16,185,129,.45);background:rgba(255,255,255,.72);border-radius:999px;padding:1px 8px;margin-left:8px}
|
|
28
|
+
.mine{margin-top:18px;background:linear-gradient(180deg,rgba(255,255,255,.85),rgba(255,248,232,.6));border:1px solid rgba(217,119,6,.32);border-radius:18px;padding:14px 16px;display:flex;align-items:center;justify-content:space-between;gap:12px;box-shadow:var(--panel-shadow)}
|
|
29
|
+
.mine .lab{font-size:13px;color:#9a5b06;flex:none;letter-spacing:1px;font-weight:600}
|
|
30
|
+
.mine b{color:var(--t1);font-size:17px}
|
|
31
|
+
.mine .note{font-size:12.5px;color:var(--t3)}
|
|
32
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:12px;color:var(--t3)}
|
|
33
33
|
`
|
|
34
34
|
|
|
35
35
|
function fmtKm(n) {
|
package/lib/command/status.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
const { esc, fmtTime, fetchJsonMemo, renderCard, isText, cardTheme, CARD_DECO } = require('../util/common')
|
|
2
2
|
|
|
3
|
-
const CARD_CSS = cardTheme('#
|
|
3
|
+
const CARD_CSS = cardTheme('#059669', '#0891b2', 720) + `
|
|
4
4
|
.head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:2px}
|
|
5
|
-
.title{font-size:23px;font-weight:700;color
|
|
6
|
-
.brand{color:#
|
|
5
|
+
.title{font-size:23px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
6
|
+
.brand{color:#2f7d6b;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
7
7
|
.hero-num{text-align:center;padding:16px 0 6px}
|
|
8
|
-
.ring{display:inline-flex;align-items:center;justify-content:center;width:
|
|
9
|
-
.dot{width:10px;height:10px;border-radius:50%;background:#
|
|
10
|
-
.dot.on{background:#
|
|
11
|
-
.big{font-size:66px;font-weight:800;
|
|
12
|
-
.cap{color
|
|
13
|
-
.hstate{margin-top:9px;font-size:12.5px;color:#
|
|
8
|
+
.ring{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:50%;background:var(--glass-2);border:1px solid var(--stroke);box-shadow:var(--panel-shadow);margin-bottom:8px}
|
|
9
|
+
.dot{width:10px;height:10px;border-radius:50%;background:#a8b3c7}
|
|
10
|
+
.dot.on{background:#10b981;box-shadow:0 0 0 5px rgba(16,185,129,.18)}
|
|
11
|
+
.big{font-size:66px;font-weight:800;line-height:1.02;background:linear-gradient(150deg,#0f766e,#0ea5e9);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
|
|
12
|
+
.cap{color:var(--t3);font-size:13px;margin-top:6px;letter-spacing:3px}
|
|
13
|
+
.hstate{margin-top:9px;font-size:12.5px;color:#0b7a5b;letter-spacing:2px;font-weight:600}
|
|
14
14
|
.tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:18px}
|
|
15
|
-
.tile{background:
|
|
16
|
-
.tile .t{font-size:12px;color
|
|
17
|
-
.tile .v{font-size:15px;color
|
|
18
|
-
.on{color:#
|
|
19
|
-
.off{color:#
|
|
20
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid
|
|
15
|
+
.tile{background:var(--glass-2);border:1px solid var(--stroke);border-radius:18px;padding:11px 14px;box-shadow:var(--panel-shadow)}
|
|
16
|
+
.tile .t{font-size:12px;color:var(--t3);letter-spacing:1px}
|
|
17
|
+
.tile .v{font-size:15px;color:var(--t1);font-weight:600;margin-top:5px}
|
|
18
|
+
.on{color:#0b7a5b;font-weight:700}
|
|
19
|
+
.off{color:#dc2626;font-weight:700}
|
|
20
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:12px;color:var(--t3)}
|
|
21
21
|
`
|
|
22
22
|
|
|
23
23
|
function fmtBytes(n) {
|
package/lib/command/traffic.js
CHANGED
|
@@ -87,23 +87,23 @@ function trafficCard(list) {
|
|
|
87
87
|
rows.push(`<div class="r"><i style="background:${KINDS[k].color};box-shadow:0 0 10px ${KINDS[k].color}"></i><span class="k">${KINDS[k].zh}</span><span class="city">${esc(it.city)} 附近</span><span class="rm${soon ? ' soon' : ''}">${it.remain ? `剩 ${it.remain} 分钟` : ''}</span></div>`)
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
91
|
-
.head{display:flex;align-items:center;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--
|
|
92
|
-
.title{font-size:24px;font-weight:700;color
|
|
93
|
-
.badge{background:linear-gradient(180deg,rgba(
|
|
90
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#e11d48', '#f59e0b', width)}
|
|
91
|
+
.head{display:flex;align-items:center;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
92
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
93
|
+
.badge{background:linear-gradient(180deg,rgba(255,255,255,.92),rgba(255,241,242,.72));border:1px solid rgba(225,29,72,.32);color:#9f1239;font-weight:700;font-size:15px;border-radius:999px;padding:6px 15px;box-shadow:var(--panel-shadow)}
|
|
94
94
|
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:15px}
|
|
95
|
-
.chip{background:var(--glass-
|
|
96
|
-
.chip b{color
|
|
95
|
+
.chip{background:var(--glass-2);border:1px solid var(--stroke);border-radius:999px;padding:5px 13px;font-size:13px;color:var(--t2);box-shadow:var(--panel-shadow)}
|
|
96
|
+
.chip b{color:var(--t1);margin-left:4px}
|
|
97
97
|
.chip i{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:7px;vertical-align:middle}
|
|
98
|
-
.list{margin-top:15px;background:var(--glass-
|
|
98
|
+
.list{margin-top:15px;background:var(--glass-2);border:1px solid var(--stroke);border-radius:20px;overflow:hidden;column-count:${cols};column-gap:0;box-shadow:var(--panel-shadow)}
|
|
99
99
|
.r{display:flex;align-items:center;gap:12px;padding:9px 16px;break-inside:avoid}
|
|
100
|
-
.r + .r{border-top:1px solid
|
|
100
|
+
.r + .r{border-top:1px solid var(--edge-2)}
|
|
101
101
|
.r > i{width:9px;height:9px;border-radius:50%;flex:none}
|
|
102
|
-
.r .k{width:52px;font-size:13.5px;font-weight:600;color
|
|
103
|
-
.r .city{flex:1;min-width:0;font-size:13.5px;color
|
|
104
|
-
.r .rm{font-size:12.5px;color
|
|
105
|
-
.r .rm.soon{color:#
|
|
106
|
-
.foot{margin-top:16px;padding-top:12px;border-top:1px solid var(--
|
|
102
|
+
.r .k{width:52px;font-size:13.5px;font-weight:600;color:var(--t2);flex:none}
|
|
103
|
+
.r .city{flex:1;min-width:0;font-size:13.5px;color:var(--t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
104
|
+
.r .rm{font-size:12.5px;color:var(--t3);flex:none}
|
|
105
|
+
.r .rm.soon{color:#b45309;font-weight:700}
|
|
106
|
+
.foot{margin-top:16px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
107
107
|
</style></head><body><div id="card">${CARD_DECO}
|
|
108
108
|
<div class="head"><span class="title">HaulMP 实时路况</span><span class="badge">${list.length} 处</span></div>
|
|
109
109
|
<div class="chips">${chips}</div>
|
package/lib/command/version.js
CHANGED
|
@@ -64,19 +64,19 @@ function versionCard(v) {
|
|
|
64
64
|
c.bytes ? fmtBytes(c.bytes) : '',
|
|
65
65
|
c.publishedAt ? `发布 ${fmtWhen(c.publishedAt)}` : '',
|
|
66
66
|
].filter(Boolean).join(' · ')
|
|
67
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
68
|
-
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid
|
|
69
|
-
.title{font-size:24px;font-weight:700;color
|
|
70
|
-
.brand{color:#
|
|
67
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#0284c7', '#06b6d4', 720)}
|
|
68
|
+
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
69
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
70
|
+
.brand{color:#2b6f96;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
71
71
|
.hero-v{text-align:center;padding:18px 0 4px}
|
|
72
|
-
.hlab{font-size:13px;color
|
|
73
|
-
.hbig{font-size:58px;font-weight:800;line-height:1.1;margin-top:8px;background:linear-gradient(
|
|
74
|
-
.hsub{color
|
|
72
|
+
.hlab{font-size:13px;color:var(--t3);letter-spacing:4px}
|
|
73
|
+
.hbig{font-size:58px;font-weight:800;line-height:1.1;margin-top:8px;background:linear-gradient(150deg,#0369a1,#06b6d4);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
|
|
74
|
+
.hsub{color:var(--t3);font-size:12.5px;margin-top:10px}
|
|
75
75
|
.tiles{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:22px}
|
|
76
|
-
.tile{background:var(--glass-
|
|
77
|
-
.tile .t{font-size:12.5px;color
|
|
78
|
-
.tile .v{font-size:27px;font-weight:800;color
|
|
79
|
-
.foot{margin-top:20px;padding-top:12px;border-top:1px solid
|
|
76
|
+
.tile{background:var(--glass-2);border:1px solid var(--stroke);border-radius:20px;padding:16px 12px;text-align:center;box-shadow:var(--panel-shadow)}
|
|
77
|
+
.tile .t{font-size:12.5px;color:var(--t3);letter-spacing:1px}
|
|
78
|
+
.tile .v{font-size:27px;font-weight:800;color:var(--t1);margin-top:8px}
|
|
79
|
+
.foot{margin-top:20px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
80
80
|
</style></head><body><div id="card">${CARD_DECO}
|
|
81
81
|
<div class="head"><span class="title">版本信息</span><span class="brand">VERSION</span></div>
|
|
82
82
|
<div class="hero-v"><div class="hlab">HAULMP 客户端</div><div class="hbig">${esc(big)}</div><div class="hsub">${esc(sub || '—')}</div></div>
|
|
@@ -115,18 +115,18 @@ function saveState(ctx, st) {
|
|
|
115
115
|
|
|
116
116
|
function gameCard(changes) {
|
|
117
117
|
const rows = changes.map(([g, from, to]) => `<div class="grow"><span class="gname">${esc(g)}</span><span class="gfrom">${esc(from)}</span><span class="garrow">→</span><span class="gnew">${esc(to)}</span></div>`).join('')
|
|
118
|
-
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#
|
|
119
|
-
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid
|
|
120
|
-
.title{font-size:24px;font-weight:700;color
|
|
121
|
-
.brand{color:#
|
|
118
|
+
return `<!doctype html><html><head><meta charset="utf-8"><style>${cardTheme('#059669', '#0284c7', 720)}
|
|
119
|
+
.head{display:flex;align-items:baseline;justify-content:space-between;padding-bottom:15px;border-bottom:1px solid var(--edge)}
|
|
120
|
+
.title{font-size:24px;font-weight:700;color:var(--t1);letter-spacing:1px}
|
|
121
|
+
.brand{color:#2f7d6b;font-size:13px;font-weight:700;letter-spacing:2px}
|
|
122
122
|
.rows{margin-top:18px}
|
|
123
|
-
.grow{display:flex;align-items:center;gap:14px;background:var(--glass-
|
|
123
|
+
.grow{display:flex;align-items:center;gap:14px;background:var(--glass-2);border:1px solid var(--stroke);border-radius:20px;padding:16px 18px;box-shadow:var(--panel-shadow)}
|
|
124
124
|
.grow + .grow{margin-top:12px}
|
|
125
|
-
.gname{flex:1;color
|
|
126
|
-
.gfrom{color
|
|
127
|
-
.garrow{color:#
|
|
128
|
-
.gnew{font-size:17px;font-weight:800;color:#
|
|
129
|
-
.foot{margin-top:18px;padding-top:12px;border-top:1px solid
|
|
125
|
+
.gname{flex:1;color:var(--t1);font-weight:700;font-size:16px}
|
|
126
|
+
.gfrom{color:var(--t3);font-size:15px;text-decoration:line-through;opacity:.9}
|
|
127
|
+
.garrow{color:#0b7a5b;font-weight:700;font-size:17px}
|
|
128
|
+
.gnew{font-size:17px;font-weight:800;color:#047857}
|
|
129
|
+
.foot{margin-top:18px;padding-top:12px;border-top:1px solid var(--edge);display:flex;justify-content:space-between;font-size:11.5px;color:var(--t3)}
|
|
130
130
|
</style></head><body><div id="card">${CARD_DECO}
|
|
131
131
|
<div class="head"><span class="title">游戏版本更新</span><span class="brand">GAME</span></div>
|
|
132
132
|
<div class="rows">${rows}</div>
|
package/lib/util/common.js
CHANGED
|
@@ -3,24 +3,24 @@ const fs = require('fs')
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const { FONT } = require('./constant')
|
|
5
5
|
|
|
6
|
-
// 🎨
|
|
7
|
-
// -
|
|
8
|
-
// -
|
|
9
|
-
// -
|
|
10
|
-
// -
|
|
6
|
+
// 🎨 共享卡片主题:浅色极光玻璃拟态(Light Aurora Glass)
|
|
7
|
+
// - 底色:柔和彩色极光渐变(靛蓝 / 天蓝 / 薄荷 / 琥珀 / 粉),直接画在 body 上
|
|
8
|
+
// - 卡面:白色磨砂玻璃(半透明 + backdrop-filter 强模糊 + 白色描边 + 内外双高光 + 柔和投影)
|
|
9
|
+
// - 装饰:顶部极光光带 + 两团柔光(沿用 .glow / .orb 结构,改为亮色柔光)
|
|
10
|
+
// - 每张卡仍保留各自的强调色(--ac / --ac2)
|
|
11
11
|
function cardTheme(accent, accent2, width) {
|
|
12
12
|
const a2 = accent2 || accent
|
|
13
|
-
return `:root{--ac:${accent};--ac2:${a2};--glass:rgba(255,255,255,.
|
|
13
|
+
return `:root{--ac:${accent};--ac2:${a2};--glass:rgba(255,255,255,.68);--glass-2:rgba(255,255,255,.52);--glass-3:rgba(255,255,255,.34);--stroke:rgba(255,255,255,.95);--edge:rgba(124,144,196,.22);--edge-2:rgba(124,144,196,.13);--t1:#16203a;--t2:#48587a;--t3:#7b8aa5;--card-shadow:0 26px 64px -24px rgba(58,76,140,.50);--panel-shadow:0 12px 30px -16px rgba(58,76,140,.36),inset 0 1px 0 rgba(255,255,255,.95)}
|
|
14
14
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
15
|
-
body{background:#
|
|
16
|
-
#card{position:relative;overflow:hidden;width:${width || 720}px;background:linear-gradient(
|
|
17
|
-
#card::before{content:'';position:absolute;inset:0;z-index:0;pointer-events:none;background:
|
|
15
|
+
body{background-color:#eef2fc;background-image:radial-gradient(48% 42% at 8% 2%,rgba(129,140,248,.62),transparent 64%),radial-gradient(44% 40% at 94% 6%,rgba(56,189,248,.52),transparent 62%),radial-gradient(50% 46% at 90% 94%,rgba(52,211,153,.48),transparent 64%),radial-gradient(46% 40% at 6% 98%,rgba(251,191,36,.44),transparent 62%),radial-gradient(40% 36% at 50% 50%,rgba(244,114,182,.30),transparent 66%),radial-gradient(34% 30% at 62% 12%,rgba(167,139,250,.40),transparent 64%);background-repeat:no-repeat;font-family:${FONT}}
|
|
16
|
+
#card{position:relative;overflow:hidden;width:${width || 720}px;padding:26px 28px 16px;color:var(--t2);border-radius:26px;background:linear-gradient(150deg,rgba(255,255,255,.60),rgba(248,251,255,.38) 48%,rgba(255,255,255,.54));border:1px solid var(--stroke);box-shadow:var(--card-shadow),inset 0 1px 0 rgba(255,255,255,.98),inset 0 -1px 0 rgba(255,255,255,.35);backdrop-filter:saturate(190%) blur(26px);-webkit-backdrop-filter:saturate(190%) blur(26px)}
|
|
17
|
+
#card::before{content:'';position:absolute;inset:0;z-index:0;pointer-events:none;background:linear-gradient(180deg,rgba(255,255,255,.55),transparent 24%),linear-gradient(115deg,rgba(255,255,255,.42) 0%,rgba(255,255,255,.06) 34%,transparent 58%)}
|
|
18
18
|
#card>*{position:relative;z-index:1}
|
|
19
19
|
#card>.glow,#card>.orb{z-index:0}
|
|
20
|
-
#card>.glow{position:absolute;top:0;left:0;right:0;height:
|
|
21
|
-
#card>.orb{position:absolute;border-radius:50%;filter:blur(
|
|
22
|
-
#card>.orb1{width:
|
|
23
|
-
#card>.orb2{width:
|
|
20
|
+
#card>.glow{position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,transparent,var(--ac) 26%,var(--ac2) 74%,transparent);opacity:.9;box-shadow:0 6px 24px -4px var(--ac)}
|
|
21
|
+
#card>.orb{position:absolute;border-radius:50%;filter:blur(72px);pointer-events:none}
|
|
22
|
+
#card>.orb1{width:330px;height:330px;background:var(--ac);top:-180px;right:-120px;opacity:.34}
|
|
23
|
+
#card>.orb2{width:270px;height:270px;background:var(--ac2);bottom:-160px;left:-100px;opacity:.26}`
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const CARD_DECO = '<div class="glow"></div><div class="orb orb1"></div><div class="orb orb2"></div>'
|