[fix] table width + text selectiion + batch note naming
This commit is contained in:
@@ -214,7 +214,7 @@ function extractFpsMetrics(result: string): { avg: number | null; p1: number | n
|
||||
function NoteCell({ note, onEdit }: { note: string; onEdit: () => void }) {
|
||||
return (
|
||||
<div className="flex items-center min-w-0 gap-1">
|
||||
<span className="flex-1 min-w-0 truncate">
|
||||
<span className="flex-1 min-w-0 truncate select-text">
|
||||
{note || "无备注"}
|
||||
</span>
|
||||
<Button
|
||||
@@ -278,6 +278,10 @@ export function FpsTest() {
|
||||
const testStartVideoSettingRef = useRef<typeof tool.state.videoSetting | null>(null)
|
||||
// 记录当前测试的分辨率信息(用于备注)
|
||||
const currentTestResolutionRef = useRef<{ width: string; height: string; label: string } | null>(null)
|
||||
// 记录当前分辨率在分辨率组中的索引和总测试次数(用于批量测试备注)
|
||||
const currentResolutionGroupInfoRef = useRef<{ resIndex: number; totalResolutions: number; totalTestCount: number; currentBatchIndex: number; batchCount: number } | null>(null)
|
||||
// 记录最后一次测试的时间戳(用于平均值记录)
|
||||
const lastTestTimestampRef = useRef<string | null>(null)
|
||||
|
||||
// 检测游戏是否运行
|
||||
const checkGameRunning = useCallback(async () => {
|
||||
@@ -426,6 +430,8 @@ export function FpsTest() {
|
||||
|
||||
setTestResult(parsed.data)
|
||||
setTestTimestamp(parsed.timestamp)
|
||||
// 保存最后一次测试的时间戳(用于平均值记录)
|
||||
lastTestTimestampRef.current = parsed.timestamp
|
||||
// 成功读取后,清除测试开始时间戳(测试已完成)
|
||||
testStartTimestampRef.current = null
|
||||
testStartTimeRef.current = null
|
||||
@@ -461,6 +467,7 @@ export function FpsTest() {
|
||||
// 如果是批量测试,保存结果到批量结果数组,否则直接保存
|
||||
const currentBatchProgress = batchTestProgress
|
||||
const currentResolution = currentTestResolutionRef.current
|
||||
const resolutionGroupInfo = currentResolutionGroupInfoRef.current
|
||||
if (currentBatchProgress) {
|
||||
const result = { avg, p1 }
|
||||
setBatchTestResults((prev) => [...prev, result])
|
||||
@@ -474,9 +481,18 @@ export function FpsTest() {
|
||||
if (testNote) {
|
||||
batchNote = batchNote ? `${testNote} ${batchNote}` : testNote
|
||||
}
|
||||
batchNote = batchNote
|
||||
? `${batchNote} [批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
||||
: `[批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
||||
|
||||
// 如果启用了分辨率组,使用新的备注格式:[分辨率] [批量当前测试/该分辨率批量总数]
|
||||
if (resolutionGroupInfo && isResolutionGroupEnabled) {
|
||||
const { currentBatchIndex, batchCount } = resolutionGroupInfo
|
||||
const batchInfo = `[批量${currentBatchIndex}/${batchCount}]`
|
||||
batchNote = batchNote ? `${batchNote} ${batchInfo}` : batchInfo
|
||||
} else {
|
||||
// 普通批量测试,使用原来的格式
|
||||
batchNote = batchNote
|
||||
? `${batchNote} [批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
||||
: `[批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
||||
}
|
||||
|
||||
fpsTest.addResult({
|
||||
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
|
||||
@@ -550,6 +566,8 @@ export function FpsTest() {
|
||||
// 清除保存的启动时视频设置和分辨率信息
|
||||
testStartVideoSettingRef.current = null
|
||||
currentTestResolutionRef.current = null
|
||||
currentResolutionGroupInfoRef.current = null
|
||||
// 注意:不清除lastTestTimestampRef,因为平均值记录需要使用它
|
||||
|
||||
if (!silent) {
|
||||
if (avg !== null || p1 !== null) {
|
||||
@@ -633,6 +651,7 @@ export function FpsTest() {
|
||||
testStartTimeRef.current = null
|
||||
testStartVideoSettingRef.current = null
|
||||
currentTestResolutionRef.current = null
|
||||
currentResolutionGroupInfoRef.current = null
|
||||
addToast({
|
||||
title: "测试超时(200秒),测试失败",
|
||||
variant: "flat",
|
||||
@@ -826,6 +845,7 @@ export function FpsTest() {
|
||||
testStartTimeRef.current = null
|
||||
testStartVideoSettingRef.current = null
|
||||
currentTestResolutionRef.current = null
|
||||
currentResolutionGroupInfoRef.current = null
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -848,6 +868,17 @@ export function FpsTest() {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查垂直同步设置,如果开启则提醒(但不阻止测试)
|
||||
if (steam.state.steamDirValid && steam.currentUser()) {
|
||||
await tool.getVideoConfig(steam.state.steamDir, steam.currentUser()?.steam_id32 || 0)
|
||||
if (tool.state.videoSetting?.mat_vsync === "1") {
|
||||
addToast({
|
||||
title: "警告:垂直同步已开启,可能会影响测试结果准确性",
|
||||
color: "warning",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const totalTests = batchTestCount
|
||||
batchTestAbortRef.current = false
|
||||
setBatchTestResults([])
|
||||
@@ -879,6 +910,15 @@ export function FpsTest() {
|
||||
globalTestIndex++
|
||||
setBatchTestProgress({ current: globalTestIndex, total: totalTestCount })
|
||||
|
||||
// 设置当前分辨率组信息(用于备注)
|
||||
currentResolutionGroupInfoRef.current = {
|
||||
resIndex,
|
||||
totalResolutions,
|
||||
totalTestCount,
|
||||
currentBatchIndex: i,
|
||||
batchCount: totalTests,
|
||||
}
|
||||
|
||||
// 执行单次测试,第一次测试跳过5秒等待
|
||||
const isFirstTest = resIndex === 0 && i === 1
|
||||
const success = await runSingleTest(i, totalTests, isFirstTest, currentResolution)
|
||||
@@ -915,23 +955,50 @@ export function FpsTest() {
|
||||
validResults.reduce((sum, r) => sum + (r.avg || 0), 0) / validResults.length
|
||||
const avgP1 = validResults.reduce((sum, r) => sum + (r.p1 || 0), 0) / validResults.length
|
||||
|
||||
const now = new Date()
|
||||
const testDate = now.toISOString()
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0")
|
||||
const day = String(now.getDate()).padStart(2, "0")
|
||||
const hour = String(now.getHours()).padStart(2, "0")
|
||||
const minute = String(now.getMinutes()).padStart(2, "0")
|
||||
const second = String(now.getSeconds()).padStart(2, "0")
|
||||
const testTime = `${month}/${day} ${hour}:${minute}:${second}`
|
||||
// 使用最后一次测试的时间戳作为平均值记录的时间戳(更准确)
|
||||
// 如果最后一次测试时间戳存在,使用它;否则使用当前时间
|
||||
let testTime: string
|
||||
let testDate: string
|
||||
if (lastTestTimestampRef.current) {
|
||||
testTime = lastTestTimestampRef.current
|
||||
// 将时间戳转换为ISO格式(用于排序)
|
||||
const now = new Date()
|
||||
const [monthDay, time] = testTime.split(" ")
|
||||
const [month, day] = monthDay.split("/")
|
||||
const [hour, minute, second] = time.split(":")
|
||||
const testDateTime = new Date(
|
||||
now.getFullYear(),
|
||||
parseInt(month) - 1,
|
||||
parseInt(day),
|
||||
parseInt(hour),
|
||||
parseInt(minute),
|
||||
parseInt(second)
|
||||
)
|
||||
testDate = testDateTime.toISOString()
|
||||
} else {
|
||||
const now = new Date()
|
||||
testDate = now.toISOString()
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0")
|
||||
const day = String(now.getDate()).padStart(2, "0")
|
||||
const hour = String(now.getHours()).padStart(2, "0")
|
||||
const minute = String(now.getMinutes()).padStart(2, "0")
|
||||
const second = String(now.getSeconds()).padStart(2, "0")
|
||||
testTime = `${month}/${day} ${hour}:${minute}:${second}`
|
||||
}
|
||||
|
||||
// 修改备注格式:[分辨率] [批量N次平均]
|
||||
let averageNote = `[${currentResolution.label}]`
|
||||
if (testNote) {
|
||||
averageNote = `${testNote} ${averageNote}`
|
||||
}
|
||||
averageNote = `${averageNote} [批量${totalTests}次平均]`
|
||||
|
||||
// 生成唯一ID
|
||||
const idTime = lastTestTimestampRef.current
|
||||
? new Date(testDate).getTime()
|
||||
: Date.now()
|
||||
fpsTest.addResult({
|
||||
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
|
||||
id: `${idTime}-${Math.random().toString(36).slice(2, 11)}`,
|
||||
testTime,
|
||||
testDate,
|
||||
mapName: mapConfig?.name || "unknown",
|
||||
@@ -1016,21 +1083,46 @@ export function FpsTest() {
|
||||
validResults.reduce((sum, r) => sum + (r.avg || 0), 0) / validResults.length
|
||||
const avgP1 = validResults.reduce((sum, r) => sum + (r.p1 || 0), 0) / validResults.length
|
||||
|
||||
const now = new Date()
|
||||
const testDate = now.toISOString()
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0")
|
||||
const day = String(now.getDate()).padStart(2, "0")
|
||||
const hour = String(now.getHours()).padStart(2, "0")
|
||||
const minute = String(now.getMinutes()).padStart(2, "0")
|
||||
const second = String(now.getSeconds()).padStart(2, "0")
|
||||
const testTime = `${month}/${day} ${hour}:${minute}:${second}`
|
||||
// 使用最后一次测试的时间戳作为平均值记录的时间戳(更准确)
|
||||
let testTime: string
|
||||
let testDate: string
|
||||
if (lastTestTimestampRef.current) {
|
||||
testTime = lastTestTimestampRef.current
|
||||
// 将时间戳转换为ISO格式(用于排序)
|
||||
const now = new Date()
|
||||
const [monthDay, time] = testTime.split(" ")
|
||||
const [month, day] = monthDay.split("/")
|
||||
const [hour, minute, second] = time.split(":")
|
||||
const testDateTime = new Date(
|
||||
now.getFullYear(),
|
||||
parseInt(month) - 1,
|
||||
parseInt(day),
|
||||
parseInt(hour),
|
||||
parseInt(minute),
|
||||
parseInt(second)
|
||||
)
|
||||
testDate = testDateTime.toISOString()
|
||||
} else {
|
||||
const now = new Date()
|
||||
testDate = now.toISOString()
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0")
|
||||
const day = String(now.getDate()).padStart(2, "0")
|
||||
const hour = String(now.getHours()).padStart(2, "0")
|
||||
const minute = String(now.getMinutes()).padStart(2, "0")
|
||||
const second = String(now.getSeconds()).padStart(2, "0")
|
||||
testTime = `${month}/${day} ${hour}:${minute}:${second}`
|
||||
}
|
||||
|
||||
const averageNote = testNote
|
||||
? `${testNote} [批量${totalTests}次平均]`
|
||||
: `[批量${totalTests}次平均]`
|
||||
|
||||
// 生成唯一ID
|
||||
const idTime = lastTestTimestampRef.current
|
||||
? new Date(testDate).getTime()
|
||||
: Date.now()
|
||||
fpsTest.addResult({
|
||||
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
|
||||
id: `${idTime}-${Math.random().toString(36).slice(2, 11)}`,
|
||||
testTime,
|
||||
testDate,
|
||||
mapName: mapConfig?.name || "unknown",
|
||||
@@ -1183,6 +1275,84 @@ export function FpsTest() {
|
||||
}
|
||||
}
|
||||
|
||||
// 仅导出平均结果CSV
|
||||
const handleExportAverageCSV = async () => {
|
||||
// 过滤备注中包含"平均"的结果
|
||||
const averageResults = fpsTest.state.results.filter(
|
||||
(result) => result.note && result.note.includes("平均")
|
||||
)
|
||||
|
||||
if (averageResults.length === 0) {
|
||||
addToast({ title: "没有平均结果数据可导出", color: "warning" })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建CSV内容
|
||||
const headers = [
|
||||
"测试时间",
|
||||
"测试地图",
|
||||
"平均帧",
|
||||
"P1低帧",
|
||||
"CPU",
|
||||
"系统版本",
|
||||
"GPU",
|
||||
"内存(GB)",
|
||||
"分辨率",
|
||||
"视频设置",
|
||||
"备注",
|
||||
]
|
||||
|
||||
const csvRows = [headers.join(",")]
|
||||
|
||||
for (const result of averageResults) {
|
||||
const row = [
|
||||
`"${result.testTime}"`,
|
||||
`"${result.mapLabel}"`,
|
||||
result.avg !== null ? result.avg.toFixed(1) : "N/A",
|
||||
result.p1 !== null ? result.p1.toFixed(1) : "N/A",
|
||||
`"${result.hardwareInfo?.cpu || "N/A"}"`,
|
||||
`"${result.hardwareInfo?.os || "N/A"}"`,
|
||||
`"${result.hardwareInfo?.gpu || "N/A"}"`,
|
||||
result.hardwareInfo?.memory ? result.hardwareInfo.memory.toString() : "N/A",
|
||||
result.videoSetting
|
||||
? `${result.videoSetting.defaultres}x${result.videoSetting.defaultresheight}`
|
||||
: "N/A",
|
||||
`"${formatVideoSettingSummary(result.videoSetting)}"`,
|
||||
`"${result.note || ""}"`,
|
||||
]
|
||||
csvRows.push(row.join(","))
|
||||
}
|
||||
|
||||
const csvContent = csvRows.join("\n")
|
||||
|
||||
// 添加UTF-8 BOM以确保Excel等软件正确识别编码
|
||||
const csvContentWithBOM = "\uFEFF" + csvContent
|
||||
|
||||
// 使用文件保存对话框
|
||||
const filePath = await save({
|
||||
filters: [
|
||||
{
|
||||
name: "CSV",
|
||||
extensions: ["csv"],
|
||||
},
|
||||
],
|
||||
defaultPath: `fps_test_average_results_${new Date().toISOString().split("T")[0]}.csv`,
|
||||
})
|
||||
|
||||
if (filePath) {
|
||||
await writeTextFile(filePath, csvContentWithBOM)
|
||||
addToast({ title: "导出成功", color: "success" })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("导出CSV失败:", error)
|
||||
addToast({
|
||||
title: `导出失败: ${error instanceof Error ? error.message : String(error)}`,
|
||||
color: "danger",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 应用预设分辨率
|
||||
const handlePresetResolution = (preset: { width: string; height: string; label: string }) => {
|
||||
fpsTest.setResolution(preset.width, preset.height)
|
||||
@@ -1228,10 +1398,16 @@ export function FpsTest() {
|
||||
</div>
|
||||
)}
|
||||
{showResultsTable && (
|
||||
<Button size="sm" variant="flat" onPress={handleExportCSV} className="font-medium">
|
||||
<DownloadOne size={14} />
|
||||
导出CSV
|
||||
</Button>
|
||||
<>
|
||||
<Button size="sm" variant="flat" onPress={handleExportAverageCSV} className="font-medium">
|
||||
<DownloadOne size={14} />
|
||||
仅导出平均结果
|
||||
</Button>
|
||||
<Button size="sm" variant="flat" onPress={handleExportCSV} className="font-medium">
|
||||
<DownloadOne size={14} />
|
||||
导出CSV
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
@@ -1291,7 +1467,7 @@ export function FpsTest() {
|
||||
<TableColumn width={80}>测试地图</TableColumn>
|
||||
<TableColumn width={80}>平均帧</TableColumn>
|
||||
<TableColumn width={80}>P1低帧</TableColumn>
|
||||
<TableColumn width={150}>CPU</TableColumn>
|
||||
<TableColumn width={100}>CPU</TableColumn>
|
||||
<TableColumn minWidth={80}>系统版本</TableColumn>
|
||||
<TableColumn minWidth={100}>GPU</TableColumn>
|
||||
<TableColumn width={80}>内存</TableColumn>
|
||||
@@ -1314,10 +1490,16 @@ export function FpsTest() {
|
||||
<TableCell className="text-xs">
|
||||
{result.p1 !== null ? `${result.p1.toFixed(1)}` : "N/A"}
|
||||
</TableCell>
|
||||
<TableCell className="text-xs max-w-[150px]">
|
||||
<div className="truncate">
|
||||
{result.hardwareInfo?.cpu || "N/A"}
|
||||
</div>
|
||||
<TableCell className="text-xs max-w-[175px]">
|
||||
<Tooltip
|
||||
content={result.hardwareInfo?.cpu || "N/A"}
|
||||
delay={500}
|
||||
placement="top"
|
||||
>
|
||||
<div className="truncate cursor-help">
|
||||
{result.hardwareInfo?.cpu || "N/A"}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell className="text-xs">
|
||||
<div className="truncate">
|
||||
@@ -1474,9 +1656,9 @@ export function FpsTest() {
|
||||
}
|
||||
}}
|
||||
isDisabled={isMonitoring}
|
||||
className="h-5 min-w-[40px] px-1.5 text-xs font-medium"
|
||||
className="h-5 gap-1 flex px-1.5 min-w-fit text-xs font-medium"
|
||||
>
|
||||
<List size={14} />
|
||||
<List size={12} />
|
||||
多组
|
||||
</Button>
|
||||
{!isResolutionGroupEnabled && (
|
||||
|
||||
Reference in New Issue
Block a user