|
|
@@ -0,0 +1,710 @@ |
|
|
|
<!DOCTYPE html> |
|
|
|
<html> |
|
|
|
|
|
|
|
<head> |
|
|
|
<title>Excel 编辑器</title> |
|
|
|
<style> |
|
|
|
body { |
|
|
|
margin: 0; |
|
|
|
padding: 0; |
|
|
|
font-family: Arial, sans-serif; |
|
|
|
font-size: 12px; |
|
|
|
background-color: #f0f0f0; |
|
|
|
color: #333; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
.container { |
|
|
|
max-width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.toolbar { |
|
|
|
position: sticky; |
|
|
|
top: 0; |
|
|
|
background: #fff; |
|
|
|
padding: 10px 0; |
|
|
|
margin-bottom: 15px; |
|
|
|
border-bottom: 1px solid #ddd; |
|
|
|
z-index: 100; |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
align-items: center; |
|
|
|
} |
|
|
|
|
|
|
|
.file-controls { |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.column-controls { |
|
|
|
margin-left: 20px; |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
flex-wrap: wrap; |
|
|
|
align-items: center; |
|
|
|
} |
|
|
|
|
|
|
|
.column-checkbox { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
gap: 4px; |
|
|
|
padding: 4px 8px; |
|
|
|
background: #f5f5f5; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.column-checkbox:hover { |
|
|
|
background: #e8e8e8; |
|
|
|
} |
|
|
|
|
|
|
|
button { |
|
|
|
padding: 6px 12px; |
|
|
|
background: #4CAF50; |
|
|
|
color: white; |
|
|
|
border: none; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
button:hover { |
|
|
|
background: #45a049; |
|
|
|
} |
|
|
|
|
|
|
|
input[type="file"] { |
|
|
|
padding: 6px; |
|
|
|
border: 1px solid #ddd; |
|
|
|
border-radius: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
table { |
|
|
|
border-collapse: collapse; |
|
|
|
width: 100%; |
|
|
|
background: white; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
th, |
|
|
|
td { |
|
|
|
border: 1px solid #ddd; |
|
|
|
padding: 0; |
|
|
|
vertical-align: top; |
|
|
|
} |
|
|
|
|
|
|
|
th { |
|
|
|
background: #f5f5f5; |
|
|
|
position: sticky; |
|
|
|
top: 60px; |
|
|
|
z-index: 90; |
|
|
|
} |
|
|
|
|
|
|
|
textarea { |
|
|
|
width: 100%; |
|
|
|
min-height: 100px; |
|
|
|
resize: vertical; |
|
|
|
padding: 0; |
|
|
|
border: 0; |
|
|
|
border-radius: 4px; |
|
|
|
font-size: 12px; |
|
|
|
box-sizing: border-box; |
|
|
|
} |
|
|
|
|
|
|
|
.index-column { |
|
|
|
width: 60px; |
|
|
|
text-align: center; |
|
|
|
background-color: #f5f5f5; |
|
|
|
position: sticky; |
|
|
|
left: 0; |
|
|
|
z-index: 80; |
|
|
|
} |
|
|
|
|
|
|
|
th.index-column { |
|
|
|
z-index: 91; |
|
|
|
} |
|
|
|
|
|
|
|
.image-upload-container { |
|
|
|
margin-top: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.preview-button { |
|
|
|
margin-top: 5px; |
|
|
|
background: #2196F3; |
|
|
|
} |
|
|
|
|
|
|
|
.preview-button:hover { |
|
|
|
background: #1976D2; |
|
|
|
} |
|
|
|
|
|
|
|
.preview-modal { |
|
|
|
display: none; |
|
|
|
position: fixed; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
background: rgba(0, 0, 0, 0.7); |
|
|
|
z-index: 1000; |
|
|
|
} |
|
|
|
|
|
|
|
.preview-content { |
|
|
|
position: relative; |
|
|
|
width: 80%; |
|
|
|
height: 80%; |
|
|
|
margin: 5% auto; |
|
|
|
background: white; |
|
|
|
padding: 20px; |
|
|
|
overflow: auto; |
|
|
|
border-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.close-preview { |
|
|
|
position: absolute; |
|
|
|
right: 20px; |
|
|
|
top: 10px; |
|
|
|
font-size: 24px; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.h5-preview-content { |
|
|
|
max-width: 375px; |
|
|
|
margin: 0 auto; |
|
|
|
background: #fff; |
|
|
|
} |
|
|
|
|
|
|
|
.h5-preview-content img { |
|
|
|
max-width: 100%; |
|
|
|
height: auto; |
|
|
|
} |
|
|
|
|
|
|
|
.hidden-column { |
|
|
|
display: none; |
|
|
|
} |
|
|
|
|
|
|
|
.quick-actions { |
|
|
|
margin-left: 20px; |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.help-button { |
|
|
|
background: #607D8B; |
|
|
|
color: white; |
|
|
|
border: none; |
|
|
|
border-radius: 50%; |
|
|
|
width: 24px; |
|
|
|
height: 24px; |
|
|
|
cursor: pointer; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
.help-modal { |
|
|
|
display: none; |
|
|
|
position: fixed; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
background: rgba(0, 0, 0, 0.7); |
|
|
|
z-index: 1000; |
|
|
|
} |
|
|
|
|
|
|
|
.help-content { |
|
|
|
position: relative; |
|
|
|
width: 60%; |
|
|
|
max-height: 80%; |
|
|
|
margin: 5% auto; |
|
|
|
background: white; |
|
|
|
padding: 20px; |
|
|
|
border-radius: 8px; |
|
|
|
overflow-y: auto; |
|
|
|
} |
|
|
|
|
|
|
|
.shortcut-key { |
|
|
|
background: #f0f0f0; |
|
|
|
padding: 2px 6px; |
|
|
|
border-radius: 3px; |
|
|
|
font-family: monospace; |
|
|
|
} |
|
|
|
|
|
|
|
.status-bar { |
|
|
|
position: fixed; |
|
|
|
bottom: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
background: #f5f5f5; |
|
|
|
padding: 8px 20px; |
|
|
|
border-top: 1px solid #ddd; |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
z-index: 100; |
|
|
|
} |
|
|
|
|
|
|
|
.unsaved-changes { |
|
|
|
color: #f44336; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
.save-reminder { |
|
|
|
position: fixed; |
|
|
|
bottom: 40px; |
|
|
|
right: 20px; |
|
|
|
background: #ff9800; |
|
|
|
color: white; |
|
|
|
padding: 10px 20px; |
|
|
|
border-radius: 4px; |
|
|
|
display: none; |
|
|
|
animation: bounce 1s infinite; |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes bounce { |
|
|
|
|
|
|
|
0%, |
|
|
|
100% { |
|
|
|
transform: translateY(0); |
|
|
|
} |
|
|
|
|
|
|
|
50% { |
|
|
|
transform: translateY(-5px); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.search-box { |
|
|
|
padding: 6px 12px; |
|
|
|
border: 1px solid #ddd; |
|
|
|
border-radius: 4px; |
|
|
|
margin-right: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.highlight { |
|
|
|
background-color: #fff176; |
|
|
|
} |
|
|
|
|
|
|
|
.column-preset { |
|
|
|
padding: 4px 8px; |
|
|
|
background: #e3f2fd; |
|
|
|
border: 1px solid #90caf9; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
margin-right: 10px; |
|
|
|
} |
|
|
|
</style> |
|
|
|
</head> |
|
|
|
|
|
|
|
<body> |
|
|
|
<div class="container"> |
|
|
|
<div class="toolbar"> |
|
|
|
<div class="file-controls"> |
|
|
|
<input type="file" id="fileInput" accept=".xlsx"> |
|
|
|
<button onclick="uploadFile()">上传</button> |
|
|
|
<button onclick="saveChanges()" id="saveButton">保存</button> |
|
|
|
<button class="help-button" onclick="showHelp()">?</button> |
|
|
|
</div> |
|
|
|
<div class="quick-actions"> |
|
|
|
<input type="text" class="search-box" placeholder="搜索内容..." onkeyup="searchContent(this.value)"> |
|
|
|
<button onclick="toggleCommonColumns()">常用列</button> |
|
|
|
<button onclick="toggleAllColumns()">显示/隐藏所有列</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
<div class="column-controls" id="columnControls"> |
|
|
|
<!-- 列控制复选框 --> |
|
|
|
</div> |
|
|
|
<div id="tableContainer"></div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 帮助模态框 --> |
|
|
|
<div id="helpModal" class="help-modal"> |
|
|
|
<div class="help-content"> |
|
|
|
<span class="close-preview" onclick="closeHelp()">×</span> |
|
|
|
<h2>使用帮助</h2> |
|
|
|
<h3>快捷键</h3> |
|
|
|
<ul> |
|
|
|
<li><span class="shortcut-key">Ctrl + S</span> - 保存更改</li> |
|
|
|
<li><span class="shortcut-key">Ctrl + F</span> - 搜索内容</li> |
|
|
|
<li><span class="shortcut-key">Tab</span> - 切换到下一个单元格</li> |
|
|
|
<li><span class="shortcut-key">Shift + Tab</span> - 切换到上一个单元格</li> |
|
|
|
</ul> |
|
|
|
<h3>常用功能</h3> |
|
|
|
<ul> |
|
|
|
<li>点击"常用列"可以快速显示常用编辑的列</li> |
|
|
|
<li>使用搜索框可以快速定位内容</li> |
|
|
|
<li>双击单元格可以快速编辑</li> |
|
|
|
<li>图片上传支持多选</li> |
|
|
|
</ul> |
|
|
|
<h3>注意事项</h3> |
|
|
|
<ul> |
|
|
|
<li>有未保存的更改时会有提醒</li> |
|
|
|
<li>建议定期保存更改</li> |
|
|
|
<li>图片上传完成后请等待提示再继续操作</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="status-bar"> |
|
|
|
<span id="statusText">就绪</span> |
|
|
|
<span id="unsavedChanges" class="unsaved-changes" style="display: none;">有未保存的更改</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div id="saveReminder" class="save-reminder"> |
|
|
|
请记得保存更改! |
|
|
|
</div> |
|
|
|
|
|
|
|
<div id="previewModal" class="preview-modal"> |
|
|
|
<div class="preview-content"> |
|
|
|
<span class="close-preview" onclick="closePreview()">×</span> |
|
|
|
<div id="previewContent"></div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.16.0.min.js"></script> |
|
|
|
<script> |
|
|
|
let headers = []; |
|
|
|
let data = []; |
|
|
|
let columnVisibility = {}; |
|
|
|
let hasUnsavedChanges = false; |
|
|
|
const commonColumns = ['SKU商品描述(PC)', 'SKU商品描述(h5)', 'SKU商品名称']; |
|
|
|
|
|
|
|
function initColumnControls() { |
|
|
|
const container = document.getElementById('columnControls'); |
|
|
|
container.innerHTML = headers.map(header => ` |
|
|
|
<label class="column-checkbox"> |
|
|
|
<input type="checkbox" |
|
|
|
checked |
|
|
|
onchange="toggleColumn('${header}')" |
|
|
|
data-column="${header}"> |
|
|
|
${header} |
|
|
|
</label> |
|
|
|
`).join(''); |
|
|
|
|
|
|
|
// 初始化列可见性状态 |
|
|
|
headers.forEach(header => { |
|
|
|
columnVisibility[header] = true; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function toggleColumn(header) { |
|
|
|
columnVisibility[header] = !columnVisibility[header]; |
|
|
|
const cells = document.querySelectorAll(`[data-column="${header}"]`); |
|
|
|
cells.forEach(cell => { |
|
|
|
if (cell.tagName === 'INPUT') { |
|
|
|
// 复选框状态 |
|
|
|
cell.checked = columnVisibility[header]; |
|
|
|
} else { |
|
|
|
// 表格单元格 |
|
|
|
cell.classList.toggle('hidden-column'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function renderTable() { |
|
|
|
const container = document.getElementById('tableContainer'); |
|
|
|
let html = '<table><tr>'; |
|
|
|
|
|
|
|
html += '<th class="index-column">序号</th>'; |
|
|
|
headers.forEach(header => { |
|
|
|
html += `<th data-column="${header}" ${!columnVisibility[header] ? 'class="hidden-column"' : ''}>${header}</th>`; |
|
|
|
}); |
|
|
|
html += '</tr>'; |
|
|
|
|
|
|
|
data.forEach((row, rowIndex) => { |
|
|
|
html += '<tr>'; |
|
|
|
html += `<td class="index-column">${rowIndex + 1}</td>`; |
|
|
|
headers.forEach(header => { |
|
|
|
html += `<td data-column="${header}" ${!columnVisibility[header] ? 'class="hidden-column"' : ''}> |
|
|
|
<textarea |
|
|
|
data-row="${rowIndex}" |
|
|
|
data-header="${header}" |
|
|
|
onchange="updateData(${rowIndex}, '${header}', this.value)" |
|
|
|
>${row[header] || ''}</textarea> |
|
|
|
${header === 'SKU商品描述(PC)' ? ` |
|
|
|
<div class="image-upload-container"> |
|
|
|
<input type="file" accept="image/*" |
|
|
|
onchange="uploadImage(this, ${rowIndex}, '${header}')" multiple> |
|
|
|
</div> |
|
|
|
<button class="preview-button" onclick="previewContent(${rowIndex}, '${header}', 'pc')"> |
|
|
|
预览 |
|
|
|
</button> |
|
|
|
` : ''} |
|
|
|
${header === 'SKU商品描述(h5)' ? ` |
|
|
|
<button class="preview-button" onclick="previewContent(${rowIndex}, '${header}', 'h5')"> |
|
|
|
预览 |
|
|
|
</button> |
|
|
|
` : ''} |
|
|
|
</td>`; |
|
|
|
}); |
|
|
|
html += '</tr>'; |
|
|
|
}); |
|
|
|
|
|
|
|
html += '</table>'; |
|
|
|
container.innerHTML = html; |
|
|
|
} |
|
|
|
|
|
|
|
async function uploadFile() { |
|
|
|
const fileInput = document.getElementById('fileInput'); |
|
|
|
const file = fileInput.files[0]; |
|
|
|
if (!file) return; |
|
|
|
|
|
|
|
const formData = new FormData(); |
|
|
|
formData.append('excelFile', file); |
|
|
|
|
|
|
|
const response = await fetch('/upload', { |
|
|
|
method: 'POST', |
|
|
|
body: formData |
|
|
|
}); |
|
|
|
const result = await response.json(); |
|
|
|
|
|
|
|
headers = result.headers; |
|
|
|
data = result.data; |
|
|
|
|
|
|
|
// 初始化列控制 |
|
|
|
initColumnControls(); |
|
|
|
renderTable(); |
|
|
|
} |
|
|
|
|
|
|
|
function updateData(rowIndex, header, value) { |
|
|
|
data[rowIndex][header] = value; |
|
|
|
hasUnsavedChanges = true; |
|
|
|
document.getElementById('unsavedChanges').style.display = 'block'; |
|
|
|
document.getElementById('saveReminder').style.display = 'block'; |
|
|
|
updateStatus('有未保存的更改'); |
|
|
|
} |
|
|
|
|
|
|
|
async function saveChanges() { |
|
|
|
updateStatus('正在保存...'); |
|
|
|
try { |
|
|
|
const response = await fetch('/save', { |
|
|
|
method: 'POST', |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json' |
|
|
|
}, |
|
|
|
body: JSON.stringify({ headers, data }) |
|
|
|
}); |
|
|
|
|
|
|
|
const result = await response.json(); |
|
|
|
|
|
|
|
if (!response.ok) { |
|
|
|
if (result.message) { |
|
|
|
alert(result.message); |
|
|
|
} else { |
|
|
|
alert('保存失败:' + (result.error || '未知错误')); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
window.location.href = result.downloadUrl; |
|
|
|
hasUnsavedChanges = false; |
|
|
|
document.getElementById('unsavedChanges').style.display = 'none'; |
|
|
|
document.getElementById('saveReminder').style.display = 'none'; |
|
|
|
updateStatus('保存成功'); |
|
|
|
} catch (error) { |
|
|
|
updateStatus('保存失败:' + error.message); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async function uploadImage(input, rowIndex, header) { |
|
|
|
const files = input.files; |
|
|
|
if (!files.length) return; |
|
|
|
|
|
|
|
try { |
|
|
|
updateStatus('正在上传图片...'); |
|
|
|
|
|
|
|
const formData = new FormData(); |
|
|
|
Array.from(files).forEach(file => { |
|
|
|
formData.append('images', file); |
|
|
|
}); |
|
|
|
|
|
|
|
const response = await fetch('/upload-images', { |
|
|
|
method: 'POST', |
|
|
|
body: formData |
|
|
|
}); |
|
|
|
|
|
|
|
if (!response.ok) { |
|
|
|
throw new Error('上传失败'); |
|
|
|
} |
|
|
|
|
|
|
|
const results = await response.json(); |
|
|
|
|
|
|
|
// 生成PC描述HTML |
|
|
|
const pcImageHtml = results.map(result => |
|
|
|
`<p><img src="${result.url}" title="${result.name}"></p>` |
|
|
|
).join('\n'); |
|
|
|
|
|
|
|
// 生成H5描述JSON |
|
|
|
const h5ImageJson = results.map(result => ({ |
|
|
|
type: "image", |
|
|
|
content: result.url, |
|
|
|
checked: false, |
|
|
|
edit_checked: false |
|
|
|
})); |
|
|
|
|
|
|
|
// 更新PC描述 |
|
|
|
const pcTextarea = input.parentElement.previousElementSibling; |
|
|
|
const currentPcValue = pcTextarea.value || ''; |
|
|
|
pcTextarea.value = currentPcValue + (currentPcValue ? '\n' : '') + pcImageHtml; |
|
|
|
updateData(rowIndex, header, pcTextarea.value); |
|
|
|
|
|
|
|
// 更新H5描述 |
|
|
|
const h5Header = 'SKU商品描述(h5)'; |
|
|
|
const currentH5Value = data[rowIndex][h5Header] || '[]'; |
|
|
|
let h5Data; |
|
|
|
try { |
|
|
|
h5Data = JSON.parse(currentH5Value); |
|
|
|
if (!Array.isArray(h5Data)) h5Data = []; |
|
|
|
} catch { |
|
|
|
h5Data = []; |
|
|
|
} |
|
|
|
|
|
|
|
// 合并新的图片数据 |
|
|
|
h5Data.push(...h5ImageJson); |
|
|
|
|
|
|
|
// 更新H5数据 |
|
|
|
const h5Value = JSON.stringify(h5Data); |
|
|
|
updateData(rowIndex, h5Header, h5Value); |
|
|
|
|
|
|
|
// 更新表格显示 |
|
|
|
const h5Textarea = document.querySelector(`textarea[data-row="${rowIndex}"][data-header="${h5Header}"]`); |
|
|
|
if (h5Textarea) { |
|
|
|
h5Textarea.value = h5Value; |
|
|
|
} |
|
|
|
|
|
|
|
// 清空文件输入框 |
|
|
|
input.value = ''; |
|
|
|
|
|
|
|
updateStatus('图片上传成功'); |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error('Upload error:', error); |
|
|
|
alert('上传图片失败:' + error.message); |
|
|
|
updateStatus('图片上传失败'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function previewContent(rowIndex, header, type) { |
|
|
|
const content = data[rowIndex][header] || ''; |
|
|
|
const modal = document.getElementById('previewModal'); |
|
|
|
const previewContent = document.getElementById('previewContent'); |
|
|
|
|
|
|
|
if (type === 'pc') { |
|
|
|
// PC预览直接显示HTML |
|
|
|
previewContent.innerHTML = content; |
|
|
|
} else if (type === 'h5') { |
|
|
|
// H5预览需要解析JSON并生成预览内容 |
|
|
|
try { |
|
|
|
const h5Data = JSON.parse(content); |
|
|
|
const h5Html = ` |
|
|
|
<div class="h5-preview-content"> |
|
|
|
${h5Data.map(item => { |
|
|
|
if (item.type === 'image') { |
|
|
|
return `<img src="${item.content}" alt="">`; |
|
|
|
} |
|
|
|
return ''; |
|
|
|
}).join('')} |
|
|
|
</div> |
|
|
|
`; |
|
|
|
previewContent.innerHTML = h5Html; |
|
|
|
} catch (error) { |
|
|
|
previewContent.innerHTML = '预览失败:无效的JSON格式'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
modal.style.display = 'block'; |
|
|
|
} |
|
|
|
|
|
|
|
function closePreview() { |
|
|
|
document.getElementById('previewModal').style.display = 'none'; |
|
|
|
} |
|
|
|
|
|
|
|
// 点击模态框背景关闭预览 |
|
|
|
document.getElementById('previewModal').addEventListener('click', function (e) { |
|
|
|
if (e.target === this) { |
|
|
|
closePreview(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 添加快捷键支持 |
|
|
|
document.addEventListener('keydown', function (e) { |
|
|
|
if (e.ctrlKey && e.key === 's') { |
|
|
|
e.preventDefault(); |
|
|
|
saveChanges(); |
|
|
|
} |
|
|
|
if (e.ctrlKey && e.key === 'f') { |
|
|
|
e.preventDefault(); |
|
|
|
document.querySelector('.search-box').focus(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 搜索功能 |
|
|
|
function searchContent(searchText) { |
|
|
|
if (!searchText) { |
|
|
|
clearHighlights(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const textareas = document.querySelectorAll('textarea'); |
|
|
|
textareas.forEach(textarea => { |
|
|
|
const content = textarea.value.toLowerCase(); |
|
|
|
if (content.includes(searchText.toLowerCase())) { |
|
|
|
textarea.classList.add('highlight'); |
|
|
|
textarea.parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); |
|
|
|
} else { |
|
|
|
textarea.classList.remove('highlight'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function clearHighlights() { |
|
|
|
document.querySelectorAll('.highlight').forEach(el => { |
|
|
|
el.classList.remove('highlight'); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 常用列切换 |
|
|
|
function toggleCommonColumns() { |
|
|
|
headers.forEach(header => { |
|
|
|
const isCommon = commonColumns.includes(header); |
|
|
|
columnVisibility[header] = isCommon; |
|
|
|
const checkbox = document.querySelector(`input[data-column="${header}"]`); |
|
|
|
if (checkbox) { |
|
|
|
checkbox.checked = isCommon; |
|
|
|
} |
|
|
|
}); |
|
|
|
renderTable(); |
|
|
|
} |
|
|
|
|
|
|
|
// 全部列切换 |
|
|
|
function toggleAllColumns() { |
|
|
|
const allVisible = headers.every(header => columnVisibility[header]); |
|
|
|
headers.forEach(header => { |
|
|
|
columnVisibility[header] = !allVisible; |
|
|
|
const checkbox = document.querySelector(`input[data-column="${header}"]`); |
|
|
|
if (checkbox) { |
|
|
|
checkbox.checked = !allVisible; |
|
|
|
} |
|
|
|
}); |
|
|
|
renderTable(); |
|
|
|
} |
|
|
|
|
|
|
|
function updateStatus(text) { |
|
|
|
document.getElementById('statusText').textContent = text; |
|
|
|
} |
|
|
|
|
|
|
|
// 帮助功能 |
|
|
|
function showHelp() { |
|
|
|
document.getElementById('helpModal').style.display = 'block'; |
|
|
|
} |
|
|
|
|
|
|
|
function closeHelp() { |
|
|
|
document.getElementById('helpModal').style.display = 'none'; |
|
|
|
} |
|
|
|
|
|
|
|
// 离开页面提醒 |
|
|
|
window.addEventListener('beforeunload', function (e) { |
|
|
|
if (hasUnsavedChanges) { |
|
|
|
e.preventDefault(); |
|
|
|
e.returnValue = '有未保存的更改,确定要离开吗?'; |
|
|
|
} |
|
|
|
}); |
|
|
|
</script> |
|
|
|
</body> |
|
|
|
|
|
|
|
</html> |