|
|
|
@ -2071,16 +2071,16 @@ |
|
|
|
<input type="text" id="editRegionSearchInput" placeholder="搜索地区" oninput="filterEditRegionOptions()" style="width: 100%; padding: 10px; border: 1px solid #d9d9d9; border-radius: 8px; font-size: 14px; box-sizing: border-box;"> |
|
|
|
<div id="editCurrentRegion" style="margin-top: 10px; padding: 8px 12px; background-color: #f0f8ff; border: 1px solid #91d5ff; border-radius: 4px; font-size: 12px; color: #1890ff;">当前选择: 未选择</div> |
|
|
|
</div> |
|
|
|
<div class="select-body"> |
|
|
|
<div id="editRegionOptionsList" style="display: flex; gap: 10px; padding: 10px;"> |
|
|
|
<div class="select-body" style="height: 400px;"> |
|
|
|
<div id="editRegionOptionsList" style="display: flex; gap: 10px; padding: 10px; height: 100%;"> |
|
|
|
<!-- 省市选择将通过JavaScript动态生成 --> |
|
|
|
<div id="editProvinceList" style="flex: 1; overflow-y: auto;"></div> |
|
|
|
<div id="editCityList" style="flex: 1; overflow-y: auto;"></div> |
|
|
|
<div id="editProvinceList" style="flex: 1; overflow-y: auto; height: 350px;"></div> |
|
|
|
<div id="editCityList" style="flex: 1; overflow-y: auto; height: 350px;"></div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="select-footer" style="padding: 16px 20px; display: flex; justify-content: space-between; border-top: 1px solid #f0f0f0; background-color: #fafafa;"> |
|
|
|
<button onclick="hideEditRegionSelectModal()" style="padding: 8px 20px; background-color: #f5f5f5; color: #666; border: none; border-radius: 6px; cursor: pointer;">取消</button> |
|
|
|
<button onclick="confirmEditRegionSelection()" style="padding: 8px 20px; background-color: #1677ff; color: white; border: none; border-radius: 6px; cursor: pointer;">确定</button> |
|
|
|
<button onclick="hideEditRegionSelectModal()" style="padding: 10px 24px; background-color: #f5f5f5; color: #666; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.3s ease;">取消</button> |
|
|
|
<button onclick="confirmEditRegionSelection()" style="padding: 10px 24px; background-color: #1677ff; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.3s ease;">确定</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -2112,6 +2112,9 @@ |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 操作状态跟踪,防止重复点击 |
|
|
|
let isOperating = false; |
|
|
|
|
|
|
|
// 编辑相关全局变量 |
|
|
|
let currentEditSupplyId = null; |
|
|
|
let editSelectedSpec = []; |
|
|
|
@ -2172,6 +2175,7 @@ |
|
|
|
currentUserInfoEl.innerHTML = `当前登录用户:${parsedUserInfo.name} | 用户ID:${userId} | 职位:${parsedUserInfo.projectName}`; |
|
|
|
} |
|
|
|
|
|
|
|
// 返回解析后的用户信息 |
|
|
|
return parsedUserInfo; |
|
|
|
} |
|
|
|
|
|
|
|
@ -2191,6 +2195,89 @@ |
|
|
|
// 防止loadSupplies并发执行的标志 |
|
|
|
let isLoadingSupplies = false; |
|
|
|
|
|
|
|
// 比较两个对象的差异,返回变更的字段列表 |
|
|
|
function getChangedFields(oldObj, newObj) { |
|
|
|
if (!oldObj || !newObj) return []; |
|
|
|
|
|
|
|
const changedFields = []; |
|
|
|
const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]); |
|
|
|
|
|
|
|
allKeys.forEach(key => { |
|
|
|
const oldValue = oldObj[key]; |
|
|
|
const newValue = newObj[key]; |
|
|
|
|
|
|
|
// 优化比较逻辑,减少不必要的JSON.stringify调用 |
|
|
|
// 先比较基本类型 |
|
|
|
if (oldValue !== newValue) { |
|
|
|
// 如果基本类型不同,直接添加到变更字段 |
|
|
|
// 如果是引用类型,再使用JSON.stringify比较 |
|
|
|
if (typeof oldValue !== 'object' || typeof newValue !== 'object' || |
|
|
|
oldValue === null || newValue === null || |
|
|
|
Array.isArray(oldValue) !== Array.isArray(newValue)) { |
|
|
|
changedFields.push(key); |
|
|
|
} else { |
|
|
|
// 都是对象或都是数组,使用JSON.stringify比较 |
|
|
|
if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) { |
|
|
|
changedFields.push(key); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
return changedFields; |
|
|
|
} |
|
|
|
|
|
|
|
// 记录货源操作日志 |
|
|
|
async function logSupplyOperation(operationType, productId, originalData = null, modifiedData = null, changedFields = null) { |
|
|
|
try { |
|
|
|
console.log('开始记录货源操作日志:', operationType, productId); |
|
|
|
// 获取当前登录用户信息 |
|
|
|
const userInfo = checkLogin(); |
|
|
|
console.log('获取到的用户信息:', userInfo); |
|
|
|
if (!userInfo) { |
|
|
|
console.log('没有用户信息,跳过日志记录'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 如果没有提供changedFields,自动计算 |
|
|
|
if (operationType === '修改' && originalData && modifiedData && !changedFields) { |
|
|
|
changedFields = getChangedFields(originalData, modifiedData); |
|
|
|
} |
|
|
|
|
|
|
|
// 准备日志数据 |
|
|
|
const logData = { |
|
|
|
phoneNumber: userInfo.phoneNumber, |
|
|
|
projectName: userInfo.projectName, |
|
|
|
userId: userInfo.userId || userInfo.id, // 确保使用正确的userId |
|
|
|
operationEvent: `审核系统-${operationType === '创建' ? '创建货源' : operationType === '修改' ? '编辑货源' : operationType === '下架' ? '下架货源' : operationType === '删除' ? '删除货源' : operationType}`, |
|
|
|
productId: productId, |
|
|
|
originalData: originalData, |
|
|
|
modifiedData: modifiedData, |
|
|
|
changedFields: changedFields |
|
|
|
}; |
|
|
|
|
|
|
|
console.log('准备发送的日志数据:', logData); |
|
|
|
// 调用后端API记录日志 |
|
|
|
const response = await fetch('/api/supplies/log', { |
|
|
|
method: 'POST', |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json' |
|
|
|
}, |
|
|
|
body: JSON.stringify(logData) |
|
|
|
}); |
|
|
|
|
|
|
|
const result = await response.json(); |
|
|
|
console.log('日志API返回结果:', result); |
|
|
|
if (!result.success) { |
|
|
|
console.warn('记录日志失败:', result.message); |
|
|
|
} else { |
|
|
|
console.log('日志记录成功:', result.data.logId); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('记录日志出错:', error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 初始化WebSocket连接 |
|
|
|
function initWebSocket() { |
|
|
|
// 获取当前页面的协议和主机 |
|
|
|
@ -2349,23 +2436,27 @@ |
|
|
|
startAutoOfflineCheck(); |
|
|
|
|
|
|
|
// 启动定期刷新数据,确保label字段变化能实时显示 |
|
|
|
// 优化:减少刷新频率,从5秒改为30秒,降低服务器负载 |
|
|
|
timers.loadSupplies = setInterval(() => { |
|
|
|
console.log('定期刷新数据,检查label字段变化'); |
|
|
|
loadSupplies(); |
|
|
|
}, 5000); // 每5秒刷新一次 |
|
|
|
}, 30000); // 每30秒刷新一次 |
|
|
|
|
|
|
|
// 添加防抖机制,避免短时间内多次调用loadSupplies |
|
|
|
let loadSuppliesTimeout; |
|
|
|
|
|
|
|
// 增强WebSocket消息处理,确保所有相关消息都能触发数据刷新 |
|
|
|
console.log('增强WebSocket消息处理'); |
|
|
|
if (ws) { |
|
|
|
// 添加额外的消息监听器,确保所有相关消息都能触发数据刷新 |
|
|
|
ws.addEventListener('message', function(event) { |
|
|
|
try { |
|
|
|
const data = JSON.parse(event.data); |
|
|
|
console.log('增强的WebSocket消息处理:', data); |
|
|
|
// 对于任何类型的WebSocket消息,都重新加载数据,确保label字段实时更新 |
|
|
|
if (data.type !== 'ping' && data.type !== 'pong') { |
|
|
|
console.log('收到相关WebSocket消息,刷新数据'); |
|
|
|
// 使用防抖机制,避免短时间内多次调用loadSupplies |
|
|
|
clearTimeout(loadSuppliesTimeout); |
|
|
|
loadSuppliesTimeout = setTimeout(() => { |
|
|
|
loadSupplies(); |
|
|
|
}, 1000); // 1秒防抖 |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('解析WebSocket消息失败:', error); |
|
|
|
@ -2439,38 +2530,32 @@ |
|
|
|
|
|
|
|
// 根据元素类型设置不同的显示格式 |
|
|
|
if (element.classList.contains('countdown-badge')) { |
|
|
|
element.innerHTML = `⏰ ${countdownText}`; |
|
|
|
element.textContent = `⏰ ${countdownText}`; |
|
|
|
element.style.background = 'linear-gradient(135deg, #ff6b6b, #ee5a6f)'; |
|
|
|
element.style.boxShadow = '0 2px 4px rgba(255, 107, 107, 0.3)'; |
|
|
|
} else if (element.classList.contains('countdown')) { |
|
|
|
element.innerHTML = `剩余下架时间: ${countdownText}`; |
|
|
|
element.textContent = `剩余下架时间: ${countdownText}`; |
|
|
|
} |
|
|
|
console.log('更新倒计时显示为:', countdownText); |
|
|
|
} else { |
|
|
|
// 时间到了 |
|
|
|
console.log('时间已到,显示已下架'); |
|
|
|
if (element.classList.contains('countdown-badge')) { |
|
|
|
element.innerHTML = '⏰ 已下架'; |
|
|
|
element.textContent = '⏰ 已下架'; |
|
|
|
element.style.background = '#8c8c8c'; |
|
|
|
element.style.boxShadow = '0 2px 4px rgba(140, 140, 140, 0.3)'; |
|
|
|
} else if (element.classList.contains('countdown')) { |
|
|
|
element.innerHTML = '剩余下架时间: 已下架'; |
|
|
|
element.textContent = '剩余下架时间: 已下架'; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 没有设置自动下架时间,隐藏倒计时或显示无倒计时 |
|
|
|
console.log('没有设置自动下架时间,隐藏倒计时'); |
|
|
|
if (element.classList.contains('countdown-badge')) { |
|
|
|
element.innerHTML = '⏰ 无倒计时'; |
|
|
|
element.textContent = '⏰ 无倒计时'; |
|
|
|
element.style.background = '#52c41a'; |
|
|
|
element.style.boxShadow = '0 2px 4px rgba(82, 196, 26, 0.3)'; |
|
|
|
} else if (element.classList.contains('countdown')) { |
|
|
|
element.innerHTML = '剩余下架时间: 无'; |
|
|
|
element.textContent = '剩余下架时间: 无'; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
console.log('未找到对应的货源,supplyId:', supplyId); |
|
|
|
console.log('supplyData.supplies:', supplyData.supplies); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -4074,8 +4159,10 @@ |
|
|
|
const provinceList = document.getElementById('provinceList'); |
|
|
|
const cityList = document.getElementById('cityList'); |
|
|
|
|
|
|
|
// 使用文档片段减少DOM重绘 |
|
|
|
const provinceFragment = document.createDocumentFragment(); |
|
|
|
|
|
|
|
// 生成省份选项 |
|
|
|
provinceList.innerHTML = ''; |
|
|
|
filteredProvinces.forEach(province => { |
|
|
|
const option = document.createElement('div'); |
|
|
|
option.className = 'select-item'; |
|
|
|
@ -4092,15 +4179,21 @@ |
|
|
|
cityList.scrollTop = 0; |
|
|
|
}, 100); |
|
|
|
}; |
|
|
|
provinceList.appendChild(option); |
|
|
|
provinceFragment.appendChild(option); |
|
|
|
}); |
|
|
|
|
|
|
|
// 一次性添加到DOM,减少重绘 |
|
|
|
provinceList.innerHTML = ''; |
|
|
|
provinceList.appendChild(provinceFragment); |
|
|
|
} |
|
|
|
|
|
|
|
// 生成城市选项 |
|
|
|
function generateCityOptions(cities) { |
|
|
|
const cityList = document.getElementById('cityList'); |
|
|
|
|
|
|
|
cityList.innerHTML = ''; |
|
|
|
// 使用文档片段减少DOM重绘 |
|
|
|
const cityFragment = document.createDocumentFragment(); |
|
|
|
|
|
|
|
cities.forEach(city => { |
|
|
|
const option = document.createElement('div'); |
|
|
|
option.className = 'select-item'; |
|
|
|
@ -4122,9 +4215,13 @@ |
|
|
|
hideRegionSelectModal(); |
|
|
|
saveFormData(); // 保存选择 |
|
|
|
}; |
|
|
|
cityList.appendChild(option); |
|
|
|
cityFragment.appendChild(option); |
|
|
|
}); |
|
|
|
|
|
|
|
// 一次性添加到DOM,减少重绘 |
|
|
|
cityList.innerHTML = ''; |
|
|
|
cityList.appendChild(cityFragment); |
|
|
|
|
|
|
|
// 使用scrollIntoView滚动到第一个城市 |
|
|
|
setTimeout(() => { |
|
|
|
const firstCity = cityList.querySelector('.select-item'); |
|
|
|
@ -6282,6 +6379,13 @@ |
|
|
|
localStorage.removeItem('supplyFormDraft'); |
|
|
|
console.log('创建成功,已清除保存的表单数据'); |
|
|
|
alert('货源创建成功'); |
|
|
|
|
|
|
|
// 记录创建货源日志 |
|
|
|
const userInfo = checkLogin(); |
|
|
|
if (userInfo) { |
|
|
|
await logSupplyOperation('创建', result.data.id, null, result.data); |
|
|
|
} |
|
|
|
|
|
|
|
// 重置表单状态,确保下次打开时是空白状态 |
|
|
|
resetForm(); |
|
|
|
hideAddSupplyModal(); |
|
|
|
@ -6716,19 +6820,40 @@ |
|
|
|
|
|
|
|
// 下架货源 |
|
|
|
async function unpublishSupply(id) { |
|
|
|
// 防止重复点击 |
|
|
|
if (isOperating) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (confirm('确定要下架该货源吗?')) { |
|
|
|
try { |
|
|
|
isOperating = true; |
|
|
|
|
|
|
|
// 获取要下架的货源的原始数据 |
|
|
|
const originalSupply = supplyData.supplies.find(s => String(s.id) === String(id)); |
|
|
|
if (!originalSupply) { |
|
|
|
alert('找不到要下架的货源数据'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const response = await fetch(`/api/supplies/${id}/unpublish`, { |
|
|
|
method: 'POST' |
|
|
|
}); |
|
|
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
|
|
// 记录下架货源日志 |
|
|
|
const userInfo = checkLogin(); |
|
|
|
if (userInfo) { |
|
|
|
// 传入修改后的数据,包含状态变化 |
|
|
|
await logSupplyOperation('下架', id, originalSupply, result.data); |
|
|
|
} |
|
|
|
|
|
|
|
// 向WebSocket服务器发送消息,通知其他客户端货源已下架 |
|
|
|
sendWebSocketMessage({ |
|
|
|
type: 'supply_status_change', |
|
|
|
supplyId: id, |
|
|
|
action: 'unpublish', |
|
|
|
status: 'hidden' |
|
|
|
status: 'sold_out' |
|
|
|
}); |
|
|
|
|
|
|
|
alert('下架成功'); |
|
|
|
@ -6739,6 +6864,8 @@ |
|
|
|
} catch (error) { |
|
|
|
console.error('下架失败:', error); |
|
|
|
alert('下架失败: 网络错误'); |
|
|
|
} finally { |
|
|
|
isOperating = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -6746,18 +6873,40 @@ |
|
|
|
// 显示编辑货源 |
|
|
|
// 删除货源 |
|
|
|
async function deleteSupply(id) { |
|
|
|
// 防止重复点击 |
|
|
|
if (isOperating) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (confirm('确定要删除该货源吗?')) { |
|
|
|
try { |
|
|
|
isOperating = true; |
|
|
|
|
|
|
|
// 获取要删除的货源的原始数据 |
|
|
|
const originalSupply = supplyData.supplies.find(s => String(s.id) === String(id)); |
|
|
|
if (!originalSupply) { |
|
|
|
alert('找不到要删除的货源数据'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const response = await fetch(`/api/supplies/${id}/delete`, { |
|
|
|
method: 'POST' |
|
|
|
}); |
|
|
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
|
|
// 记录删除货源日志 |
|
|
|
const userInfo = checkLogin(); |
|
|
|
if (userInfo) { |
|
|
|
// 传入修改后的数据,包含状态变化 |
|
|
|
await logSupplyOperation('删除', id, originalSupply, result.data); |
|
|
|
} |
|
|
|
|
|
|
|
// 向WebSocket服务器发送消息,通知其他客户端货源已删除 |
|
|
|
sendWebSocketMessage({ |
|
|
|
type: 'supply_update', |
|
|
|
supplyId: id, |
|
|
|
action: 'delete' |
|
|
|
action: 'delete', |
|
|
|
status: 'hidden' |
|
|
|
}); |
|
|
|
|
|
|
|
alert('删除成功'); |
|
|
|
@ -6768,6 +6917,8 @@ |
|
|
|
} catch (error) { |
|
|
|
console.error('删除失败:', error); |
|
|
|
alert('删除失败: 网络错误'); |
|
|
|
} finally { |
|
|
|
isOperating = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -7103,12 +7254,19 @@ |
|
|
|
|
|
|
|
// 上架货源 |
|
|
|
async function publishSupply(id) { |
|
|
|
// 防止重复点击 |
|
|
|
if (isOperating) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (!id) { |
|
|
|
alert('货源ID不存在'); |
|
|
|
return; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
isOperating = true; |
|
|
|
|
|
|
|
const response = await fetch(`/api/supplies/${id}/publish`, { |
|
|
|
method: 'POST' |
|
|
|
}); |
|
|
|
@ -7133,6 +7291,8 @@ |
|
|
|
console.error('上架失败:', error); |
|
|
|
alert('上架失败: ' + error.message); |
|
|
|
return false; |
|
|
|
} finally { |
|
|
|
isOperating = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -7554,7 +7714,6 @@ |
|
|
|
// 生成编辑城市选项 |
|
|
|
function generateEditCityOptions(cities) { |
|
|
|
const cityList = document.getElementById('editCityList'); |
|
|
|
const districtList = document.getElementById('editDistrictList'); |
|
|
|
|
|
|
|
cityList.innerHTML = ''; |
|
|
|
cities.forEach(city => { |
|
|
|
@ -7568,28 +7727,29 @@ |
|
|
|
editSelectedCity = city.city; |
|
|
|
updateEditRegionDisplay(); |
|
|
|
}; |
|
|
|
option.ondblclick = () => { |
|
|
|
// 双击城市直接确认整个地区选择 |
|
|
|
editSelectedCity = city.city; |
|
|
|
updateEditRegionDisplay(); |
|
|
|
// 构建完整的地区字符串 |
|
|
|
const regionString = `${editSelectedProvince} ${editSelectedCity}`; |
|
|
|
// 设置到表单 |
|
|
|
document.getElementById('editRegionDisplayText').textContent = regionString; |
|
|
|
document.getElementById('editRegionValue').value = regionString; |
|
|
|
// 隐藏弹窗 |
|
|
|
hideEditRegionSelectModal(); |
|
|
|
saveFormData(); // 保存选择 |
|
|
|
}; |
|
|
|
cityList.appendChild(option); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 生成编辑区县选项 |
|
|
|
function generateEditDistrictOptions(districts) { |
|
|
|
const districtList = document.getElementById('editDistrictList'); |
|
|
|
|
|
|
|
districtList.innerHTML = ''; |
|
|
|
districts.forEach(district => { |
|
|
|
const option = document.createElement('div'); |
|
|
|
option.className = 'select-item'; |
|
|
|
option.textContent = district; |
|
|
|
if (district === editSelectedDistrict) { |
|
|
|
option.classList.add('selected'); |
|
|
|
// 使用scrollIntoView滚动到第一个城市 |
|
|
|
setTimeout(() => { |
|
|
|
const firstCity = cityList.querySelector('.select-item'); |
|
|
|
if (firstCity) { |
|
|
|
firstCity.scrollIntoView({ behavior: 'auto', block: 'start' }); |
|
|
|
} |
|
|
|
option.onclick = () => { |
|
|
|
editSelectedDistrict = district; |
|
|
|
updateEditRegionDisplay(); |
|
|
|
}; |
|
|
|
districtList.appendChild(option); |
|
|
|
}); |
|
|
|
}, 50); |
|
|
|
} |
|
|
|
|
|
|
|
// 更新编辑地区显示 |
|
|
|
@ -7615,76 +7775,62 @@ |
|
|
|
editSelectedProvince = ''; |
|
|
|
editSelectedCity = ''; |
|
|
|
|
|
|
|
// 先尝试直接查找区县 |
|
|
|
let foundDistrict = false; |
|
|
|
for (let i = 0; i < allRegionOptions.length; i++) { |
|
|
|
const province = allRegionOptions[i]; |
|
|
|
for (let j = 0; j < province.cities.length; j++) { |
|
|
|
const city = province.cities[j]; |
|
|
|
for (let k = 0; k < city.districts.length; k++) { |
|
|
|
const district = city.districts[k]; |
|
|
|
if (district.toLowerCase().includes(searchKeyword)) { |
|
|
|
// 找到匹配的区县,自动填充省市区 |
|
|
|
editSelectedProvince = province.province; |
|
|
|
editSelectedCity = city.city; |
|
|
|
editSelectedDistrict = district; |
|
|
|
foundDistrict = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (foundDistrict) break; |
|
|
|
} |
|
|
|
if (foundDistrict) break; |
|
|
|
if (!searchKeyword) { |
|
|
|
// 如果搜索关键词为空,显示所有省份 |
|
|
|
generateEditRegionOptions(); |
|
|
|
updateEditRegionDisplay(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (foundDistrict) { |
|
|
|
// 生成地区选项并选择 |
|
|
|
generateEditRegionOptions(); |
|
|
|
// 过滤省份 |
|
|
|
const filteredProvinces = allRegionOptions.filter(province => { |
|
|
|
// 检查省份名称是否匹配 |
|
|
|
if (province.province.toLowerCase().includes(searchKeyword)) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
// 检查该省份下是否有匹配的城市 |
|
|
|
return province.cities.some(city => { |
|
|
|
return city.city.toLowerCase().includes(searchKeyword); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
// 自动生成城市选项并选择 |
|
|
|
const cityList = document.getElementById('editCityList'); |
|
|
|
cityList.innerHTML = ''; |
|
|
|
const province = allRegionOptions.find(p => p.province === editSelectedProvince); |
|
|
|
if (province) { |
|
|
|
province.cities.forEach(city => { |
|
|
|
// 生成省份选项 |
|
|
|
const provinceList = document.getElementById('editProvinceList'); |
|
|
|
provinceList.innerHTML = ''; |
|
|
|
filteredProvinces.forEach(province => { |
|
|
|
const option = document.createElement('div'); |
|
|
|
option.className = 'select-item'; |
|
|
|
option.textContent = city.city; |
|
|
|
if (city.city === editSelectedCity) { |
|
|
|
option.textContent = province.province; |
|
|
|
if (province.province === editSelectedProvince) { |
|
|
|
option.classList.add('selected'); |
|
|
|
} |
|
|
|
option.onclick = () => { |
|
|
|
editSelectedCity = city.city; |
|
|
|
editSelectedDistrict = ''; |
|
|
|
editSelectedProvince = province.province; |
|
|
|
editSelectedCity = ''; |
|
|
|
updateEditRegionDisplay(); |
|
|
|
generateEditDistrictOptions(city.districts); |
|
|
|
// 生成城市选项 |
|
|
|
generateEditCityOptions(province.cities); |
|
|
|
// 直接滚动城市列表到顶部 |
|
|
|
setTimeout(() => { |
|
|
|
document.getElementById('editCityList').scrollTop = 0; |
|
|
|
}, 100); |
|
|
|
}; |
|
|
|
cityList.appendChild(option); |
|
|
|
|
|
|
|
// 如果是选中的城市,生成区县选项 |
|
|
|
if (city.city === editSelectedCity) { |
|
|
|
generateEditDistrictOptions(city.districts); |
|
|
|
} |
|
|
|
provinceList.appendChild(option); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 更新区县选项的选中状态 |
|
|
|
const districtList = document.getElementById('editDistrictList'); |
|
|
|
const districtOptions = districtList.querySelectorAll('.select-item'); |
|
|
|
districtOptions.forEach(option => { |
|
|
|
if (option.textContent === editSelectedDistrict) { |
|
|
|
option.classList.add('selected'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// 否则按原逻辑生成所有省份 |
|
|
|
generateEditRegionOptions(); |
|
|
|
// 清空城市和区县选项 |
|
|
|
document.getElementById('editCityList').innerHTML = ''; |
|
|
|
document.getElementById('editDistrictList').innerHTML = ''; |
|
|
|
// 自动选择第一个匹配的省份和城市 |
|
|
|
if (filteredProvinces.length > 0) { |
|
|
|
editSelectedProvince = filteredProvinces[0].province; |
|
|
|
// 查找第一个匹配的城市 |
|
|
|
const matchedCity = filteredProvinces[0].cities.find(city => |
|
|
|
city.city.toLowerCase().includes(searchKeyword) |
|
|
|
); |
|
|
|
if (matchedCity) { |
|
|
|
editSelectedCity = matchedCity.city; |
|
|
|
} |
|
|
|
|
|
|
|
updateEditRegionDisplay(); |
|
|
|
generateEditCityOptions(filteredProvinces[0].cities); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 确认编辑地区选择 |
|
|
|
@ -7692,11 +7838,17 @@ |
|
|
|
if (editSelectedProvince && editSelectedCity) { |
|
|
|
const regionDisplayText = document.getElementById('editRegionDisplayText'); |
|
|
|
const regionValue = document.getElementById('editRegionValue'); |
|
|
|
const regionText = `${editSelectedProvince} ${editSelectedCity}`; |
|
|
|
let regionText = editSelectedProvince; |
|
|
|
if (editSelectedCity) { |
|
|
|
regionText = `${editSelectedProvince} ${editSelectedCity}`; |
|
|
|
} |
|
|
|
regionDisplayText.textContent = regionText; |
|
|
|
regionValue.value = regionText; |
|
|
|
} |
|
|
|
saveFormData(); // 保存选择 |
|
|
|
hideEditRegionSelectModal(); |
|
|
|
} else { |
|
|
|
alert('请选择完整的地区信息'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 编辑货源类型选择功能 |
|
|
|
@ -8078,12 +8230,27 @@ |
|
|
|
|
|
|
|
// 保存编辑货源 |
|
|
|
async function saveEditSupply() { |
|
|
|
// 防止重复点击 |
|
|
|
if (isOperating) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (!currentEditSupplyId) { |
|
|
|
alert('货源ID不存在'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 在编辑操作开始前就获取原始数据,并创建深拷贝,避免引用关系导致原始数据被修改 |
|
|
|
const originalSupplyTemp = supplyData.supplies.find(s => String(s.id) === String(currentEditSupplyId)); |
|
|
|
if (!originalSupplyTemp) { |
|
|
|
alert('找不到要编辑的货源数据'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
// 创建深拷贝,确保原始数据不会被后续操作修改 |
|
|
|
const originalSupply = JSON.parse(JSON.stringify(originalSupplyTemp)); |
|
|
|
|
|
|
|
try { |
|
|
|
isOperating = true; |
|
|
|
// 获取规格和件数数据 |
|
|
|
const pairs = document.querySelectorAll('#editSpecQuantityPairs .spec-quantity-pair'); |
|
|
|
const specifications = []; |
|
|
|
@ -8194,6 +8361,13 @@ |
|
|
|
|
|
|
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
|
|
// 记录编辑货源日志 |
|
|
|
const userInfo = checkLogin(); |
|
|
|
if (userInfo) { |
|
|
|
// 使用之前保存的原始数据(编辑前的数据) |
|
|
|
await logSupplyOperation('修改', currentEditSupplyId, originalSupply, result.data); |
|
|
|
} |
|
|
|
|
|
|
|
// 向WebSocket服务器发送消息,通知其他客户端货源已更新 |
|
|
|
sendWebSocketMessage({ |
|
|
|
type: 'supply_update', |
|
|
|
@ -8232,6 +8406,8 @@ |
|
|
|
console.error('编辑失败:', error); |
|
|
|
alert('编辑失败: 网络错误'); |
|
|
|
return false; |
|
|
|
} finally { |
|
|
|
isOperating = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|