1+ import { Router , Request , Response } from "express" ;
2+ import { Controller } from "../controller" ;
3+ import { login as fishpiLogin , register as fishpiRegister , updateUserInfo } from "../login/fishpi" ;
4+ import { login as steamLogin } from "../login/steam" ;
5+ import { bind as steamBind } from "../login/steam" ;
6+ import { login as githubLogin , bind as githubBind } from "../login/github" ;
7+ import { login as wechatLogin , bind as wechatBind } from "../login/wechat" ;
8+ import { Record , RecordRepo , User , UserRepo , AppDataSource , PlayerStats , ManageRepo , UserBindRepo } from "@/entities" ;
9+ import { getPlayerStats , getPlayerStat , isConfigured } from "@/utils" ;
10+ import { FindOptionsWhere , Like } from "typeorm" ;
11+ import GameRouter from "./game" ;
12+ import Games , { GameRoom } from "@/games" ;
13+ import { getThirdPartyType , saveUser } from "@/login" ;
14+ import FishPi from "fishpi" ;
15+
16+
17+ const router = Router ( ) ;
18+
19+ router . get ( '/:username/:game' , async ( req : Request , res : Response ) => {
20+ const { username, game } = req . params ;
21+
22+ try {
23+ const stats = await getPlayerStat ( username , game ) ;
24+ const gameName = Games [ game ] ?. name || game ;
25+ let htmlContent = '' ;
26+ if ( stats ) {
27+ const winPercent = stats . total > 0 ? ( stats . wins / stats . total * 100 ) : 0 ;
28+ const drawPercent = stats . total > 0 ? ( stats . draws / stats . total * 100 ) : 0 ;
29+ const lossPercent = stats . total > 0 ? ( stats . losses / stats . total * 100 ) : 0 ;
30+ htmlContent = `
31+ <style>
32+ .card { background-color: #f3f4f6; border-radius: 8px; padding: 16px; font-family: system-ui, -apple-system, sans-serif; box-sizing: border-box; }
33+ .header { display: flex; justify-content: space-between; align-items: baseline; }
34+ .game-name { font-size: 14px; font-weight: bold; margin-bottom: 4px; }
35+ .score-label { font-size: 12px; opacity: 0.6; }
36+ .stats { display: flex; justify-content: space-between; font-size: 12px; }
37+ .win { color: #16a34a; }
38+ .draw { color: #ca8a04; }
39+ .loss { color: #dc2626; }
40+ .progress-bar { width: 100%; background-color: #e5e7eb; border-radius: 9999px; height: 8px; margin-top: 8px; overflow: hidden; display: flex; }
41+ .progress-win { background-color: #16a34a; height: 100%; }
42+ .progress-draw { background-color: #ca8a04; height: 100%; }
43+ .progress-loss { background-color: #dc2626; height: 100%; }
44+ .score-container { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 8px 0; }
45+ .score { font-size: 30px; font-weight: 900; color: #06b6d4; }
46+ .bottom { text-align: right; font-size: 12px; margin-top: 4px; opacity: 0.6; padding-right: 4px; }
47+ </style>
48+ <div class="card">
49+ <header class="header">
50+ <div class="game-name">${ gameName } </div>
51+ ${ stats . score ? '<div class="score-label">最高得分</div>' : '' }
52+ </header>
53+ ${ ! stats . score ? `
54+ <div class="stats">
55+ <span class="win">胜: ${ stats . wins } </span>
56+ <span class="draw">平: ${ stats . draws } </span>
57+ <span class="loss">负: ${ stats . losses } </span>
58+ </div>
59+ <div class="progress-bar">
60+ <div class="progress-win" style="width: ${ winPercent } %;"></div>
61+ <div class="progress-draw" style="width: ${ drawPercent } %;"></div>
62+ <div class="progress-loss" style="width: ${ lossPercent } %;"></div>
63+ </div>
64+ ` : `
65+ <div class="score-container">
66+ <div class="score">${ stats . score } </div>
67+ </div>
68+ ` }
69+ <div class="bottom">游玩次数:${ stats . total } </div>
70+ </div>
71+ <div class="bottom">@${ username } </div>
72+ ` ;
73+ } else {
74+ htmlContent = `
75+ <style>
76+ .no-data { background-color: #f3f4f6; border-radius: 8px; padding: 16px; font-family: system-ui, -apple-system, sans-serif; box-sizing: border-box; display: flex; align-items: center; justify-content: center; }
77+ .no-data-text { text-align: center; color: #6b7280; }
78+ </style>
79+ <div class="no-data">
80+ <div class="no-data-text">未找到 ${ username } 在 ${ gameName } 中的战绩</div>
81+ </div>
82+ ` ;
83+ }
84+ const svg = `
85+ <svg width="400" height="168" xmlns="http://www.w3.org/2000/svg">
86+ <foreignObject x="0" y="0" width="400" height="168">
87+ <html xmlns="http://www.w3.org/1999/xhtml">
88+ ${ htmlContent }
89+ </html>
90+ </foreignObject>
91+ </svg>
92+ ` ;
93+ res . setHeader ( 'Content-Type' , 'image/svg+xml; charset=utf-8' ) ;
94+ res . send ( svg ) ;
95+ } catch ( error ) {
96+ console . error ( error ) ;
97+ const errorSvg = `
98+ <svg width="400" height="168" xmlns="http://www.w3.org/2000/svg">
99+ <foreignObject x="0" y="0" width="400" height="168">
100+ <html xmlns="http://www.w3.org/1999/xhtml">
101+ <style>
102+ .error { color: red; text-align: center; padding: 20px; width: 400px; height: 168px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; }
103+ </style>
104+ <div class="error">服务器错误</div>
105+ </html>
106+ </foreignObject>
107+ </svg>
108+ ` ;
109+ res . status ( 500 ) . send ( errorSvg ) ;
110+ }
111+ } ) ;
112+
113+ export default router ;
0 commit comments