Trae AI 4 weeks ago
parent
commit
6a045a0131
  1. 4
      web/src/main/resources/application.yaml
  2. 151
      web/src/main/resources/static/apiRequestManager.js
  3. 219
      web/src/main/resources/static/index.html

4
web/src/main/resources/application.yaml

@ -7,8 +7,8 @@ spring:
password: schl@2025 password: schl@2025
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
hikari: hikari:
max-lifetime: 1200000 max-lifetime: 1200000 # 连接最大生命周期,单位毫秒
idle-timeout: 600000 idle-timeout: 600000 # 连接空闲超时时间,单位毫秒
minimum-idle: 5 minimum-idle: 5
maximum-pool-size: 20 maximum-pool-size: 20
# wechat_app数据库 # wechat_app数据库

151
web/src/main/resources/static/apiRequestManager.js

@ -0,0 +1,151 @@
// 对象转查询字符串函数
function objectToQueryString(obj) {
return Object.keys(obj)
.map(key => key + '=' + encodeURIComponent(obj[key]))
.join('&');
}
// API请求管理
var apiRequestManager = {
pendingRequests: {},
// 生成请求键
generateRequestKey: function(url, params) {
var sortedParams = Object.keys(params)
.sort()
.map(key => `${key}:${params[key]}`)
.join('_');
return `${url}_${sortedParams}`;
},
// 优先级定义
PRIORITY: {
HIGH: 1, // 高优先级(用户主动操作,如下一页点击)
MEDIUM: 2, // 中优先级(如标签页切换)
LOW: 3 // 低优先级(如后台预加载)
},
requestQueue: [],
isProcessingQueue: false,
// 发送请求
sendRequest: function(url, params, callback, priority = this.PRIORITY.MEDIUM) {
var requestKey = this.generateRequestKey(url, params);
// 取消之前的相同请求
this.cancelRequest(requestKey);
// 创建请求对象
var request = {
key: requestKey,
url: url,
params: params,
callback: callback,
priority: priority,
xhr: null
};
// 将请求添加到队列
this.requestQueue.push(request);
// 按优先级排序队列
this.requestQueue.sort((a, b) => a.priority - b.priority);
// 处理请求队列
this.processRequestQueue();
return requestKey;
},
// 取消请求
cancelRequest: function(requestKey) {
if (this.pendingRequests[requestKey]) {
this.pendingRequests[requestKey].abort();
delete this.pendingRequests[requestKey];
}
// 从队列中移除
this.requestQueue = this.requestQueue.filter(request => request.key !== requestKey);
},
// 取消所有请求
cancelAllRequests: function() {
// 取消正在处理的请求
Object.keys(this.pendingRequests).forEach(key => {
this.cancelRequest(key);
});
// 清空队列
this.requestQueue = [];
this.isProcessingQueue = false;
},
// 处理请求队列
processRequestQueue: function() {
if (this.isProcessingQueue || this.requestQueue.length === 0) {
return;
}
this.isProcessingQueue = true;
// 取出队列中的请求
var request = this.requestQueue.shift();
// 创建XHR对象
var xhr = new XMLHttpRequest();
var requestUrl = request.url + '?' + objectToQueryString(request.params);
// 保存XHR对象
request.xhr = xhr;
this.pendingRequests[request.key] = xhr;
xhr.open('GET', requestUrl, true);
xhr.timeout = 30000; // 30秒超时
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// 移除请求
delete this.pendingRequests[request.key];
if (xhr.status == 200) {
try {
var data = JSON.parse(xhr.responseText);
request.callback(null, data);
} catch (e) {
request.callback(e, null);
}
} else {
request.callback(new Error(`API请求失败,状态码: ${xhr.status}`), null);
}
// 继续处理队列
this.isProcessingQueue = false;
this.processRequestQueue();
}
}.bind(this);
xhr.ontimeout = function() {
delete this.pendingRequests[request.key];
request.callback(new Error('API请求超时'), null);
// 继续处理队列
this.isProcessingQueue = false;
this.processRequestQueue();
}.bind(this);
xhr.send();
},
// 取消低优先级请求,为高优先级请求让路
cancelLowPriorityRequests: function(minPriority) {
// 取消正在处理的低优先级请求
Object.keys(this.pendingRequests).forEach(key => {
var request = this.requestQueue.find(req => req.key === key);
if (request && request.priority > minPriority) {
this.cancelRequest(key);
}
});
// 从队列中移除低优先级请求
this.requestQueue = this.requestQueue.filter(request => request.priority <= minPriority);
}
};

219
web/src/main/resources/static/index.html

@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>客户管理系统</title> <title>客户管理系统</title>
<script src="apiRequestManager.js"></script>
<style> <style>
* { * {
margin: 0; margin: 0;
@ -1157,6 +1158,52 @@
// 定期清理过期缓存 // 定期清理过期缓存
setInterval(cleanupExpiredCache, 5 * 60 * 1000); // 每5分钟清理一次 setInterval(cleanupExpiredCache, 5 * 60 * 1000); // 每5分钟清理一次
// 带缓存的数据加载函数
function loadDataWithCache(type, url, params, callback, showSkeleton = false) {
// 生成缓存键
var cacheKey = generateCacheKey(type + '_all', params);
// 检查缓存
var cachedData = getCachedData(type, cacheKey);
if (cachedData) {
console.log('使用缓存的' + (type === 'personal' ? '个人' : '公海池') + '数据');
callback(cachedData);
return;
}
// 缓存未命中,从服务器获取数据
if (showSkeleton) {
loadingManager.showTableSkeleton(type + 'Body');
}
var fullUrl = url + '?' + objectToQueryString(params);
var xhr = new XMLHttpRequest();
xhr.open('GET', fullUrl, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var data = JSON.parse(xhr.responseText);
var users = data.users || [];
// 更新缓存
setCachedData(type, cacheKey, users);
if (showSkeleton) {
loadingManager.hideTableSkeleton(type + 'Body');
}
callback(users);
} else if (xhr.readyState == 4) {
if (showSkeleton) {
loadingManager.hideTableSkeleton(type + 'Body');
}
console.error('加载' + (type === 'personal' ? '个人' : '公海池') + '数据失败:', xhr.status, xhr.statusText);
callback([]);
}
};
xhr.send();
}
// 加载状态管理 // 加载状态管理
var loadingManager = { var loadingManager = {
// 显示加载覆盖层 // 显示加载覆盖层
@ -1250,8 +1297,17 @@
return `${url}_${sortedParams}`; return `${url}_${sortedParams}`;
}, },
// 优先级定义
PRIORITY: {
HIGH: 1, // 高优先级(用户主动操作,如下一页点击)
MEDIUM: 2, // 中优先级(如标签页切换)
LOW: 3 // 低优先级(如后台预加载)
},
requestQueue: [],
isProcessingQueue: false,
// 发送请求 // 发送请求
sendRequest: function(url, params, callback) { sendRequest: function(url, params, callback, priority = this.PRIORITY.MEDIUM) {
var requestKey = this.generateRequestKey(url, params); var requestKey = this.generateRequestKey(url, params);
// 取消之前的相同请求 // 取消之前的相同请求
@ -1300,13 +1356,91 @@
this.pendingRequests[requestKey].abort(); this.pendingRequests[requestKey].abort();
delete this.pendingRequests[requestKey]; delete this.pendingRequests[requestKey];
} }
// 从队列中移除
this.requestQueue = this.requestQueue.filter(request => request.key !== requestKey);
}, },
// 取消所有请求 // 取消所有请求
cancelAllRequests: function() { cancelAllRequests: function() {
// 取消正在处理的请求
Object.keys(this.pendingRequests).forEach(key => { Object.keys(this.pendingRequests).forEach(key => {
this.cancelRequest(key); this.cancelRequest(key);
}); });
// 清空队列
this.requestQueue = [];
this.isProcessingQueue = false;
},
// 处理请求队列
processRequestQueue: function() {
if (this.isProcessingQueue || this.requestQueue.length === 0) {
return;
}
this.isProcessingQueue = true;
// 取出队列中的请求
var request = this.requestQueue.shift();
// 创建XHR对象
var xhr = new XMLHttpRequest();
var requestUrl = request.url + '?' + objectToQueryString(request.params);
// 保存XHR对象
request.xhr = xhr;
this.pendingRequests[request.key] = xhr;
xhr.open('GET', requestUrl, true);
xhr.timeout = 30000; // 30秒超时
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// 移除请求
delete this.pendingRequests[request.key];
if (xhr.status == 200) {
try {
var data = JSON.parse(xhr.responseText);
request.callback(null, data);
} catch (e) {
request.callback(e, null);
}
} else {
request.callback(new Error(`API请求失败,状态码: ${xhr.status}`), null);
}
// 继续处理队列
this.isProcessingQueue = false;
this.processRequestQueue();
}
}.bind(this);
xhr.ontimeout = function() {
delete this.pendingRequests[request.key];
request.callback(new Error('API请求超时'), null);
// 继续处理队列
this.isProcessingQueue = false;
this.processRequestQueue();
}.bind(this);
xhr.send();
},
// 取消低优先级请求,为高优先级请求让路
cancelLowPriorityRequests: function(minPriority) {
// 取消正在处理的低优先级请求
Object.keys(this.pendingRequests).forEach(key => {
var request = this.requestQueue.find(req => req.key === key);
if (request && request.priority > minPriority) {
this.cancelRequest(key);
}
});
// 从队列中移除低优先级请求
this.requestQueue = this.requestQueue.filter(request => request.priority <= minPriority);
} }
}; };
@ -2101,6 +2235,19 @@
role: usersManagements.role || '' role: usersManagements.role || ''
}; };
// 生成缓存键
var cacheKey = generateCacheKey('personal_all', params);
// 检查缓存
var cachedData = getCachedData('personal', cacheKey);
if (cachedData) {
console.log('使用缓存的个人数据');
allPersonalData = cachedData;
isLoadingAllData = false;
displayFilteredPersonalData();
return;
}
var url = '/KH/api/users?' + objectToQueryString(params); var url = '/KH/api/users?' + objectToQueryString(params);
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
@ -2109,6 +2256,8 @@
if (xhr.readyState == 4 && xhr.status == 200) { if (xhr.readyState == 4 && xhr.status == 200) {
var data = JSON.parse(xhr.responseText); var data = JSON.parse(xhr.responseText);
allPersonalData = data.users || []; allPersonalData = data.users || [];
// 更新缓存
setCachedData('personal', cacheKey, allPersonalData);
isLoadingAllData = false; isLoadingAllData = false;
// 加载完成后显示数据 // 加载完成后显示数据
displayFilteredPersonalData(); displayFilteredPersonalData();
@ -2327,6 +2476,14 @@
// 渲染分页控件 // 渲染分页控件
renderPersonalPagination(personalPage, totalPages, total); renderPersonalPagination(personalPage, totalPages, total);
// 预加载下一页数据
if (personalPage < totalPages) {
setTimeout(function() {
console.log('预加载个人数据下一页:', personalPage + 1);
// 预加载逻辑:由于我们是在前端筛选,所以不需要额外请求,数据已经在内存中
}, 1000);
}
} else { } else {
personalEmpty.style.display = 'block'; personalEmpty.style.display = 'block';
// 没有数据时隐藏分页控件 // 没有数据时隐藏分页控件
@ -3021,6 +3178,20 @@
role: usersManagements.role || '' role: usersManagements.role || ''
}; };
// 生成缓存键
var cacheKey = generateCacheKey('public_all', params);
// 检查缓存
var cachedData = getCachedData('public', cacheKey);
if (cachedData) {
console.log('使用缓存的公海池数据');
// 隐藏骨架屏
loadingManager.hideTableSkeleton('publicBody');
allPublicData = cachedData;
displayFilteredPublicData();
return;
}
var url = '/KH/api/users/public?' + objectToQueryString(params); var url = '/KH/api/users/public?' + objectToQueryString(params);
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
@ -3033,6 +3204,8 @@
// 保存公海池数据到全局变量 // 保存公海池数据到全局变量
if (data.users) { if (data.users) {
allPublicData = data.users; allPublicData = data.users;
// 更新缓存
setCachedData('public', cacheKey, allPublicData);
} }
displayFilteredPublicData(); displayFilteredPublicData();
} else if (xhr.readyState == 4) { } else if (xhr.readyState == 4) {
@ -3169,6 +3342,14 @@
// 渲染分页控件 // 渲染分页控件
renderPublicPagination(publicPage, totalPages, total); renderPublicPagination(publicPage, totalPages, total);
// 预加载下一页数据
if (publicPage < totalPages) {
setTimeout(function() {
console.log('预加载公海池数据下一页:', publicPage + 1);
// 预加载逻辑:由于我们是在前端筛选,所以不需要额外请求,数据已经在内存中
}, 1000);
}
} else { } else {
publicEmpty.style.display = 'block'; publicEmpty.style.display = 'block';
// 没有数据时隐藏分页控件 // 没有数据时隐藏分页控件
@ -6269,12 +6450,8 @@
prevBtn.onclick = function() { prevBtn.onclick = function() {
if (current > 1) { if (current > 1) {
personalPage = current - 1; personalPage = current - 1;
// 根据当前筛选条件决定调用哪个函数 // 直接使用内存中的数据,不重新加载
if (personalFilter === 'followed' || personalFilter === 'unfollowed') { displayFilteredPersonalData();
displayFilteredPersonalData();
} else {
loadPersonalData();
}
} }
}; };
pagination.appendChild(prevBtn); pagination.appendChild(prevBtn);
@ -6288,12 +6465,8 @@
pageBtn.className = i == current ? 'active' : ''; pageBtn.className = i == current ? 'active' : '';
pageBtn.onclick = function() { pageBtn.onclick = function() {
personalPage = parseInt(this.innerHTML); personalPage = parseInt(this.innerHTML);
// 根据当前筛选条件决定调用哪个函数 // 直接使用内存中的数据,不重新加载
if (personalFilter === 'followed' || personalFilter === 'unfollowed') { displayFilteredPersonalData();
displayFilteredPersonalData();
} else {
loadPersonalData();
}
}; };
pagination.appendChild(pageBtn); pagination.appendChild(pageBtn);
} }
@ -6320,12 +6493,8 @@
pageBtn.className = i == current ? 'active' : ''; pageBtn.className = i == current ? 'active' : '';
pageBtn.onclick = function() { pageBtn.onclick = function() {
personalPage = parseInt(this.innerHTML); personalPage = parseInt(this.innerHTML);
// 根据当前筛选条件决定调用哪个函数 // 直接使用内存中的数据,不重新加载
if (personalFilter === 'followed' || personalFilter === 'unfollowed') { displayFilteredPersonalData();
displayFilteredPersonalData();
} else {
loadPersonalData();
}
}; };
pagination.appendChild(pageBtn); pagination.appendChild(pageBtn);
} }
@ -6337,12 +6506,8 @@
nextBtn.onclick = function() { nextBtn.onclick = function() {
if (current < total) { if (current < total) {
personalPage = current + 1; personalPage = current + 1;
// 根据当前筛选条件决定调用哪个函数 // 直接使用内存中的数据,不重新加载
if (personalFilter === 'followed' || personalFilter === 'unfollowed') { displayFilteredPersonalData();
displayFilteredPersonalData();
} else {
loadPersonalData();
}
} }
}; };
pagination.appendChild(nextBtn); pagination.appendChild(nextBtn);
@ -6372,7 +6537,7 @@
pageBtn.className = i == current ? 'active' : ''; pageBtn.className = i == current ? 'active' : '';
pageBtn.onclick = function() { pageBtn.onclick = function() {
publicPage = parseInt(this.innerHTML); publicPage = parseInt(this.innerHTML);
loadPublicData(); displayFilteredPublicData();
}; };
pagination.appendChild(pageBtn); pagination.appendChild(pageBtn);
} }
@ -6399,7 +6564,7 @@
pageBtn.className = i == current ? 'active' : ''; pageBtn.className = i == current ? 'active' : '';
pageBtn.onclick = function() { pageBtn.onclick = function() {
publicPage = parseInt(this.innerHTML); publicPage = parseInt(this.innerHTML);
loadPublicData(); displayFilteredPublicData();
}; };
pagination.appendChild(pageBtn); pagination.appendChild(pageBtn);
} }

Loading…
Cancel
Save