fix :UI repeat history sms

This commit is contained in:
yyh 2025-03-23 20:59:02 +08:00
parent 84881871a8
commit b18ddc8f5a

View File

@ -18,48 +18,31 @@ document.addEventListener("DOMContentLoaded", function() {
const pagination = document.getElementById('pagination'); const pagination = document.getElementById('pagination');
const refreshButton = document.querySelector('.refresh-records'); const refreshButton = document.querySelector('.refresh-records');
// 初始化页面 // 绑定事件监听器
initializePage(); if (codeQueryForm) {
codeQueryForm.addEventListener('submit', function(e) {
/** e.preventDefault();
* 初始化页面 queryVerificationCode();
*/
function initializePage() {
// 加载短信记录
loadSMSRecords(currentPage);
// 绑定事件监听器
bindEventListeners();
// 初始化工具提示
initializeTooltips();
}
/**
* 绑定事件监听器
*/
function bindEventListeners() {
// 验证码查询表单提交
if (codeQueryForm) {
codeQueryForm.addEventListener('submit', function(e) {
e.preventDefault();
queryVerificationCode();
});
}
// 刷新按钮点击
if (refreshButton) {
refreshButton.addEventListener('click', function() {
loadSMSRecords(currentPage);
});
}
// 监听窗口大小变化,调整表格显示
window.addEventListener('resize', function() {
adjustTableColumns();
}); });
} }
if (refreshButton) {
refreshButton.addEventListener('click', function() {
loadSMSRecords(currentPage);
});
}
// 初始化工具提示
initializeTooltips();
// 加载短信记录
loadSMSRecords(currentPage);
// 监听窗口大小变化,调整表格显示
window.addEventListener('resize', function() {
adjustTableColumns();
});
/** /**
* 初始化工具提示 * 初始化工具提示
*/ */
@ -76,9 +59,10 @@ document.addEventListener("DOMContentLoaded", function() {
/** /**
* 加载短信记录 * 加载短信记录
* @param {number} page - 页码 * @param {number} page - 页码
* @param {number} limit - 每页记录数
*/ */
function loadSMSRecords(page) { function loadSMSRecords(page = 1, limit = PAGE_SIZE) {
const offset = (page - 1) * PAGE_SIZE; const offset = (page - 1) * limit;
// 显示加载指示器 // 显示加载指示器
if (loadingIndicator) { if (loadingIndicator) {
@ -99,42 +83,62 @@ document.addEventListener("DOMContentLoaded", function() {
} }
// 获取短信记录 // 获取短信记录
fetch(`/v1/sms/history?limit=${PAGE_SIZE}&offset=${offset}`) fetch(`/v1/sms/history?limit=${limit}&offset=${offset}`)
.then(response => { .then(response => {
if (!response.ok) { if (!response.ok) {
throw new Error('网络响应异常'); throw new Error('网络响应异常');
} }
return response.json(); return response.json();
}) })
.then(data => { .then(records => {
if (Array.isArray(data)) { // 隐藏加载指示器
if (loadingIndicator) {
loadingIndicator.classList.add('d-none');
}
if (records.length === 0) {
// 显示无记录提示
if (noRecords) {
noRecords.classList.remove('d-none');
}
if (pagination) {
pagination.innerHTML = '';
}
} else {
// 更新记录总数 // 更新记录总数
totalRecords = data.length === PAGE_SIZE ? -1 : offset + data.length; totalRecords = records.length === limit ? -1 : offset + records.length;
// 渲染记录 // 渲染记录
renderSMSRecords(data); renderRecords(records);
// 更新分页 // 生成分页
updatePagination(data.length === PAGE_SIZE); generatePagination(page, limit, records.length === limit);
// 调整表格列 // 调整表格列
adjustTableColumns(); adjustTableColumns();
// 显示无记录提示
if (data.length === 0 && noRecords) {
noRecords.classList.remove('d-none');
}
} }
}) })
.catch(error => { .catch(error => {
console.error('获取短信记录失败:', error); console.error('获取短信记录失败:', error);
showToast('error', '获取短信记录失败', error.message); showToast('error', '获取短信记录失败', error.message);
})
.finally(() => {
// 隐藏加载指示器 // 隐藏加载指示器
if (loadingIndicator) { if (loadingIndicator) {
loadingIndicator.classList.add('d-none'); loadingIndicator.classList.add('d-none');
} }
if (smsRecordsTable) {
const tableBody = smsRecordsTable.querySelector('tbody');
if (tableBody) {
tableBody.innerHTML = `
<tr>
<td colspan="6" class="text-center text-danger">
<i class="fas fa-exclamation-circle me-2"></i>: ${error.message}
</td>
</tr>
`;
}
}
}); });
} }
@ -142,22 +146,25 @@ document.addEventListener("DOMContentLoaded", function() {
* 渲染短信记录到表格 * 渲染短信记录到表格
* @param {Array} records - 短信记录数组 * @param {Array} records - 短信记录数组
*/ */
function renderSMSRecords(records) { function renderRecords(records) {
if (!smsRecordsTable) return;
const tableBody = smsRecordsTable.querySelector('tbody'); const tableBody = smsRecordsTable.querySelector('tbody');
if (!tableBody) return; if (!tableBody) return;
tableBody.innerHTML = ''; tableBody.innerHTML = '';
if (records.length === 0) {
return;
}
records.forEach(record => { records.forEach(record => {
const row = document.createElement('tr'); const row = document.createElement('tr');
row.classList.add('fade-in'); row.classList.add('fade-in');
// 格式化日期时间
const date = new Date(record.receive_time);
const formattedDate = formatDateTime(date);
// 应用敏感信息掩码
const maskedSMS = maskSensitiveInfo(record.sms);
const maskedFrom = maskSensitiveInfo(record.from_ || record.from);
const maskedSimSlot = record.sim_slot ? maskSensitiveInfo(record.sim_slot) : '';
// 为验证码创建适当的徽章 // 为验证码创建适当的徽章
const codeElement = record.extracted_code const codeElement = record.extracted_code
? `<span class="badge bg-success">${record.extracted_code}</span>` ? `<span class="badge bg-success">${record.extracted_code}</span>`
@ -165,10 +172,10 @@ document.addEventListener("DOMContentLoaded", function() {
row.innerHTML = ` row.innerHTML = `
<td>${record.id}</td> <td>${record.id}</td>
<td>${escapeHtml(record.from_ || record.from)}</td> <td title="${maskedFrom}${maskedSimSlot ? '\n' + maskedSimSlot : ''}">${maskedFrom}</td>
<td class="sms-content" title="${escapeHtml(record.sms)}">${escapeHtml(record.sms)}</td> <td class="sms-content" title="${maskedSMS}">${maskedSMS}</td>
<td>${codeElement}</td> <td>${codeElement}</td>
<td>${formatDateTime(record.receive_time)}</td> <td>${formattedDate}</td>
<td class="text-center"> <td class="text-center">
<button class="btn btn-sm btn-outline-primary view-sms" data-id="${record.id}" <button class="btn btn-sm btn-outline-primary view-sms" data-id="${record.id}"
data-bs-toggle="tooltip" title="查看详情"> data-bs-toggle="tooltip" title="查看详情">
@ -193,90 +200,45 @@ document.addEventListener("DOMContentLoaded", function() {
} }
/** /**
* 更新分页控件 * 生成分页控件
* @param {number} currentPage - 当前页码
* @param {number} limit - 每页记录数
* @param {boolean} hasMore - 是否有更多记录 * @param {boolean} hasMore - 是否有更多记录
*/ */
function updatePagination(hasMore) { function generatePagination(currentPage, limit, hasMore) {
if (!pagination) return; if (!pagination) return;
pagination.innerHTML = ''; pagination.innerHTML = '';
// 上一页按钮 // 上一页按钮
pagination.appendChild(createPageItem('上一页', currentPage - 1, currentPage === 1, 'fas fa-chevron-left')); const prevItem = document.createElement('li');
prevItem.className = `page-item ${currentPage === 1 ? 'disabled' : ''}`;
// 数字页码 prevItem.innerHTML = `<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a>`;
const totalPages = totalRecords > 0 ? Math.ceil(totalRecords / PAGE_SIZE) : currentPage + (hasMore ? 1 : 0); if (currentPage > 1) {
let startPage = Math.max(1, currentPage - 2); prevItem.querySelector('a').addEventListener('click', (e) => {
const endPage = Math.min(totalPages, startPage + 4);
// 首页按钮
if (startPage > 1) {
pagination.appendChild(createPageItem('1', 1, false));
if (startPage > 2) {
const ellipsis = document.createElement('li');
ellipsis.className = 'page-item disabled';
ellipsis.innerHTML = '<span class="page-link">...</span>';
pagination.appendChild(ellipsis);
}
}
// 页码按钮
for (let i = startPage; i <= endPage; i++) {
pagination.appendChild(createPageItem(i.toString(), i, i === currentPage));
}
// 最后一页按钮
if (endPage < totalPages) {
if (endPage < totalPages - 1) {
const ellipsis = document.createElement('li');
ellipsis.className = 'page-item disabled';
ellipsis.innerHTML = '<span class="page-link">...</span>';
pagination.appendChild(ellipsis);
}
pagination.appendChild(createPageItem(totalPages.toString(), totalPages, false));
}
// 下一页按钮
pagination.appendChild(createPageItem('下一页', currentPage + 1, !hasMore && totalRecords > 0 && currentPage >= totalPages, 'fas fa-chevron-right'));
}
/**
* 创建分页项
* @param {string} text - 显示文本
* @param {number} page - 页码
* @param {boolean} isActive - 是否是当前页
* @param {string} icon - 图标类名可选
* @returns {HTMLElement} 分页项元素
*/
function createPageItem(text, page, isDisabled, icon) {
const pageItem = document.createElement('li');
pageItem.className = `page-item ${isDisabled ? 'disabled' : ''} ${page === currentPage ? 'active' : ''}`;
const link = document.createElement('a');
link.className = 'page-link';
link.href = '#';
link.setAttribute('data-page', page);
if (icon) {
link.innerHTML = `<i class="${icon}"></i>`;
link.setAttribute('aria-label', text);
} else {
link.textContent = text;
}
pageItem.appendChild(link);
if (!isDisabled) {
link.addEventListener('click', function(e) {
e.preventDefault(); e.preventDefault();
if (page !== currentPage) { loadSMSRecords(currentPage - 1, limit);
currentPage = page;
loadSMSRecords(currentPage);
}
}); });
} }
pagination.appendChild(prevItem);
return pageItem; // 当前页
const currentItem = document.createElement('li');
currentItem.className = 'page-item active';
currentItem.innerHTML = `<a class="page-link" href="#">${currentPage}</a>`;
pagination.appendChild(currentItem);
// 下一页按钮
const nextItem = document.createElement('li');
nextItem.className = `page-item ${!hasMore ? 'disabled' : ''}`;
nextItem.innerHTML = `<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a>`;
if (hasMore) {
nextItem.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
loadSMSRecords(currentPage + 1, limit);
});
}
pagination.appendChild(nextItem);
} }
/** /**
@ -325,6 +287,7 @@ document.addEventListener("DOMContentLoaded", function() {
// 显示查询结果 // 显示查询结果
if (resultContent) { if (resultContent) {
if (data.result === 'ok') { if (data.result === 'ok') {
const maskedSmsExcerpt = maskSensitiveInfo(data.data.sms_excerpt);
resultContent.innerHTML = ` resultContent.innerHTML = `
<div class="alert alert-success mb-0"> <div class="alert alert-success mb-0">
<div class="d-flex align-items-center mb-2"> <div class="d-flex align-items-center mb-2">
@ -339,12 +302,12 @@ document.addEventListener("DOMContentLoaded", function() {
</div> </div>
<div class="col-md-6 mb-2"> <div class="col-md-6 mb-2">
<strong><i class="fas fa-clock me-1"></i> :</strong> <strong><i class="fas fa-clock me-1"></i> :</strong>
<div class="mt-1">${formatDateTime(data.data.received_time)}</div> <div class="mt-1">${formatDateTime(new Date(data.data.received_time))}</div>
</div> </div>
</div> </div>
<div class="mb-2"> <div class="mb-2">
<strong><i class="fas fa-envelope me-1"></i> :</strong> <strong><i class="fas fa-envelope me-1"></i> :</strong>
<div class="sms-excerpt mt-1 p-2 bg-light rounded">${escapeHtml(data.data.sms_excerpt)}...</div> <div class="sms-excerpt mt-1 p-2 bg-light rounded">${maskedSmsExcerpt}...</div>
</div> </div>
<div class="text-end mt-3"> <div class="text-end mt-3">
<button class="btn btn-sm btn-outline-success copy-code" data-code="${data.data.code}"> <button class="btn btn-sm btn-outline-success copy-code" data-code="${data.data.code}">
@ -418,6 +381,12 @@ document.addEventListener("DOMContentLoaded", function() {
// 关闭加载中模态框 // 关闭加载中模态框
closeModal('loadingModal'); closeModal('loadingModal');
// 应用敏感信息掩码
const maskedSMS = maskSensitiveInfo(data.sms);
const maskedFrom = maskSensitiveInfo(data.from_ || data.from);
const maskedSimSlot = data.sim_slot ? maskSensitiveInfo(data.sim_slot) : '未知';
const maskedPhoneNumber = data.phone_number ? maskSensitiveInfo(data.phone_number) : '未提取';
// 创建详情模态框 // 创建详情模态框
const modalHtml = ` const modalHtml = `
<div class="modal fade" id="smsDetailModal" tabindex="-1" aria-hidden="true"> <div class="modal fade" id="smsDetailModal" tabindex="-1" aria-hidden="true">
@ -437,7 +406,7 @@ document.addEventListener("DOMContentLoaded", function() {
<label class="detail-label"> <label class="detail-label">
<i class="fas fa-user me-1"></i> <i class="fas fa-user me-1"></i>
</label> </label>
<div class="detail-value">${escapeHtml(data.from_ || data.from)}</div> <div class="detail-value">${maskedFrom}</div>
</div> </div>
</div> </div>
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
@ -457,7 +426,7 @@ document.addEventListener("DOMContentLoaded", function() {
</label> </label>
<div class="detail-value"> <div class="detail-value">
<div class="sms-content-box p-3 bg-light rounded"> <div class="sms-content-box p-3 bg-light rounded">
${escapeHtml(data.sms).replace(/\n/g, '<br>')} ${maskedSMS.replace(/\n/g, '<br>')}
</div> </div>
</div> </div>
</div> </div>
@ -481,7 +450,7 @@ document.addEventListener("DOMContentLoaded", function() {
<label class="detail-label"> <label class="detail-label">
<i class="fas fa-mobile-alt me-1"></i> <i class="fas fa-mobile-alt me-1"></i>
</label> </label>
<div class="detail-value">${data.phone_number || '未提取'}</div> <div class="detail-value">${maskedPhoneNumber}</div>
</div> </div>
</div> </div>
</div> </div>
@ -492,7 +461,7 @@ document.addEventListener("DOMContentLoaded", function() {
<label class="detail-label"> <label class="detail-label">
<i class="fas fa-sim-card me-1"></i> SIM <i class="fas fa-sim-card me-1"></i> SIM
</label> </label>
<div class="detail-value text-break">${escapeHtml(data.sim_slot || '未知')}</div> <div class="detail-value text-break">${maskedSimSlot}</div>
</div> </div>
</div> </div>
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
@ -500,7 +469,7 @@ document.addEventListener("DOMContentLoaded", function() {
<label class="detail-label"> <label class="detail-label">
<i class="fas fa-clock me-1"></i> <i class="fas fa-clock me-1"></i>
</label> </label>
<div class="detail-value">${formatDateTime(data.receive_time)}</div> <div class="detail-value">${formatDateTime(new Date(data.receive_time))}</div>
</div> </div>
</div> </div>
</div> </div>
@ -689,14 +658,11 @@ document.addEventListener("DOMContentLoaded", function() {
/** /**
* 格式化日期时间 * 格式化日期时间
* @param {string} dateTimeStr - ISO格式的日期时间字符串 * @param {Date} date - 日期对象
* @returns {string} 格式化后的日期时间字符串 * @returns {string} 格式化后的日期时间字符串
*/ */
function formatDateTime(dateTimeStr) { function formatDateTime(date) {
if (!dateTimeStr) return '未知时间'; if (!date || isNaN(date.getTime())) return '未知时间';
const date = new Date(dateTimeStr);
if (isNaN(date.getTime())) return dateTimeStr;
return date.toLocaleString('zh-CN', { return date.toLocaleString('zh-CN', {
year: 'numeric', year: 'numeric',
@ -731,7 +697,6 @@ document.addEventListener("DOMContentLoaded", function() {
if (!smsRecordsTable) return; if (!smsRecordsTable) return;
const tableHeaders = smsRecordsTable.querySelectorAll('th'); const tableHeaders = smsRecordsTable.querySelectorAll('th');
const tableRows = smsRecordsTable.querySelectorAll('tbody tr');
// 如果窗口宽度小于768px隐藏某些列 // 如果窗口宽度小于768px隐藏某些列
if (window.innerWidth < 768) { if (window.innerWidth < 768) {
@ -791,282 +756,3 @@ function maskSensitiveInfo(text) {
return maskedText; return maskedText;
} }
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
// 查询验证码表单处理
const codeQueryForm = document.getElementById('codeQueryForm');
const queryResult = document.getElementById('queryResult');
const resultContent = document.getElementById('resultContent');
if (codeQueryForm) {
codeQueryForm.addEventListener('submit', async function(e) {
e.preventDefault();
const phoneNumber = document.getElementById('phoneNumber').value;
const platformKeyword = document.getElementById('platformKeyword').value;
const timeout = document.getElementById('timeout').value;
// 显示加载状态
resultContent.innerHTML = `
<div class="text-center my-3">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">正在查询验证码请稍候...</p>
</div>
`;
queryResult.classList.remove('d-none');
try {
// 调用API查询验证码
const response = await fetch(`/v1/sms/code?phone_number=${encodeURIComponent(phoneNumber)}&platform_keyword=${encodeURIComponent(platformKeyword || '')}&wait_timeout=${timeout}`);
const data = await response.json();
// 显示结果
if (data.result === 'ok') {
resultContent.innerHTML = `
<div class="alert alert-success mb-0">
<h5 class="alert-heading"><i class="fas fa-check-circle me-2"></i></h5>
<hr>
<p class="mb-1"><strong>验证码:</strong> <span class="fs-5 fw-bold">${data.data.code}</span></p>
<p class="mb-1"><strong>接收时间:</strong> ${new Date(data.data.received_time).toLocaleString()}</p>
<p class="mb-0"><strong>短信内容:</strong> ${maskSensitiveInfo(data.data.sms_excerpt)}...</p>
</div>
`;
} else {
resultContent.innerHTML = `
<div class="alert alert-warning mb-0">
<h5 class="alert-heading"><i class="fas fa-exclamation-triangle me-2"></i></h5>
<hr>
<p class="mb-0">${data.message}</p>
</div>
`;
}
} catch (error) {
resultContent.innerHTML = `
<div class="alert alert-danger mb-0">
<h5 class="alert-heading"><i class="fas fa-times-circle me-2"></i></h5>
<hr>
<p class="mb-0">请求失败: ${error.message}</p>
</div>
`;
}
});
}
// 加载短信历史记录
loadSMSRecords();
// 监听刷新按钮
const refreshButton = document.querySelector('.refresh-records');
if (refreshButton) {
refreshButton.addEventListener('click', () => loadSMSRecords());
}
});
// 加载短信历史记录
async function loadSMSRecords(page = 1, limit = 10) {
const tableBody = document.querySelector('#smsRecordsTable tbody');
const loadingIndicator = document.getElementById('loadingIndicator');
const noRecords = document.getElementById('noRecords');
const pagination = document.getElementById('pagination');
if (!tableBody) return;
// 显示加载指示器
tableBody.innerHTML = '';
loadingIndicator.classList.remove('d-none');
noRecords.classList.add('d-none');
try {
// 计算偏移量
const offset = (page - 1) * limit;
// 获取短信历史记录
const response = await fetch(`/v1/sms/history?limit=${limit}&offset=${offset}`);
const records = await response.json();
// 隐藏加载指示器
loadingIndicator.classList.add('d-none');
if (records.length === 0) {
// 显示无记录提示
noRecords.classList.remove('d-none');
pagination.innerHTML = '';
} else {
// 渲染记录
records.forEach(record => {
const row = document.createElement('tr');
// 格式化日期时间
const date = new Date(record.receive_time);
const formattedDate = date.toLocaleString();
// 应用敏感信息掩码
const maskedSMS = maskSensitiveInfo(record.sms);
const maskedFrom = maskSensitiveInfo(record.from_);
const maskedSimSlot = record.sim_slot ? maskSensitiveInfo(record.sim_slot) : '';
row.innerHTML = `
<td>${record.id}</td>
<td title="${maskedFrom}${maskedSimSlot ? '\n' + maskedSimSlot : ''}">${maskedFrom}</td>
<td>
<div class="sms-content" title="${maskedSMS}">${maskedSMS}</div>
</td>
<td>
<span class="badge ${record.extracted_code ? 'bg-success' : 'bg-secondary'}">
${record.extracted_code || '无'}
</span>
</td>
<td>${formattedDate}</td>
<td class="text-center">
<button class="btn btn-sm btn-info view-details" data-id="${record.id}" title="查看详情">
<i class="fas fa-eye"></i>
</button>
</td>
`;
tableBody.appendChild(row);
});
// 添加事件监听器到查看详情按钮
document.querySelectorAll('.view-details').forEach(button => {
button.addEventListener('click', async () => {
const id = button.getAttribute('data-id');
await showRecordDetails(id);
});
});
// 创建简单分页
generatePagination(page, limit, records.length === limit);
}
} catch (error) {
console.error('加载短信记录失败:', error);
loadingIndicator.classList.add('d-none');
tableBody.innerHTML = `
<tr>
<td colspan="6" class="text-center text-danger">
<i class="fas fa-exclamation-circle me-2"></i>: ${error.message}
</td>
</tr>
`;
}
}
// 生成分页控件
function generatePagination(currentPage, limit, hasMore) {
const pagination = document.getElementById('pagination');
if (!pagination) return;
pagination.innerHTML = '';
// 上一页按钮
const prevItem = document.createElement('li');
prevItem.className = `page-item ${currentPage === 1 ? 'disabled' : ''}`;
prevItem.innerHTML = `<a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a>`;
if (currentPage > 1) {
prevItem.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
loadSMSRecords(currentPage - 1, limit);
});
}
pagination.appendChild(prevItem);
// 当前页
const currentItem = document.createElement('li');
currentItem.className = 'page-item active';
currentItem.innerHTML = `<a class="page-link" href="#">${currentPage}</a>`;
pagination.appendChild(currentItem);
// 下一页按钮
const nextItem = document.createElement('li');
nextItem.className = `page-item ${!hasMore ? 'disabled' : ''}`;
nextItem.innerHTML = `<a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a>`;
if (hasMore) {
nextItem.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
loadSMSRecords(currentPage + 1, limit);
});
}
pagination.appendChild(nextItem);
}
// 显示记录详情
async function showRecordDetails(id) {
try {
const response = await fetch(`/v1/sms/${id}`);
const record = await response.json();
// 应用敏感信息掩码
const maskedSMS = maskSensitiveInfo(record.sms);
const maskedFrom = maskSensitiveInfo(record.from_);
const maskedSimSlot = record.sim_slot ? maskSensitiveInfo(record.sim_slot) : '未知';
const maskedPhoneNumber = record.phone_number ? maskSensitiveInfo(record.phone_number) : '未提取';
// 创建模态框
const modalId = 'recordDetailModal';
let modal = document.getElementById(modalId);
// 如果模态框不存在,创建一个
if (!modal) {
modal = document.createElement('div');
modal.id = modalId;
modal.className = 'modal fade';
modal.tabIndex = -1;
modal.setAttribute('aria-hidden', 'true');
document.body.appendChild(modal);
}
// 格式化日期时间
const formattedDate = new Date(record.receive_time).toLocaleString();
// 设置模态框内容
modal.innerHTML = `
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-gradient-primary">
<h5 class="modal-title">短信详情 #${record.id}</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label fw-bold">发送方</label>
<div>${maskedFrom}</div>
</div>
<div class="mb-3">
<label class="form-label fw-bold">SIM卡信息</label>
<div>${maskedSimSlot}</div>
</div>
<div class="mb-3">
<label class="form-label fw-bold">提取的手机号</label>
<div>${maskedPhoneNumber}</div>
</div>
<div class="mb-3">
<label class="form-label fw-bold">短信内容</label>
<div class="p-2 bg-light rounded">${maskedSMS.replace(/\n/g, '<br>')}</div>
</div>
<div class="mb-3">
<label class="form-label fw-bold">验证码</label>
<div class="fs-5 fw-bold">${record.extracted_code || '未提取'}</div>
</div>
<div class="mb-0">
<label class="form-label fw-bold">接收时间</label>
<div>${formattedDate}</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</div>
</div>
`;
// 显示模态框
const modalInstance = new bootstrap.Modal(modal);
modalInstance.show();
} catch (error) {
console.error('获取记录详情失败:', error);
alert('获取详情失败: ' + error.message);
}
}