Files
2026-05-06 21:38:45 +08:00

220 lines
4.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>ERP账单 - 方案4 Demo(diff提交 + 新增末尾)</title>
<style>
body { font-family: Arial; margin: 20px; }
table { border-collapse: collapse; width: 100%; margin-top: 10px; }
th, td { border: 1px solid #ddd; padding: 6px; text-align: left; }
th { background: #f5f5f5; }
input { width: 100%; box-sizing: border-box; }
button { margin: 5px; }
.toolbar { margin-bottom: 10px; }
.badge { padding: 2px 6px; background: orange; color: white; border-radius: 4px; }
</style>
</head>
<body>
<h2>账单明细(方案4:分页 + diff提交)</h2>
<div class="toolbar">
<button onclick="prevPage()">上一页</button>
<button onclick="nextPage()">下一页</button>
<button onclick="addRow()">新增费用</button>
<button onclick="submit()">提交(只提交diff)</button>
<span id="pageInfo"></span>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>费用名称</th>
<th>金额</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
<h3>Diff 输出:</h3>
<pre id="output"></pre>
<script>
// ===============================
// 模拟后端数据(200条)
// ===============================
let serverData = Array.from({length: 200}, (_, i) => ({
id: i + 1,
name: "费用-" + (i + 1),
amount: Math.floor(Math.random() * 1000)
}));
// ===============================
// 分页参数
// ===============================
let page = 1;
let pageSize = 10;
// ===============================
// diff结构(核心)
// ===============================
const state = {
originalMap: new Map(),
updated: new Map(),
created: [],
deleted: new Set()
};
// ===============================
// 模拟分页接口
// ===============================
function fetchPage(page, size) {
const start = (page - 1) * size;
const end = start + size;
return serverData.slice(start, end);
}
// ===============================
// 渲染
// ===============================
function render() {
const data = fetchPage(page, pageSize);
const tbody = document.getElementById("tbody");
tbody.innerHTML = "";
state.originalMap.clear();
data.forEach(row => {
state.originalMap.set(row.id, JSON.parse(JSON.stringify(row)));
if (state.deleted.has(row.id)) return;
const tr = document.createElement("tr");
tr.innerHTML = `
<td>${row.id}</td>
<td><input value="${row.name}" onchange="edit(${row.id}, 'name', this.value)"></td>
<td><input value="${row.amount}" onchange="edit(${row.id}, 'amount', this.value)"></td>
<td>
<button onclick="del(${row.id})">删除</button>
${state.updated.has(row.id) ? '<span class="badge">已修改</span>' : ''}
</td>
`;
tbody.appendChild(tr);
});
document.getElementById("pageInfo").innerText =
`第 ${page} 页 / 共 ${Math.ceil(serverData.length / pageSize)} 页`;
}
// ===============================
// 编辑(diff核心)
// ===============================
function edit(id, field, value) {
const original = state.originalMap.get(id);
if (!original) return;
let current = state.updated.get(id);
if (!current) {
current = {...original};
}
current[field] = field === "amount" ? Number(value) : value;
state.updated.set(id, current);
}
// ===============================
// 删除
// ===============================
function del(id) {
state.deleted.add(id);
state.updated.delete(id);
render();
}
// ===============================
// 新增(关键修复:追加到末尾 + 跳最后页)
// ===============================
function addRow() {
const newId = Date.now();
const row = {
id: newId,
name: "新费用",
amount: 0
};
// ✅ 追加到末尾(ERP标准:append-only)
serverData.push(row);
// 记录create diff
state.created.push(row);
// ✅ 自动跳转到最后一页
page = Math.ceil(serverData.length / pageSize);
render();
}
// ===============================
// 分页
// ===============================
function nextPage() {
if (page * pageSize < serverData.length) {
page++;
render();
}
}
function prevPage() {
if (page > 1) {
page--;
render();
}
}
// ===============================
// 提交 diff(核心)
// ===============================
function submit() {
const patch = {
create: state.created,
update: [],
delete: Array.from(state.deleted)
};
// 计算update diff
state.updated.forEach((newVal, id) => {
const oldVal = state.originalMap.get(id);
if (!oldVal) return;
if (
oldVal.name !== newVal.name ||
oldVal.amount !== newVal.amount
) {
patch.update.push(newVal);
}
});
document.getElementById("output").innerText =
JSON.stringify(patch, null, 2);
console.log("提交patch:", patch);
alert("已生成diff,请查看下方JSON或控制台");
}
// 初始渲染
render();
</script>
</body>
</html>