feat: add dynamic report item rows
This commit is contained in:
parent
5434d1b283
commit
ab2f3dc093
@ -61,10 +61,53 @@ button {
|
||||
gap: 8px;
|
||||
}
|
||||
.item-group h2 { margin: 0; }
|
||||
.item-group-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.item-group [data-list] {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
.item-row {
|
||||
display: grid;
|
||||
grid-template-columns: 32px minmax(0, 1fr) 36px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
.item-index {
|
||||
color: #5b6472;
|
||||
text-align: right;
|
||||
}
|
||||
.add-item, .remove-item {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.add-item {
|
||||
border: 1px solid #2563eb;
|
||||
background: #fff;
|
||||
color: #2563eb;
|
||||
font-size: 22px;
|
||||
line-height: 1;
|
||||
}
|
||||
.remove-item {
|
||||
border: 1px solid #e5e7eb;
|
||||
background: #fff;
|
||||
color: #6b7280;
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
}
|
||||
.remove-item:hover {
|
||||
border-color: #fecaca;
|
||||
color: #b91c1c;
|
||||
background: #fef2f2;
|
||||
}
|
||||
.previous-plan {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
|
||||
@ -71,22 +71,18 @@ def submit_page(current_date: str, session: dict[str, str] | None = None) -> byt
|
||||
<label><input type="radio" name="report_status" value="need_help"> 需要支持</label>
|
||||
</fieldset>
|
||||
<section class="item-group">
|
||||
<h2>今日完成</h2>
|
||||
<div data-list="today_done">
|
||||
<input placeholder="1.">
|
||||
<input placeholder="2.">
|
||||
<input placeholder="3.">
|
||||
<input placeholder="4.">
|
||||
<div class="item-group-head">
|
||||
<h2>今日完成</h2>
|
||||
<button class="add-item" type="button" data-add-list="today_done" aria-label="添加今日完成">+</button>
|
||||
</div>
|
||||
<div data-list="today_done"></div>
|
||||
</section>
|
||||
<section class="item-group">
|
||||
<h2>明日计划</h2>
|
||||
<div data-list="tomorrow_plan">
|
||||
<input placeholder="1.">
|
||||
<input placeholder="2.">
|
||||
<input placeholder="3.">
|
||||
<input placeholder="4.">
|
||||
<div class="item-group-head">
|
||||
<h2>明日计划</h2>
|
||||
<button class="add-item" type="button" data-add-list="tomorrow_plan" aria-label="添加明日计划">+</button>
|
||||
</div>
|
||||
<div data-list="tomorrow_plan"></div>
|
||||
</section>
|
||||
<label>遇到的问题<textarea name="blockers" rows="3" placeholder="没有可以不填"></textarea></label>
|
||||
<label>需要协助<textarea name="help_needed" rows="3" placeholder="没有可以不填"></textarea></label>
|
||||
@ -136,15 +132,47 @@ function collectItems(name) {{
|
||||
return values.map((value, index) => `${{index + 1}}. ${{value}}`).join("\\n");
|
||||
}}
|
||||
|
||||
function renumberItems(name) {{
|
||||
Array.from(document.querySelectorAll(`[data-list="${{name}}"] .item-row`)).forEach((row, index) => {{
|
||||
row.querySelector(".item-index").textContent = `${{index + 1}}.`;
|
||||
row.querySelector("input").placeholder = `第 ${{index + 1}} 条`;
|
||||
}});
|
||||
}}
|
||||
|
||||
function addItem(name, value = "") {{
|
||||
const list = document.querySelector(`[data-list="${{name}}"]`);
|
||||
const row = document.createElement("div");
|
||||
row.className = "item-row";
|
||||
row.innerHTML = `
|
||||
<span class="item-index"></span>
|
||||
<input value="${{escapeHtml(value)}}" autocomplete="off">
|
||||
<button class="remove-item" type="button" aria-label="删除这一条">×</button>
|
||||
`;
|
||||
row.querySelector(".remove-item").addEventListener("click", () => {{
|
||||
if (list.querySelectorAll(".item-row").length <= 1) {{
|
||||
row.querySelector("input").value = "";
|
||||
return;
|
||||
}}
|
||||
row.remove();
|
||||
renumberItems(name);
|
||||
}});
|
||||
list.appendChild(row);
|
||||
renumberItems(name);
|
||||
}}
|
||||
|
||||
function resetItems(name, values = []) {{
|
||||
const list = document.querySelector(`[data-list="${{name}}"]`);
|
||||
list.innerHTML = "";
|
||||
const items = values.length ? values : ["", "", ""];
|
||||
items.forEach((value) => addItem(name, value));
|
||||
}}
|
||||
|
||||
function fillItemInputs(name, text) {{
|
||||
const inputs = Array.from(document.querySelectorAll(`[data-list="${{name}}"] input`));
|
||||
const lines = String(text || "")
|
||||
.split(/\\n+/)
|
||||
.map((line) => line.replace(/^\\s*\\d+[\\.、)]\\s*/, "").trim())
|
||||
.filter(Boolean);
|
||||
inputs.forEach((input, index) => {{
|
||||
input.value = lines[index] || "";
|
||||
}});
|
||||
resetItems(name, lines);
|
||||
}}
|
||||
|
||||
function renderHistory(data) {{
|
||||
@ -205,6 +233,11 @@ async function loadPreviousPlan() {{
|
||||
|
||||
document.querySelector("#load-history").addEventListener("click", loadHistory);
|
||||
document.querySelector("#report-date").addEventListener("change", loadPreviousPlan);
|
||||
document.querySelectorAll("[data-add-list]").forEach((button) => {{
|
||||
button.addEventListener("click", () => {{
|
||||
addItem(button.dataset.addList);
|
||||
}});
|
||||
}});
|
||||
document.querySelector("#use-previous-plan").addEventListener("click", () => {{
|
||||
fillItemInputs("today_done", document.querySelector("#previous-plan-content").textContent);
|
||||
}});
|
||||
@ -232,6 +265,8 @@ document.querySelector("#report-form").addEventListener("submit", async (event)
|
||||
}}
|
||||
}});
|
||||
|
||||
resetItems("today_done");
|
||||
resetItems("tomorrow_plan");
|
||||
loadHistory();
|
||||
loadPreviousPlan();
|
||||
</script>""",
|
||||
|
||||
@ -68,6 +68,8 @@ class WebTest(unittest.TestCase):
|
||||
self.assertIn("每日工作汇报", submit)
|
||||
self.assertIn("今日状态", submit)
|
||||
self.assertIn('data-list="today_done"', submit)
|
||||
self.assertIn('data-add-list="today_done"', submit)
|
||||
self.assertIn('resetItems("today_done")', submit)
|
||||
self.assertIn("我的历史日报", submit)
|
||||
|
||||
db.upsert_employee(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user