Files
better-genshin-impact/BetterGenshinImpact/GameTask/LogParse/Assets/log.js

373 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('th').forEach(function(th) {
th.removeAttribute('onclick');
th.addEventListener('click', function() {
const table = this.closest('table');
const columnIndex = Array.from(this.parentNode.children).indexOf(this);
const sortType = this.getAttribute('data-sort-type') || 'string';
sortTable(table, columnIndex, sortType);
});
});
});
function getCellValue(row, columnIndex, sortType) {
try {
if (!row || !row.cells || columnIndex >= row.cells.length) {
return sortType === 'number' || sortType === 'date' ? 0 : '';
}
const cell = row.cells[columnIndex];
if (!cell) return sortType === 'number' || sortType === 'date' ? 0 : '';
// 优先使用data-sort属性值
const sortValue = cell.getAttribute('data-sort');
if (sortValue !== null) {
return sortType === 'number' || sortType === 'date' ? parseFloat(sortValue) : sortValue;
}
const value = cell.textContent ? cell.textContent.trim() : '';
// 根据排序类型转换值
if (sortType === 'number') {
// 提取数字部分
const numMatch = value.match(/[\d\.]+/);
return numMatch ? parseFloat(numMatch[0]) : 0;
} else if (sortType === 'date') {
// 修改日期解析逻辑,优先处理 yyyy-MM-dd 格式
if (!value) return 0;
// 尝试解析 yyyy-MM-dd 格式
const dateOnlyMatch = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (dateOnlyMatch) {
const year = parseInt(dateOnlyMatch[1]);
const month = parseInt(dateOnlyMatch[2]) - 1; // 月份从0开始
const day = parseInt(dateOnlyMatch[3]);
return new Date(year, month, day).getTime();
}
// 尝试解析标准日期时间格式 yyyy-MM-dd HH:mm:ss
const dateTimeMatch = value.match(/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/);
if (dateTimeMatch) {
const year = parseInt(dateTimeMatch[1]);
const month = parseInt(dateTimeMatch[2]) - 1; // 月份从0开始
const day = parseInt(dateTimeMatch[3]);
const hour = parseInt(dateTimeMatch[4]);
const minute = parseInt(dateTimeMatch[5]);
const second = parseInt(dateTimeMatch[6]);
return new Date(year, month, day, hour, minute, second).getTime();
}
// 如果无法解析尝试直接使用Date构造函数
return new Date(value).getTime() || 0;
} else if (sortType === 'time') {
// 处理时间格式(小时、分钟、秒)
let seconds = 0;
if (value.includes('小时')) {
const hoursMatch = value.match(/(\d+)小时/);
if (hoursMatch) {
seconds += parseInt(hoursMatch[1]) * 3600;
}
}
if (value.includes('分钟')) {
const minutesMatch = value.match(/(\d+)分钟/);
if (minutesMatch) {
seconds += parseInt(minutesMatch[1]) * 60;
}
}
if (value.includes('秒')) {
const secondsMatch = value.match(/([\d\.]+)秒/);
if (secondsMatch) {
seconds += parseFloat(secondsMatch[1]);
}
}
return seconds;
}
return value;
} catch (e) {
console.error('获取单元格值时出错:', e);
return sortType === 'number' || sortType === 'date' ? 0 : '';
}
}
function sortTable(table, columnIndex, sortType) {
let loadingDiv = null;
let loadingTimer = null;
try {
if (!table) return;
const tbody = table.querySelector('tbody');
if (!tbody) return;
// 创建排序中的提示,但不立即显示
loadingDiv = document.createElement('div');
loadingDiv.style.position = 'fixed';
loadingDiv.style.top = '50%';
loadingDiv.style.left = '50%';
loadingDiv.style.transform = 'translate(-50%, -50%)';
loadingDiv.style.padding = '20px';
loadingDiv.style.background = 'rgba(0,0,0,0.7)';
loadingDiv.style.color = 'white';
loadingDiv.style.borderRadius = '5px';
loadingDiv.style.zIndex = '1000';
loadingDiv.textContent = '排序中,请稍候...';
// 设置延迟显示提示只有排序超过500毫秒才显示
loadingTimer = setTimeout(function() {
document.body.appendChild(loadingDiv);
}, 1000);
// 使用setTimeout让UI有机会更新
setTimeout(function() {
try {
// 保存汇总行
const summaryRows = Array.from(tbody.querySelectorAll('tr.ignore-sort') || []);
// 获取所有行并创建映射
const allRows = Array.from(tbody.querySelectorAll('tr') || []);
if (!allRows.length) {
clearTimeout(loadingTimer);
if (loadingDiv && loadingDiv.parentNode) {
document.body.removeChild(loadingDiv);
}
return;
}
// 首先标记所有行
for (let i = 0; i < allRows.length; i++) {
if (allRows[i]) {
allRows[i].setAttribute('data-original-index', i.toString());
}
}
// 获取需要排序的行(排除汇总行和子行)
const rows = [];
for (let i = 0; i < allRows.length; i++) {
const row = allRows[i];
if (row && row.classList &&
!row.classList.contains('ignore-sort') &&
!row.classList.contains('sub-row')) {
rows.push(row);
}
}
// 创建行和其对应的附属行的映射
const rowPairs = [];
for (let i = 0; i < rows.length; i++) {
try {
const row = rows[i];
if (!row || !row.getAttribute) continue;
const originalIndexStr = row.getAttribute('data-original-index');
if (!originalIndexStr) continue;
const originalIndex = parseInt(originalIndexStr);
if (isNaN(originalIndex)) continue;
// 安全地获取下一行,确保它存在
let nextRow = null;
if (originalIndex + 1 < allRows.length) {
nextRow = allRows[originalIndex + 1];
}
// 安全地检查nextRow是否存在且是否有classList属性
if (nextRow && nextRow.classList &&
typeof nextRow.classList.contains === 'function' &&
nextRow.classList.contains('sub-row')) {
rowPairs.push({main: row, sub: nextRow});
} else {
rowPairs.push({main: row, sub: null});
}
} catch (e) {
console.error('创建行对时出错:', e);
continue;
}
}
// 确定排序方向
let sortDirection = 'asc';
const headerCells = table.querySelectorAll('th');
if (!headerCells || columnIndex >= headerCells.length) {
if (loadingDiv && loadingDiv.parentNode) {
document.body.removeChild(loadingDiv);
}
return;
}
const headerCell = headerCells[columnIndex];
if (!headerCell || !headerCell.classList) {
if (loadingDiv && loadingDiv.parentNode) {
document.body.removeChild(loadingDiv);
}
return;
}
// 如果已经按这列排序,则切换方向
if (headerCell.classList.contains('sort-asc')) {
sortDirection = 'desc';
} else if (headerCell.classList.contains('sort-desc')) {
sortDirection = 'asc';
}
// 清除所有表头的排序指示器
for (let i = 0; i < headerCells.length; i++) {
const th = headerCells[i];
if (th && th.classList) {
th.classList.remove('sort-asc', 'sort-desc');
}
}
// 添加新的排序指示器
headerCell.classList.add('sort-' + sortDirection);
// 特殊处理耗时列
const isTimeColumn = headerCell.textContent && headerCell.textContent.trim() === '任务耗时';
const actualSortType = isTimeColumn ? 'time' : sortType;
// 排序行对 - 使用稳定的排序算法
rowPairs.sort((pairA, pairB) => {
try {
// 确保main对象存在
if (!pairA || !pairA.main || !pairB || !pairB.main) {
return 0;
}
const valueA = getCellValue(pairA.main, columnIndex, actualSortType);
const valueB = getCellValue(pairB.main, columnIndex, actualSortType);
let result;
if (actualSortType === 'number' || actualSortType === 'date' || actualSortType === 'time') {
result = sortDirection === 'asc' ? valueA - valueB : valueB - valueA;
} else {
result = sortDirection === 'asc'
? String(valueA).localeCompare(String(valueB), 'zh-CN')
: String(valueB).localeCompare(String(valueA), 'zh-CN');
}
// 如果值相等,保持原始顺序(稳定排序)
if (result === 0) {
const indexA = parseInt(pairA.main.getAttribute('data-original-index') || '0');
const indexB = parseInt(pairB.main.getAttribute('data-original-index') || '0');
return indexA - indexB;
}
return result;
} catch (e) {
console.error('排序比较时出错:', e);
return 0;
}
});
// 创建文档片段以提高性能
const fragment = document.createDocumentFragment();
// 先添加排序后的数据行和附属行
for (let i = 0; i < rowPairs.length; i++) {
const pair = rowPairs[i];
// 确保main对象存在
if (pair && pair.main) {
fragment.appendChild(pair.main);
// 确保sub对象存在
if (pair.sub) {
fragment.appendChild(pair.sub);
}
}
}
// 最后添加汇总行
for (let i = 0; i < summaryRows.length; i++) {
const row = summaryRows[i];
if (row) {
fragment.appendChild(row);
}
}
// 清空tbody
while (tbody.firstChild) {
tbody.removeChild(tbody.firstChild);
}
// 一次性添加所有行
tbody.appendChild(fragment);
} catch (error) {
console.error('排序过程中发生错误:', error);
alert('排序过程中发生错误: ' + error.message);
} finally {
// 清除定时器并移除加载提示
clearTimeout(loadingTimer);
if (loadingDiv && loadingDiv.parentNode) {
document.body.removeChild(loadingDiv);
}
}
}, 50); // 短暂延迟让UI更新
} catch (error) {
console.error('排序初始化时发生错误:', error);
// 清除定时器并确保加载提示被移除
clearTimeout(loadingTimer);
if (loadingDiv && loadingDiv.parentNode) {
document.body.removeChild(loadingDiv);
}
}
}
function togglePre(preId, btn) {
const pre = document.getElementById(preId);
if (!pre) {
console.error(`未找到 ID 为 "${preId}" 的元素`);
return;
}
if (window.getComputedStyle(pre).display === "none") {
pre.style.display = "block";
btn.textContent = "隐藏 JSON";
} else {
pre.style.display = "none";
btn.textContent = "显示 JSON";
}
}
function copyPreContent(preId) {
const pre = document.getElementById(preId);
if (!pre) {
console.error(`未找到 ID 为 "${preId}" 的元素`);
return;
}
const docComment = `
// 如果所有 JSON 都在同一目录下,可直接拷贝并命名为 control.json5放入该追踪目录。
// 注意:有些因为卡死或其他原因导致失败的记录需自行判断处理。
// 参数说明:
// primary_target: "
// 主目标,值为 elite或normal 时,所配置的类别达到上限时,就会跳过该路径。
// 填写 disable 表示非锄地脚本(如挖矿战斗),也会纳入统计,即使达到上限,但不影响继续执行。
// 如果不填或其他值则两种都达到上限另一种目标数为0也会跳过才会跳过。
// global_cover: 针对该目录所有 JSON。
// json_list.cover: name 与实际文件名匹配的 JSON。
// allow_farming_count: true 开启锄地规划时纳入统计。
// enable_monster_loot_split: true 允许区分怪物拾取支持调度器只拾取精英配置这里把精英为0的直接启用了。
// normal_mob_count: 小怪计数。
// elite_mob_count: 精英计数。
// duration_seconds: 执行秒数。
// elite_details: 精英详细。
// total_mora: 摩拉数。
`;
const text = docComment + pre.textContent;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text)
.then(() => alert("已复制到剪贴板!"))
.catch(err => console.error("复制失败:", err));
} else {
const textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand("copy");
alert("已复制到剪贴板!");
} catch (err) {
console.error("复制失败:", err);
}
document.body.removeChild(textarea);
}
}