298 lines
5.3 KiB
HTML
298 lines
5.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>主子表分页编辑 Demo</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial;
|
|
padding: 20px;
|
|
background: #f5f6f8;
|
|
}
|
|
|
|
.container {
|
|
background: #fff;
|
|
padding: 16px;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
h2 {
|
|
margin: 10px 0;
|
|
}
|
|
|
|
/* 主表 */
|
|
.form-row {
|
|
display: flex;
|
|
gap: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
input {
|
|
padding: 6px;
|
|
flex: 1;
|
|
}
|
|
|
|
/* 表格 */
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
th, td {
|
|
border: 1px solid #ddd;
|
|
padding: 6px;
|
|
text-align: left;
|
|
}
|
|
|
|
td input {
|
|
width: 100%;
|
|
border: none;
|
|
outline: none;
|
|
}
|
|
|
|
/* 分页 */
|
|
.pager {
|
|
margin-top: 10px;
|
|
display: flex;
|
|
gap: 10px;
|
|
align-items: center;
|
|
}
|
|
|
|
button {
|
|
padding: 5px 10px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.tag {
|
|
font-size: 12px;
|
|
padding: 2px 6px;
|
|
background: #ffecb3;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.deleted {
|
|
background: #ffe5e5;
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
.toolbar {
|
|
margin-top: 10px;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container">
|
|
|
|
<h2>主表</h2>
|
|
<div class="form-row">
|
|
<input id="mainName" placeholder="主表名称" />
|
|
<input id="mainCode" placeholder="主表编码" />
|
|
</div>
|
|
|
|
<h2>子表(分页编辑)</h2>
|
|
|
|
<div class="toolbar">
|
|
<button onclick="addRow()">新增行</button>
|
|
<button onclick="submitAll()">提交全部</button>
|
|
</div>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>名称</th>
|
|
<th>数量</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tbody"></tbody>
|
|
</table>
|
|
|
|
<div class="pager">
|
|
<button onclick="prevPage()">上一页</button>
|
|
<span id="pageInfo"></span>
|
|
<button onclick="nextPage()">下一页</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
/**
|
|
* =========================
|
|
* 模拟后端数据
|
|
* =========================
|
|
*/
|
|
const serverData = [];
|
|
for (let i = 1; i <= 50; i++) {
|
|
serverData.push({
|
|
id: i,
|
|
name: "物料-" + i,
|
|
qty: Math.floor(Math.random() * 100)
|
|
});
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 核心状态
|
|
* =========================
|
|
*/
|
|
let page = 1;
|
|
const pageSize = 5;
|
|
|
|
// ⭐ 子表缓存(核心)
|
|
const cache = new Map();
|
|
|
|
/**
|
|
* =========================
|
|
* 拉取数据(模拟分页接口)
|
|
* =========================
|
|
*/
|
|
function fetchPageData(page) {
|
|
const start = (page - 1) * pageSize;
|
|
const list = serverData.slice(start, start + pageSize);
|
|
|
|
return list.map(item => {
|
|
const cached = cache.get(item.id);
|
|
return cached ? { ...item, ...cached } : item;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 渲染表格
|
|
* =========================
|
|
*/
|
|
function render() {
|
|
const data = fetchPageData(page);
|
|
const tbody = document.getElementById("tbody");
|
|
|
|
tbody.innerHTML = "";
|
|
|
|
data.forEach(row => {
|
|
if (row._deleted) return;
|
|
|
|
const tr = document.createElement("tr");
|
|
|
|
if (row.isNew) tr.classList.add("deleted");
|
|
|
|
tr.innerHTML = `
|
|
<td>${row.id}</td>
|
|
<td>
|
|
<input value="${row.name || ""}"
|
|
onchange="onEdit(${row.id}, 'name', this.value)" />
|
|
</td>
|
|
<td>
|
|
<input value="${row.qty || 0}"
|
|
onchange="onEdit(${row.id}, 'qty', this.value)" />
|
|
</td>
|
|
<td>
|
|
${row.isNew ? '<span class="tag">新增</span>' : ''}
|
|
<button onclick="removeRow(${row.id})">删除</button>
|
|
</td>
|
|
`;
|
|
|
|
tbody.appendChild(tr);
|
|
});
|
|
|
|
document.getElementById("pageInfo").innerText =
|
|
`第 ${page} / ${Math.ceil(serverData.length / pageSize)} 页`;
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 编辑缓存
|
|
* =========================
|
|
*/
|
|
function onEdit(id, field, value) {
|
|
const old = cache.get(id) || { id };
|
|
const updated = { ...old, [field]: value, isDirty: true };
|
|
cache.set(id, updated);
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 新增
|
|
* =========================
|
|
*/
|
|
function addRow() {
|
|
const tempId = "tmp_" + Date.now();
|
|
|
|
const newRow = {
|
|
id: tempId,
|
|
name: "",
|
|
qty: 0,
|
|
isNew: true
|
|
};
|
|
|
|
cache.set(tempId, newRow);
|
|
serverData.unshift(newRow); // 模拟插入数据源
|
|
render();
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 删除(逻辑删除)
|
|
* =========================
|
|
*/
|
|
function removeRow(id) {
|
|
const row = cache.get(id) || { id };
|
|
cache.set(id, { ...row, _deleted: true });
|
|
render();
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 分页
|
|
* =========================
|
|
*/
|
|
function prevPage() {
|
|
if (page > 1) {
|
|
page--;
|
|
render();
|
|
}
|
|
}
|
|
|
|
function nextPage() {
|
|
if (page < Math.ceil(serverData.length / pageSize)) {
|
|
page++;
|
|
render();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* =========================
|
|
* 提交全部(核心)
|
|
* =========================
|
|
*/
|
|
function submitAll() {
|
|
const all = Array.from(cache.values());
|
|
|
|
const inserted = all.filter(i => i.isNew);
|
|
const updated = all.filter(i => i.isDirty && !i.isNew);
|
|
const deleted = all.filter(i => i._deleted);
|
|
|
|
console.log("主表:", {
|
|
name: document.getElementById("mainName").value,
|
|
code: document.getElementById("mainCode").value
|
|
});
|
|
|
|
console.log("新增:", inserted);
|
|
console.log("修改:", updated);
|
|
console.log("删除:", deleted);
|
|
|
|
alert("数据已输出到控制台(F12查看)");
|
|
}
|
|
|
|
/**
|
|
* init
|
|
*/
|
|
render();
|
|
</script>
|
|
|
|
</body>
|
|
</html> |