|
|
@ -10,58 +10,6 @@ |
|
|
box-sizing: border-box; |
|
|
box-sizing: border-box; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 后台加载剩余货源数据 |
|
|
|
|
|
function loadRemainingProductsData(userRole, userName, total) { |
|
|
|
|
|
console.log('开始在后台加载剩余货源数据...'); |
|
|
|
|
|
|
|
|
|
|
|
// 计算需要加载的剩余数据量 |
|
|
|
|
|
var remainingSize = Math.min(1000, total); // 最多加载1000条 |
|
|
|
|
|
|
|
|
|
|
|
// 构建查询参数 |
|
|
|
|
|
var url = '/KH/api/products?userName=' + encodeURIComponent(userName) + '&userRole=' + encodeURIComponent(userRole) + '&page=1&size=' + remainingSize; |
|
|
|
|
|
|
|
|
|
|
|
var xhr = new XMLHttpRequest(); |
|
|
|
|
|
xhr.open('GET', url, true); |
|
|
|
|
|
xhr.onreadystatechange = function() { |
|
|
|
|
|
if (xhr.readyState == 4 && xhr.status == 200) { |
|
|
|
|
|
var data = JSON.parse(xhr.responseText); |
|
|
|
|
|
if (data.success) { |
|
|
|
|
|
var allProducts = data.products || []; |
|
|
|
|
|
var totalCount = data.total || 0; |
|
|
|
|
|
var pages = Math.ceil(totalCount / productsPageSize); |
|
|
|
|
|
|
|
|
|
|
|
// 更新缓存 |
|
|
|
|
|
setCachedData('products', 'all', { |
|
|
|
|
|
products: allProducts, |
|
|
|
|
|
total: totalCount, |
|
|
|
|
|
pages: pages |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 缓存所有页面数据 |
|
|
|
|
|
for (var i = 1; i <= pages && i <= 100; i++) { // 最多缓存100页 |
|
|
|
|
|
var startIndex = (i - 1) * productsPageSize; |
|
|
|
|
|
var endIndex = startIndex + productsPageSize; |
|
|
|
|
|
var pageProducts = allProducts.slice(startIndex, endIndex); |
|
|
|
|
|
|
|
|
|
|
|
setCachedData('products', 'page_' + i + '_size_' + productsPageSize, { |
|
|
|
|
|
products: pageProducts, |
|
|
|
|
|
total: totalCount, |
|
|
|
|
|
pages: pages |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log('后台加载剩余货源数据完成,共', allProducts.length, '条数据,分为', pages, '页'); |
|
|
|
|
|
console.log('已缓存', Math.min(pages, 100), '页数据'); |
|
|
|
|
|
} else { |
|
|
|
|
|
console.error('后台加载剩余货源数据失败:', data.message); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (xhr.readyState == 4) { |
|
|
|
|
|
console.error('后台加载剩余货源数据失败:', xhr.status, xhr.statusText); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
xhr.send(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
body { |
|
|
body { |
|
|
font-family: Arial, sans-serif; |
|
|
font-family: Arial, sans-serif; |
|
|
background-color: #f5f7fa; |
|
|
background-color: #f5f7fa; |
|
|
@ -2231,6 +2179,59 @@ |
|
|
updateFilterTags('public'); |
|
|
updateFilterTags('public'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 后台加载剩余货源数据 |
|
|
|
|
|
function loadRemainingProductsData(userRole, userName, total) { |
|
|
|
|
|
console.log('开始在后台加载剩余货源数据...'); |
|
|
|
|
|
|
|
|
|
|
|
// 计算需要加载的剩余数据量 |
|
|
|
|
|
var remainingSize = Math.min(1000, total); // 最多加载1000条 |
|
|
|
|
|
|
|
|
|
|
|
// 构建查询参数 |
|
|
|
|
|
var url = '/KH/api/products?userName=' + encodeURIComponent(userName) + '&userRole=' + encodeURIComponent(userRole) + '&page=1&size=' + remainingSize; |
|
|
|
|
|
|
|
|
|
|
|
var xhr = new XMLHttpRequest(); |
|
|
|
|
|
xhr.open('GET', url, true); |
|
|
|
|
|
xhr.onreadystatechange = function() { |
|
|
|
|
|
if (xhr.readyState == 4 && xhr.status == 200) { |
|
|
|
|
|
var data = JSON.parse(xhr.responseText); |
|
|
|
|
|
if (data.success) { |
|
|
|
|
|
var allProducts = data.products || []; |
|
|
|
|
|
var totalCount = data.total || 0; |
|
|
|
|
|
var pages = Math.ceil(totalCount / productsPageSize); |
|
|
|
|
|
|
|
|
|
|
|
// 更新缓存 |
|
|
|
|
|
setCachedData('products', 'all', { |
|
|
|
|
|
products: allProducts, |
|
|
|
|
|
total: totalCount, |
|
|
|
|
|
pages: pages |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 缓存所有页面数据 |
|
|
|
|
|
for (var i = 1; i <= pages && i <= 100; i++) { // 最多缓存100页 |
|
|
|
|
|
var startIndex = (i - 1) * productsPageSize; |
|
|
|
|
|
var endIndex = startIndex + productsPageSize; |
|
|
|
|
|
var pageProducts = allProducts.slice(startIndex, endIndex); |
|
|
|
|
|
|
|
|
|
|
|
setCachedData('products', 'page_' + i + '_size_' + productsPageSize, { |
|
|
|
|
|
products: pageProducts, |
|
|
|
|
|
total: totalCount, |
|
|
|
|
|
pages: pages |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log('后台加载剩余货源数据完成,共', allProducts.length, '条数据,分为', pages, '页'); |
|
|
|
|
|
console.log('已缓存', Math.min(pages, 100), '页数据'); |
|
|
|
|
|
} else { |
|
|
|
|
|
console.error('后台加载剩余货源数据失败:', data.message); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (xhr.readyState == 4) { |
|
|
|
|
|
console.error('后台加载剩余货源数据失败:', xhr.status, xhr.statusText); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
xhr.send(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 重置公海池数据创建时间筛选 |
|
|
// 重置公海池数据创建时间筛选 |
|
|
function resetPublicDateFilter() { |
|
|
function resetPublicDateFilter() { |
|
|
document.getElementById('publicStartDate').value = ''; |
|
|
document.getElementById('publicStartDate').value = ''; |
|
|
@ -2726,16 +2727,21 @@ |
|
|
mergedTraces.forEach(trace => { |
|
|
mergedTraces.forEach(trace => { |
|
|
if (trace.phoneNumber) { |
|
|
if (trace.phoneNumber) { |
|
|
// 根据电话号码获取用户信息 |
|
|
// 根据电话号码获取用户信息 |
|
|
var url = '/KH/api/users/public?phoneNumber=' + encodeURIComponent(trace.phoneNumber) + '&userRole=admin'; |
|
|
var url = '/KH/api/users/public?phoneNumber=' + encodeURIComponent(trace.phoneNumber) + '&userRole=管理员'; |
|
|
var xhr = new XMLHttpRequest(); |
|
|
var xhr = new XMLHttpRequest(); |
|
|
xhr.open('GET', url, true); |
|
|
xhr.open('GET', url, true); |
|
|
xhr.onreadystatechange = function() { |
|
|
xhr.onreadystatechange = function() { |
|
|
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); |
|
|
if (data.users && data.users.length > 0) { |
|
|
if (data.users && data.users.length > 0) { |
|
|
var user = data.users[0]; |
|
|
// 根据电话号码筛选正确的用户 |
|
|
var createTime = user.create_time; |
|
|
var user = data.users.find(u => |
|
|
var followupTime = user.followup_time; |
|
|
u.phoneNumber === trace.phoneNumber || |
|
|
|
|
|
u.phoneNumber === trace.phoneNumber.replace(/\s/g, '') |
|
|
|
|
|
) || data.users[0]; |
|
|
|
|
|
// 统一使用正确的字段名 |
|
|
|
|
|
var createTime = user.created_at || user.create_time; |
|
|
|
|
|
var followupTime = user.followup_at || user.followup_time; |
|
|
|
|
|
|
|
|
if (createTime && followupTime) { |
|
|
if (createTime && followupTime) { |
|
|
// 计算响应时间 |
|
|
// 计算响应时间 |
|
|
@ -4232,7 +4238,7 @@ |
|
|
// 员工申请记录模态框HTML |
|
|
// 员工申请记录模态框HTML |
|
|
var employeeApplyModalHTML = ` |
|
|
var employeeApplyModalHTML = ` |
|
|
<div id="employeeApplyModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.7) 100%); backdrop-filter: blur(5px); display: none; z-index: 1000; animation: fadeIn 0.3s ease;"> |
|
|
<div id="employeeApplyModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.7) 100%); backdrop-filter: blur(5px); display: none; z-index: 1000; animation: fadeIn 0.3s ease;"> |
|
|
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); width: 90%; max-width: 900px; max-height: 80vh; overflow: hidden; display: flex; flex-direction: column; animation: slideIn 0.3s ease;"> |
|
|
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); width: 95%; max-width: 1200px; max-height: 80vh; overflow: hidden; display: flex; flex-direction: column; animation: slideIn 0.3s ease;"> |
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8;"> |
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8;"> |
|
|
<h3 style="margin: 0; color: #722ed1;">我的申请记录</h3> |
|
|
<h3 style="margin: 0; color: #722ed1;">我的申请记录</h3> |
|
|
<button onclick="closeEmployeeApplyModal()" style="background: none; border: none; font-size: 20px; cursor: pointer; color: #999;">×</button> |
|
|
<button onclick="closeEmployeeApplyModal()" style="background: none; border: none; font-size: 20px; cursor: pointer; color: #999;">×</button> |
|
|
@ -4247,16 +4253,16 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div style="overflow-x: auto;"> |
|
|
<div style="overflow-x: auto;"> |
|
|
<table style="width: 100%; border-collapse: collapse;"> |
|
|
<table style="width: 100%; border-collapse: collapse; table-layout: fixed;"> |
|
|
<thead> |
|
|
<thead> |
|
|
<tr style="background-color: #f5f5f5;"> |
|
|
<tr style="background-color: #f5f5f5;"> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">申请ID</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; width: 80px; white-space: nowrap;">申请ID</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">客户ID</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; width: 180px; white-space: nowrap;">客户ID</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">申请时间</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; width: 140px; white-space: nowrap;">申请时间</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">状态</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; width: 80px; white-space: nowrap;">状态</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">审批时间</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; width: 140px; white-space: nowrap;">审批时间</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">审批人</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; width: 80px; white-space: nowrap;">审批人</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left;">备注</th> |
|
|
<th style="padding: 10px; border: 1px solid #e8e8e8; text-align: left; flex: 1;">备注</th> |
|
|
</tr> |
|
|
</tr> |
|
|
</thead> |
|
|
</thead> |
|
|
<tbody id="employeeApplyTableBody"> |
|
|
<tbody id="employeeApplyTableBody"> |
|
|
@ -6381,15 +6387,15 @@ |
|
|
|
|
|
|
|
|
var row = ` |
|
|
var row = ` |
|
|
<tr> |
|
|
<tr> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${apply.id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.user_id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${apply.user_id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.sales_name}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.sales_name}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.original_manager_name || '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.original_manager_name || '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${formatDateTime(apply.apply_time)}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${formatDateTime(apply.apply_time)}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;"> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;"> |
|
|
<span style="display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 12px; color: white; background-color: ${statusColor};">${statusText}</span> |
|
|
<span style="display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 12px; color: white; background-color: ${statusColor};">${statusText}</span> |
|
|
</td> |
|
|
</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: normal; word-wrap: break-word; max-width: 300px;">${apply.reason}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${apply.reason || '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${actionButtons}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${actionButtons}</td> |
|
|
</tr> |
|
|
</tr> |
|
|
`; |
|
|
`; |
|
|
@ -6520,15 +6526,15 @@ |
|
|
|
|
|
|
|
|
var row = ` |
|
|
var row = ` |
|
|
<tr> |
|
|
<tr> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${apply.id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.user_id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${apply.user_id}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${formatDateTime(apply.apply_time)}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${formatDateTime(apply.apply_time)}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;"> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;"> |
|
|
<span style="display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 12px; color: white; background-color: ${statusColor};">${statusText}</span> |
|
|
<span style="display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 12px; color: white; background-color: ${statusColor};">${statusText}</span> |
|
|
</td> |
|
|
</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.approve_time ? formatDateTime(apply.approve_time) : '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${apply.approve_time ? formatDateTime(apply.approve_time) : '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8;">${apply.approve_by || '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${apply.approve_by || '-'}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: normal; word-wrap: break-word; max-width: 300px;">${apply.reason}</td> |
|
|
<td style="padding: 10px; border: 1px solid #e8e8e8; white-space: nowrap;">${apply.reason || '-'}</td> |
|
|
</tr> |
|
|
</tr> |
|
|
`; |
|
|
`; |
|
|
|
|
|
|
|
|
@ -6553,7 +6559,7 @@ |
|
|
if (trace.phoneNumber) { |
|
|
if (trace.phoneNumber) { |
|
|
console.log('处理电话号码:', trace.phoneNumber); |
|
|
console.log('处理电话号码:', trace.phoneNumber); |
|
|
// 根据电话号码获取用户信息 |
|
|
// 根据电话号码获取用户信息 |
|
|
var url = '/KH/api/users/public?phoneNumber=' + encodeURIComponent(trace.phoneNumber) + '&userRole=admin'; |
|
|
var url = '/KH/api/users/public?phoneNumber=' + encodeURIComponent(trace.phoneNumber) + '&userRole=管理员'; |
|
|
console.log('API请求URL:', url); |
|
|
console.log('API请求URL:', url); |
|
|
var xhr = new XMLHttpRequest(); |
|
|
var xhr = new XMLHttpRequest(); |
|
|
xhr.open('GET', url, true); |
|
|
xhr.open('GET', url, true); |
|
|
@ -6565,16 +6571,32 @@ |
|
|
var data = JSON.parse(xhr.responseText); |
|
|
var data = JSON.parse(xhr.responseText); |
|
|
console.log('API响应数据:', data); |
|
|
console.log('API响应数据:', data); |
|
|
if (data.users && data.users.length > 0) { |
|
|
if (data.users && data.users.length > 0) { |
|
|
var user = data.users[0]; |
|
|
// 根据电话号码筛选正确的用户 |
|
|
|
|
|
var user = data.users.find(u => |
|
|
|
|
|
u.phoneNumber === trace.phoneNumber || |
|
|
|
|
|
u.phoneNumber === trace.phoneNumber.replace(/\s/g, '') |
|
|
|
|
|
) || data.users[0]; |
|
|
console.log('用户信息:', user); |
|
|
console.log('用户信息:', user); |
|
|
var createTime = user.created_at; |
|
|
console.log('电话号码匹配:', user.phoneNumber === trace.phoneNumber); |
|
|
var followupTime = user.followup_at; |
|
|
// 统一使用正确的字段名 |
|
|
|
|
|
var createTime = user.created_at || user.create_time || user.createTime; |
|
|
|
|
|
var followupTime = user.followup_at || user.followup_time || user.followupTime; |
|
|
console.log('创建时间:', createTime, '跟进时间:', followupTime); |
|
|
console.log('创建时间:', createTime, '跟进时间:', followupTime); |
|
|
|
|
|
console.log('用户对象所有字段:', Object.keys(user)); |
|
|
|
|
|
console.log('trace对象:', trace); |
|
|
|
|
|
|
|
|
if (createTime && followupTime) { |
|
|
// 尝试从trace对象中获取跟进时间 |
|
|
|
|
|
var traceFollowupTime = trace.followupTime || trace.followUpTime; |
|
|
|
|
|
console.log('trace中的跟进时间:', traceFollowupTime); |
|
|
|
|
|
|
|
|
|
|
|
// 优先使用用户对象中的跟进时间,其次使用trace对象中的 |
|
|
|
|
|
var finalFollowupTime = followupTime || traceFollowupTime; |
|
|
|
|
|
console.log('最终使用的跟进时间:', finalFollowupTime); |
|
|
|
|
|
|
|
|
|
|
|
if (createTime && finalFollowupTime) { |
|
|
// 计算响应时间 |
|
|
// 计算响应时间 |
|
|
var createDate = new Date(createTime); |
|
|
var createDate = new Date(createTime); |
|
|
var followupDate = new Date(followupTime); |
|
|
var followupDate = new Date(finalFollowupTime); |
|
|
console.log('创建日期:', createDate, '跟进日期:', followupDate); |
|
|
console.log('创建日期:', createDate, '跟进日期:', followupDate); |
|
|
var responseTimeMs = followupDate - createDate; |
|
|
var responseTimeMs = followupDate - createDate; |
|
|
console.log('响应时间毫秒:', responseTimeMs); |
|
|
console.log('响应时间毫秒:', responseTimeMs); |
|
|
|