feat: 增加盒子名称自动生成和唯一性检查功能,优化创建和更新盒子的界面提示

This commit is contained in:
2026-03-08 03:07:59 +08:00
parent 22147a1c03
commit 89e5a2162a
3 changed files with 62 additions and 16 deletions

View File

@@ -12,6 +12,7 @@ v1.1 新增能力:
- 支持盒子改名和删除。
- 新增盒子时可设置 `前缀 + 起始序号`,内部编号自动递增。
- 盒子名称自动生成:`基础名称 + 编号范围`,重名自动加 `#2/#3`
- 首页可直接看到每个盒子的编号范围(如 `A1-A28`)。
- 首页新增概览按钮:快速查看已启用的编号与名称。
- 编辑页支持 `启用/停用`
@@ -125,6 +126,11 @@ python app.py
- 前缀 `A`、起始 `1`、容量 28 -> `A1-A28`
- 前缀 `B`、起始 `100`、容量 14 -> `B100-B113`
盒子名生成示例:
- 基础名称 `电阻盒` + 范围 `A1-A28` -> `电阻盒 A1-A28`
- 若发生重名会自动变为:`电阻盒 A1-A28 #2`
## 6. 元器件命名建议(简洁版)
为避免命名过长又保证可检索,建议:

67
app.py
View File

@@ -121,6 +121,33 @@ def slot_range_label(box: Box) -> str:
return f"{start_code}-{end_code}"
def compose_box_name(base_name: str, prefix: str, start_number: int, slot_capacity: int) -> str:
base = (base_name or "").strip()
if not base:
base = "盒子"
end_number = start_number + slot_capacity - 1
return f"{base} {prefix}{start_number}-{prefix}{end_number}"
def make_unique_box_name(candidate_name: str, exclude_box_id: int = None) -> str:
name = candidate_name
counter = 2
while True:
query = Box.query.filter_by(name=name)
if exclude_box_id is not None:
query = query.filter(Box.id != exclude_box_id)
if not query.first():
return name
name = f"{candidate_name} #{counter}"
counter += 1
def infer_base_name(box: Box) -> str:
pattern = rf"\s+{re.escape(box.slot_prefix)}\d+-{re.escape(box.slot_prefix)}\d+(?:\s+#\d+)?$"
base = re.sub(pattern, "", box.name).strip()
return base or box.name
def slot_data_for_box(box: Box):
components = Component.query.filter_by(box_id=box.id).all()
slot_map = {c.slot_index: c for c in components}
@@ -263,6 +290,7 @@ def index():
"used_count": len(overview_rows),
"slot_range": slot_range_label(box),
"overview_rows": overview_rows,
"base_name": infer_base_name(box),
}
)
@@ -272,16 +300,14 @@ def index():
@app.route("/boxes/create", methods=["POST"])
def create_box():
box_type = request.form.get("box_type", "small_28").strip()
name = request.form.get("name", "").strip()
base_name = request.form.get("name", "").strip()
description = request.form.get("description", "").strip()
slot_prefix = request.form.get("slot_prefix", "").strip().upper()
if box_type not in BOX_TYPES:
return "无效盒子类型", 400
if not name:
if not base_name:
return "盒子名称不能为空", 400
if Box.query.filter_by(name=name).first():
return "盒子名称已存在,请更换", 400
try:
start_number = _parse_non_negative_int(request.form.get("start_number", "1"), 1)
@@ -289,12 +315,21 @@ def create_box():
return "起始序号必须是大于等于 0 的整数", 400
meta = BOX_TYPES[box_type]
effective_prefix = slot_prefix or meta["default_prefix"]
generated_name = compose_box_name(
base_name=base_name,
prefix=effective_prefix,
start_number=start_number,
slot_capacity=meta["default_capacity"],
)
final_name = make_unique_box_name(generated_name)
box = Box(
name=name,
name=final_name,
description=description or meta["default_desc"],
box_type=box_type,
slot_capacity=meta["default_capacity"],
slot_prefix=slot_prefix or meta["default_prefix"],
slot_prefix=effective_prefix,
start_number=start_number,
)
db.session.add(box)
@@ -306,25 +341,29 @@ def create_box():
def update_box(box_id: int):
box = Box.query.get_or_404(box_id)
new_name = request.form.get("name", "").strip()
base_name = request.form.get("name", "").strip()
description = request.form.get("description", "").strip()
slot_prefix = request.form.get("slot_prefix", "").strip().upper()
if not new_name:
if not base_name:
return "盒子名称不能为空", 400
duplicate = Box.query.filter(Box.name == new_name, Box.id != box.id).first()
if duplicate:
return "盒子名称已存在,请更换", 400
try:
start_number = _parse_non_negative_int(request.form.get("start_number", "1"), 1)
except ValueError:
return "起始序号必须是大于等于 0 的整数", 400
box.name = new_name
effective_prefix = slot_prefix or BOX_TYPES[box.box_type]["default_prefix"]
generated_name = compose_box_name(
base_name=base_name,
prefix=effective_prefix,
start_number=start_number,
slot_capacity=box.slot_capacity,
)
box.name = make_unique_box_name(generated_name, exclude_box_id=box.id)
box.description = description or BOX_TYPES[box.box_type]["default_desc"]
box.slot_prefix = slot_prefix or BOX_TYPES[box.box_type]["default_prefix"]
box.slot_prefix = effective_prefix
box.start_number = start_number
db.session.commit()
return redirect(url_for("index"))

View File

@@ -24,7 +24,7 @@
<form class="new-box-form" method="post" action="{{ url_for('create_box') }}">
<input type="hidden" name="box_type" value="{{ key }}">
<input type="text" name="name" placeholder="新增盒子名称" required>
<input type="text" name="name" placeholder="基础名称(自动拼范围)" required>
<input type="text" name="slot_prefix" placeholder="前缀(如A/B/C)">
<input type="number" name="start_number" min="0" value="1" placeholder="起始序号">
<input type="text" name="description" placeholder="备注(可选)">
@@ -61,8 +61,9 @@
<details class="box-overview">
<summary>设置(改名/前缀/起始号)</summary>
<p class="hint">输入基础名称后,系统会自动生成: 基础名称 + 编号范围。</p>
<form class="new-box-form compact" method="post" action="{{ url_for('update_box', box_id=item.box.id) }}">
<input type="text" name="name" value="{{ item.box.name }}" required>
<input type="text" name="name" value="{{ item.base_name }}" required>
<input type="text" name="slot_prefix" value="{{ item.box.slot_prefix }}" required>
<input type="number" name="start_number" min="0" value="{{ item.box.start_number }}" required>
<input type="text" name="description" value="{{ item.box.description or '' }}">