feat: 增加盒子名称自动生成和唯一性检查功能,优化创建和更新盒子的界面提示
This commit is contained in:
@@ -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
67
app.py
@@ -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"))
|
||||
|
||||
@@ -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 '' }}">
|
||||
|
||||
Reference in New Issue
Block a user