<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<title>手机采集记录表</title>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<style>
*{box-sizing:border-box;margin:0;padding:0;font-family:system-ui,-apple-system,sans-serif;}
body{padding:12px;background:#f4f6f8;}
.wrap{background:#fff;padding:14px;border-radius:10px;box-shadow:0 1px 5px #00000015;}
.btns{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px;}
button{
flex:1;
min-width:72px;
padding:11px 4px;
font-size:14px;
border:none;
border-radius:8px;
background:#2b7bcc;
color:#fff;
}
button:active{background:#1f63a8;}
#tableArea{overflow-x:auto;}
table{
border-collapse:collapse;
width:100%;
min-width:360px;
}
th,td{
border:1px solid #aaa;
padding:14px 6px;
text-align:center;
font-size:15px;
min-width:95px;
}
.th-time{background:#c2d1e0;color:#222;}
.th-dynamic{background:#d0dfee;color:#222;}
.th-hand{background:#e2f1ff;color:#222;}
.date-row th{
background:#f0f4f8;
font-size:16px;
padding:12px;
}
td{background:#ffffff;}
/*附属备注通栏矮行 */
.sub-note td{
background:#f3f5f7 !important;
padding:7px 10px !important;
min-height:36px;
text-align:left;
white-space:pre-wrap;
word-break:break-all;
}
.del-cell{
width:36px;
min-width:36px;
padding:4px;
background:#fff;
}
.del-btn{
border:none;
background:#ee6666;
color:white;
border-radius:4px;
width:26px;
height:26px;
font-size:16px;
line-height:1;
padding:0;
}
td[contenteditable],th[contenteditable]{cursor:text;}
.tip{font-size:12px;color:#666;margin:8px 0 4px;}
</style>
</head>
<body>
<div class="wrap">
<div class="tip">✓内容自动保存在本机,关闭页面不会丢失</div>
<div class="btns">
<button onclick="addRecordRow()">新增记录行</button>
<button onclick="addSubNote()">新增备注行</button>
<button onclick="clearAllData()">清空全部</button>
<button onclick="exportImage()">导出PNG图片</button>
</div>
<div id="tableArea">
<table>
<thead>
<tr class="date-row">
<th colspan="4" contenteditable="true" id="top-date">日期</th>
</tr>
<tr>
<th class="th-time">时间</th>
<th class="th-dynamic" contenteditable="true" id="h-dynamic">动态</th>
<th class="th-hand">手采</th>
<th style="width:36px;"></th>
</tr>
</thead>
<tbody id="tbody">
<tr class="data-row">
<td contenteditable="true"></td>
<td contenteditable="true"></td>
<td contenteditable="true"></td>
<td class="del-cell"><button class="del-btn" onclick="deleteRow(this)">×</button></td>
</tr>
</tbody>
</table>
</div>
</div>
<script>
const STORAGE_KEY = "collect_table_data";
function loadData(){
let str = localStorage.getItem(STORAGE_KEY);
if(!str) return;
let data = JSON.parse(str);
document.getElementById("top-date").innerText = data.topDate;
document.getElementById("h-dynamic").innerText = data.head.dynamic;
const tbody = document.getElementById("tbody");
tbody.innerHTML = "";
data.items.forEach(item=>{
if(item.type === "record"){
const tr = document.createElement("tr");
tr.className = "data-row";
tr.innerHTML = `<td contenteditable="true">${item.t}</td><td contenteditable="true">${item.dy}</td><td contenteditable="true">${item.h}</td><td class="del-cell"><button class="del-btn" onclick="deleteRow(this)">×</button></td>`;
tbody.appendChild(tr);
}else if(item.type === "subnote"){
const tr = document.createElement("tr");
tr.className = "sub-note";
tr.innerHTML = `<td colspan="3" contenteditable="true">${item.txt}</td><td class="del-cell"><button class="del-btn" onclick="deleteRow(this)">×</button></td>`;
tbody.appendChild(tr);
}
})
}
function saveData(){
const topDate = document.getElementById("top-date").innerText;
const hdynamic = document.getElementById("h-dynamic").innerText;
const rows = document.querySelectorAll("#tbody > tr");
const items = [];
rows.forEach(r=>{
if(r.classList.contains("data-row")){
const cells = r.querySelectorAll("td");
items.push({
type:"record",
t:cells[0].innerText,
dy:cells[1].innerText,
h:cells[2].innerText
})
}else if(r.classList.contains("sub-note")){
const cell = r.querySelector("td[colspan]");
items.push({
type:"subnote",
txt:cell.innerText
})
}
})
const saveObj = {topDate:topDate,head:{dynamic:hdynamic},items:items};
localStorage.setItem(STORAGE_KEY,JSON.stringify(saveObj));
}
document.addEventListener("input",e=>{
if(e.target.isContentEditable){
saveData();
}
})
function deleteRow(btn){
const tr = btn.closest("tr");
tr.remove();
saveData();
}
function addRecordRow(){
const tbody = document.getElementById("tbody");
const tr = document.createElement("tr");
tr.className = "data-row";
tr.innerHTML = `<td contenteditable="true"></td><td contenteditable="true"></td><td contenteditable="true"></td><td class="del-cell"><button class="del-btn" onclick="deleteRow(this)">×</button></td>`;
tbody.appendChild(tr);
saveData();
}
function addSubNote(){
const tbody = document.getElementById("tbody");
const tr = document.createElement("tr");
tr.className = "sub-note";
tr.innerHTML = `<td colspan="3" contenteditable="true"></td><td class="del-cell"><button class="del-btn" onclick="deleteRow(this)">×</button></td>`;
tbody.appendChild(tr);
saveData();
}
function clearAllData(){
if(!confirm("确定清空所有填写内容?该操作不可恢复"))return;
const tbody = document.getElementById("tbody");
tbody.innerHTML = `
<tr class="data-row">
<td contenteditable="true"></td>
<td contenteditable="true"></td>
<td contenteditable="true"></td>
<td class="del-cell"><button class="del-btn" onclick="deleteRow(this)">×</button></td>
</tr>
`;
document.getElementById("top-date").innerText="日期";
document.getElementById("h-dynamic").innerText="动态";
saveData();
}
async function exportImage(){
const dom = document.getElementById("tableArea");
const canvas = await html2canvas(dom,{
backgroundColor:"#ffffff",
scale:2.2
});
const link = document.createElement("a");
link.download = "采集记录表.png";
link.href = canvas.toDataURL("image/png");
link.click();
}
window.onload = loadData;
</script>
</body>
</html>