diff --git a/inventory-backend/app/api/v1/inbound/base.py b/inventory-backend/app/api/v1/inbound/base.py index 754e7d7..c4462bb 100644 --- a/inventory-backend/app/api/v1/inbound/base.py +++ b/inventory-backend/app/api/v1/inbound/base.py @@ -455,3 +455,21 @@ def batch_set_inspection(): db.session.rollback() current_app.logger.error(f"批量设置强制质检失败: {str(e)}") return jsonify({"code": 500, "msg": f"批量设置强制质检失败: {str(e)}"}), 500 + + +# ============================================================================== +# 2.7 智能分组求最大连号 API (GET /api/v1/inbound/base/spec-latest) +# ============================================================================== +@inbound_base_bp.route('/spec-latest', methods=['GET']) +@permission_required('material_list') +def get_spec_latest(): + """ + 获取所有规格型号的最大连号,按智能分组返回 + 返回格式: [{"group": "S", "latest": "S0115/S0115"}, {"group": "Opt4xxx", "latest": "Opt4018/Opt4018"}, ...] + """ + try: + data = MaterialBaseService.get_latest_specs() + return jsonify({"code": 200, "msg": "success", "data": data}) + except Exception as e: + traceback.print_exc() + return jsonify({"code": 500, "msg": str(e)}), 500 diff --git a/inventory-backend/app/services/inbound/base_service.py b/inventory-backend/app/services/inbound/base_service.py index fa67298..0c0625d 100644 --- a/inventory-backend/app/services/inbound/base_service.py +++ b/inventory-backend/app/services/inbound/base_service.py @@ -954,4 +954,71 @@ class MaterialBaseService: except Exception as e: traceback.print_exc() - raise e \ No newline at end of file + raise e + + @staticmethod + def get_latest_specs(): + """ + 获取所有规格型号的最大连号,按智能分组返回 + 返回格式: [{"group": "S", "latest": "S0115/S0115"}, {"group": "Opt4xxx", "latest": "Opt4018/Opt4018"}, ...] + """ + import re + + # 1. 查询所有不为空的规格型号 + specs = MaterialBase.query.filter( + MaterialBase.spec_model.isnot(None), + MaterialBase.spec_model != '' + ).all() + + # 2. 数据结构:{分组名: (原始规格, 数字部分)} + groups = {} + + def parse_spec(spec_full): + """ + 解析规格型号 + 返回: (prefix, num, group_name, original_spec) + """ + # 取斜杠前的部分作为基准 + base_spec = spec_full.split('/')[0] + + # 使用正则解析:字母前缀 + 数字 + match = re.match(r'^([A-Za-z]+)(\d+)$', base_spec) + if not match: + return (base_spec, 0, base_spec, spec_full) + + prefix, num_str = match.groups() + num = int(num_str) + + # 智能分组逻辑 + if prefix == 'Opt': + # Opt 按千位段分组 + thousand = num // 1000 + group = f"Opt{thousand}xxx" + else: + # 常规前缀按原值分组 + group = prefix + + return (prefix, num, group, spec_full) + + # 3. 遍历并分组 + for material in specs: + spec = material.spec_model + if not spec: + continue + + prefix, num, group, original_spec = parse_spec(spec) + + if group not in groups: + groups[group] = (original_spec, num) + else: + _, existing_num = groups[group] + if num > existing_num: + groups[group] = (original_spec, num) + + # 4. 构建返回结果,按分组名排序 + result = [ + {"group": group, "latest": spec} + for group, (spec, _) in sorted(groups.items()) + ] + + return result \ No newline at end of file diff --git a/inventory-web/src/api/material_base.ts b/inventory-web/src/api/material_base.ts index c690f25..dd47e4e 100644 --- a/inventory-web/src/api/material_base.ts +++ b/inventory-web/src/api/material_base.ts @@ -69,4 +69,12 @@ export function batchSetInspection(data: { ids: number[], isInspectionRequired: method: 'post', data }) +} + +// 7. 获取智能分组规格最大连号 +export function getLatestSpecs() { + return request({ + url: '/inbound/base/spec-latest', + method: 'get' + }) } \ No newline at end of file diff --git a/inventory-web/src/components/SpecHelper/index.vue b/inventory-web/src/components/SpecHelper/index.vue new file mode 100644 index 0000000..038c94c --- /dev/null +++ b/inventory-web/src/components/SpecHelper/index.vue @@ -0,0 +1,200 @@ + + + + + \ No newline at end of file diff --git a/inventory-web/src/layout/index.vue b/inventory-web/src/layout/index.vue index a5d1950..af8e789 100644 --- a/inventory-web/src/layout/index.vue +++ b/inventory-web/src/layout/index.vue @@ -5,12 +5,16 @@
+ + +