feat: 自动提交 - 周一 2025/09/22 16:50:40.70
This commit is contained in:
@@ -149,6 +149,13 @@ class TSPDashboard {
|
||||
this.cache = new Map();
|
||||
this.cacheTimeout = 30000; // 30秒缓存
|
||||
|
||||
// 分页配置
|
||||
this.paginationConfig = {
|
||||
defaultPageSize: 10,
|
||||
pageSizeOptions: [5, 10, 20, 50],
|
||||
maxVisiblePages: 5
|
||||
};
|
||||
|
||||
this.init();
|
||||
this.restorePageState();
|
||||
this.initLanguage();
|
||||
@@ -342,6 +349,123 @@ class TSPDashboard {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 统一分页组件
|
||||
createPaginationComponent(data, containerId, loadFunction, itemName = '条记录') {
|
||||
const paginationContainer = document.getElementById(containerId);
|
||||
if (!paginationContainer) return;
|
||||
|
||||
const { page, total_pages, total, per_page } = data;
|
||||
|
||||
if (total_pages <= 1) {
|
||||
paginationContainer.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let paginationHtml = `
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<small class="text-muted me-3">共 ${total} ${itemName},第 ${page} / ${total_pages} 页</small>
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="form-label me-2 mb-0">每页显示:</label>
|
||||
<select class="form-select form-select-sm" style="width: auto;" onchange="dashboard.changePageSize('${containerId}', this.value, '${loadFunction}')">
|
||||
`;
|
||||
|
||||
// 每页显示条数选择器
|
||||
this.paginationConfig.pageSizeOptions.forEach(size => {
|
||||
const selected = size === per_page ? 'selected' : '';
|
||||
paginationHtml += `<option value="${size}" ${selected}>${size}</option>`;
|
||||
});
|
||||
|
||||
paginationHtml += `
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
`;
|
||||
|
||||
// 上一页
|
||||
if (page > 1) {
|
||||
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadPage('${loadFunction}', ${page - 1}, '${containerId}')">上一页</a></li>`;
|
||||
}
|
||||
|
||||
// 页码
|
||||
const startPage = Math.max(1, page - Math.floor(this.paginationConfig.maxVisiblePages / 2));
|
||||
const endPage = Math.min(total_pages, startPage + this.paginationConfig.maxVisiblePages - 1);
|
||||
|
||||
// 如果开始页码大于1,显示第一页和省略号
|
||||
if (startPage > 1) {
|
||||
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadPage('${loadFunction}', 1, '${containerId}')">1</a></li>`;
|
||||
if (startPage > 2) {
|
||||
paginationHtml += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示页码范围
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const activeClass = i === page ? 'active' : '';
|
||||
paginationHtml += `<li class="page-item ${activeClass}"><a class="page-link" href="#" onclick="dashboard.loadPage('${loadFunction}', ${i}, '${containerId}')">${i}</a></li>`;
|
||||
}
|
||||
|
||||
// 如果结束页码小于总页数,显示省略号和最后一页
|
||||
if (endPage < total_pages) {
|
||||
if (endPage < total_pages - 1) {
|
||||
paginationHtml += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
|
||||
}
|
||||
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadPage('${loadFunction}', ${total_pages}, '${containerId}')">${total_pages}</a></li>`;
|
||||
}
|
||||
|
||||
// 下一页
|
||||
if (page < total_pages) {
|
||||
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadPage('${loadFunction}', ${page + 1}, '${containerId}')">下一页</a></li>`;
|
||||
}
|
||||
|
||||
paginationHtml += `
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
`;
|
||||
|
||||
paginationContainer.innerHTML = paginationHtml;
|
||||
}
|
||||
|
||||
// 加载指定页面
|
||||
loadPage(loadFunction, page, containerId) {
|
||||
const pageSize = this.getPageSize(containerId);
|
||||
if (loadFunction === 'loadAlerts') {
|
||||
this.loadAlerts(page, true);
|
||||
} else if (loadFunction === 'loadWorkOrders') {
|
||||
this.loadWorkOrders(page, true);
|
||||
} else if (loadFunction === 'loadKnowledge') {
|
||||
this.loadKnowledge(page);
|
||||
} else if (loadFunction === 'loadConversationHistory') {
|
||||
this.loadConversationHistory(page);
|
||||
}
|
||||
}
|
||||
|
||||
// 改变每页显示条数
|
||||
changePageSize(containerId, pageSize, loadFunction) {
|
||||
// 保存页面大小到localStorage
|
||||
localStorage.setItem(`pageSize_${containerId}`, pageSize);
|
||||
|
||||
// 重新加载第一页
|
||||
if (loadFunction === 'loadAlerts') {
|
||||
this.loadAlerts(1, true);
|
||||
} else if (loadFunction === 'loadWorkOrders') {
|
||||
this.loadWorkOrders(1, true);
|
||||
} else if (loadFunction === 'loadKnowledge') {
|
||||
this.loadKnowledge(1);
|
||||
} else if (loadFunction === 'loadConversationHistory') {
|
||||
this.loadConversationHistory(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取页面大小
|
||||
getPageSize(containerId) {
|
||||
const saved = localStorage.getItem(`pageSize_${containerId}`);
|
||||
return saved ? parseInt(saved) : this.paginationConfig.defaultPageSize;
|
||||
}
|
||||
|
||||
setCachedData(key, data) {
|
||||
this.cache.set(key, {
|
||||
@@ -1348,14 +1472,27 @@ class TSPDashboard {
|
||||
}
|
||||
|
||||
// 预警管理
|
||||
async loadAlerts() {
|
||||
async loadAlerts(page = 1, forceRefresh = false) {
|
||||
const cacheKey = `alerts_page_${page}`;
|
||||
|
||||
if (!forceRefresh && this.cache.has(cacheKey)) {
|
||||
const cachedData = this.cache.get(cacheKey);
|
||||
this.updateAlertsDisplay(cachedData.alerts);
|
||||
this.updateAlertsPagination(cachedData);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/alerts');
|
||||
const alerts = await response.json();
|
||||
this.updateAlertsDisplay(alerts);
|
||||
this.updateAlertStatistics(alerts);
|
||||
const pageSize = this.getPageSize('alerts-pagination');
|
||||
const response = await fetch(`/api/alerts?page=${page}&per_page=${pageSize}`);
|
||||
const data = await response.json();
|
||||
|
||||
this.cache.set(cacheKey, data);
|
||||
this.updateAlertsDisplay(data.alerts);
|
||||
this.updateAlertsPagination(data);
|
||||
} catch (error) {
|
||||
console.error('加载预警失败:', error);
|
||||
this.showNotification('加载预警失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1418,6 +1555,10 @@ class TSPDashboard {
|
||||
container.innerHTML = headerHtml + alertsHtml;
|
||||
}
|
||||
|
||||
updateAlertsPagination(data) {
|
||||
this.createPaginationComponent(data, 'alerts-pagination', 'loadAlerts', '条预警');
|
||||
}
|
||||
|
||||
updateAlertStatistics(alerts) {
|
||||
const stats = alerts.reduce((acc, alert) => {
|
||||
acc[alert.level] = (acc[alert.level] || 0) + 1;
|
||||
@@ -1517,7 +1658,8 @@ class TSPDashboard {
|
||||
// 知识库管理
|
||||
async loadKnowledge(page = 1) {
|
||||
try {
|
||||
const response = await fetch(`/api/knowledge?page=${page}&per_page=10`);
|
||||
const pageSize = this.getPageSize('knowledge-pagination');
|
||||
const response = await fetch(`/api/knowledge?page=${page}&per_page=${pageSize}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.knowledge) {
|
||||
@@ -1596,51 +1738,7 @@ class TSPDashboard {
|
||||
}
|
||||
|
||||
updateKnowledgePagination(data) {
|
||||
const paginationContainer = document.getElementById('knowledge-pagination');
|
||||
if (!paginationContainer) return;
|
||||
|
||||
const { page, total_pages, total } = data;
|
||||
|
||||
if (total_pages <= 1) {
|
||||
paginationContainer.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let paginationHtml = `
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<small class="text-muted">共 ${total} 条知识,第 ${page} / ${total_pages} 页</small>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
`;
|
||||
|
||||
// 上一页
|
||||
if (page > 1) {
|
||||
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadKnowledge(${page - 1})">上一页</a></li>`;
|
||||
}
|
||||
|
||||
// 页码
|
||||
const startPage = Math.max(1, page - 2);
|
||||
const endPage = Math.min(total_pages, page + 2);
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const activeClass = i === page ? 'active' : '';
|
||||
paginationHtml += `<li class="page-item ${activeClass}"><a class="page-link" href="#" onclick="dashboard.loadKnowledge(${i})">${i}</a></li>`;
|
||||
}
|
||||
|
||||
// 下一页
|
||||
if (page < total_pages) {
|
||||
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadKnowledge(${page + 1})">下一页</a></li>`;
|
||||
}
|
||||
|
||||
paginationHtml += `
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
`;
|
||||
|
||||
paginationContainer.innerHTML = paginationHtml;
|
||||
this.createPaginationComponent(data, 'knowledge-pagination', 'loadKnowledge', '条知识');
|
||||
}
|
||||
|
||||
async searchKnowledge() {
|
||||
@@ -1919,13 +2017,25 @@ class TSPDashboard {
|
||||
}
|
||||
|
||||
// 工单管理
|
||||
async loadWorkOrders(forceRefresh = false) {
|
||||
async loadWorkOrders(page = 1, forceRefresh = false) {
|
||||
const cacheKey = `workorders_page_${page}`;
|
||||
|
||||
if (!forceRefresh && this.cache.has(cacheKey)) {
|
||||
const cachedData = this.cache.get(cacheKey);
|
||||
this.updateWorkOrdersDisplay(cachedData.workorders);
|
||||
this.updateWorkOrdersPagination(cachedData);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const statusFilter = document.getElementById('workorder-status-filter')?.value || 'all';
|
||||
const priorityFilter = document.getElementById('workorder-priority-filter')?.value || 'all';
|
||||
|
||||
let url = '/api/workorders';
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', page);
|
||||
const pageSize = this.getPageSize('workorders-pagination');
|
||||
params.append('per_page', pageSize.toString());
|
||||
if (statusFilter !== 'all') params.append('status', statusFilter);
|
||||
if (priorityFilter !== 'all') params.append('priority', priorityFilter);
|
||||
|
||||
@@ -1948,15 +2058,12 @@ class TSPDashboard {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const workorders = await response.json();
|
||||
this.updateWorkOrdersDisplay(workorders);
|
||||
this.updateWorkOrderStatistics(workorders);
|
||||
const data = await response.json();
|
||||
this.updateWorkOrdersDisplay(data.workorders);
|
||||
this.updateWorkOrdersPagination(data);
|
||||
|
||||
// 更新缓存
|
||||
this.cache.set('workorders', {
|
||||
data: workorders,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
this.cache.set(cacheKey, data);
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载工单失败:', error);
|
||||
@@ -2023,6 +2130,10 @@ class TSPDashboard {
|
||||
container.innerHTML = headerHtml + workordersHtml;
|
||||
}
|
||||
|
||||
updateWorkOrdersPagination(data) {
|
||||
this.createPaginationComponent(data, 'workorders-pagination', 'loadWorkOrders', '个工单');
|
||||
}
|
||||
|
||||
updateWorkOrderStatistics(workorders) {
|
||||
const stats = workorders.reduce((acc, wo) => {
|
||||
acc.total = (acc.total || 0) + 1;
|
||||
@@ -2626,14 +2737,15 @@ class TSPDashboard {
|
||||
}
|
||||
|
||||
// 对话历史管理
|
||||
async loadConversationHistory(page = 1, perPage = 10) {
|
||||
async loadConversationHistory(page = 1) {
|
||||
try {
|
||||
const response = await fetch(`/api/conversations?page=${page}&per_page=${perPage}`);
|
||||
const pageSize = this.getPageSize('conversations-pagination');
|
||||
const response = await fetch(`/api/conversations?page=${page}&per_page=${pageSize}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
if (data.conversations) {
|
||||
this.renderConversationList(data.conversations || []);
|
||||
this.renderConversationPagination(data.pagination || {});
|
||||
this.updateConversationPagination(data);
|
||||
this.updateConversationStats(data.stats || {});
|
||||
} else {
|
||||
throw new Error(data.error || '加载对话历史失败');
|
||||
@@ -2688,36 +2800,8 @@ class TSPDashboard {
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
renderConversationPagination(pagination) {
|
||||
const container = document.getElementById('conversation-pagination');
|
||||
if (!pagination || !pagination.total_pages || pagination.total_pages <= 1) {
|
||||
container.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPage = pagination.current_page || 1;
|
||||
const totalPages = pagination.total_pages;
|
||||
|
||||
let html = '<nav><ul class="pagination justify-content-center">';
|
||||
|
||||
// 上一页
|
||||
if (currentPage > 1) {
|
||||
html += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadConversationHistory(${currentPage - 1})">上一页</a></li>`;
|
||||
}
|
||||
|
||||
// 页码
|
||||
for (let i = Math.max(1, currentPage - 2); i <= Math.min(totalPages, currentPage + 2); i++) {
|
||||
const activeClass = i === currentPage ? 'active' : '';
|
||||
html += `<li class="page-item ${activeClass}"><a class="page-link" href="#" onclick="dashboard.loadConversationHistory(${i})">${i}</a></li>`;
|
||||
}
|
||||
|
||||
// 下一页
|
||||
if (currentPage < totalPages) {
|
||||
html += `<li class="page-item"><a class="page-link" href="#" onclick="dashboard.loadConversationHistory(${currentPage + 1})">下一页</a></li>`;
|
||||
}
|
||||
|
||||
html += '</ul></nav>';
|
||||
container.innerHTML = html;
|
||||
updateConversationPagination(data) {
|
||||
this.createPaginationComponent(data, 'conversations-pagination', 'loadConversationHistory', '条对话');
|
||||
}
|
||||
|
||||
updateConversationStats(stats) {
|
||||
|
||||
Reference in New Issue
Block a user