refactor(material): implement contiguous sequence grouping for specs with count-based descending sort
This commit is contained in:
@ -959,8 +959,12 @@ class MaterialBaseService:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_latest_specs():
|
def get_latest_specs():
|
||||||
"""
|
"""
|
||||||
获取所有规格型号的最大连号,按智能分组返回
|
获取所有规格型号的最大连号,按连续区间分组返回
|
||||||
返回格式: [{"group": "S", "latest": "S0115/S0115"}, {"group": "Opt4xxx", "latest": "Opt4018/Opt4018"}, ...]
|
- 前缀统一大写处理
|
||||||
|
- 只有数字完全连续(N, N+1, N+2...)才认定为同一组
|
||||||
|
- 数字不连续时断开,形成新组
|
||||||
|
- 按每组数量降序排列
|
||||||
|
- 返回每个连续区间的最大值
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -970,55 +974,81 @@ class MaterialBaseService:
|
|||||||
MaterialBase.spec_model != ''
|
MaterialBase.spec_model != ''
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
# 2. 数据结构:{分组名: (原始规格, 数字部分)}
|
# 2. 解析并收集所有有效的 (prefix, num, original_spec)
|
||||||
groups = {}
|
parsed = []
|
||||||
|
|
||||||
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:
|
for material in specs:
|
||||||
spec = material.spec_model
|
spec = material.spec_model
|
||||||
if not spec:
|
if not spec:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
prefix, num, group, original_spec = parse_spec(spec)
|
base_spec = spec.split('/')[0]
|
||||||
|
|
||||||
if group not in groups:
|
match = re.match(r'^([A-Za-z]+)(\d+)$', base_spec)
|
||||||
groups[group] = (original_spec, num)
|
if not match:
|
||||||
|
continue
|
||||||
|
|
||||||
|
prefix, num_str = match.groups()
|
||||||
|
prefix = prefix.upper()
|
||||||
|
num = int(num_str)
|
||||||
|
|
||||||
|
parsed.append((prefix, num, spec))
|
||||||
|
|
||||||
|
# 3. 先按 prefix 升序,再按 num 升序排序
|
||||||
|
parsed.sort(key=lambda x: (x[0], x[1]))
|
||||||
|
|
||||||
|
# 4. 遍历切分连续区间
|
||||||
|
# 核心逻辑:当 current_num != prev_num + 1 时,断开形成新组
|
||||||
|
intervals = []
|
||||||
|
current_prefix = None
|
||||||
|
current_start = None
|
||||||
|
current_end = None
|
||||||
|
current_last_spec = None
|
||||||
|
|
||||||
|
for prefix, num, spec in parsed:
|
||||||
|
if current_prefix is None:
|
||||||
|
current_prefix = prefix
|
||||||
|
current_start = num
|
||||||
|
current_end = num
|
||||||
|
current_last_spec = spec
|
||||||
|
elif prefix == current_prefix and num == current_end + 1:
|
||||||
|
current_end = num
|
||||||
|
current_last_spec = spec
|
||||||
else:
|
else:
|
||||||
_, existing_num = groups[group]
|
intervals.append({
|
||||||
if num > existing_num:
|
'prefix': current_prefix,
|
||||||
groups[group] = (original_spec, num)
|
'start': current_start,
|
||||||
|
'end': current_end,
|
||||||
|
'count': current_end - current_start + 1,
|
||||||
|
'latest': current_last_spec
|
||||||
|
})
|
||||||
|
current_prefix = prefix
|
||||||
|
current_start = num
|
||||||
|
current_end = num
|
||||||
|
current_last_spec = spec
|
||||||
|
|
||||||
# 4. 构建返回结果,按分组名排序
|
if current_prefix is not None:
|
||||||
result = [
|
intervals.append({
|
||||||
{"group": group, "latest": spec}
|
'prefix': current_prefix,
|
||||||
for group, (spec, _) in sorted(groups.items())
|
'start': current_start,
|
||||||
]
|
'end': current_end,
|
||||||
|
'count': current_end - current_start + 1,
|
||||||
|
'latest': current_last_spec
|
||||||
|
})
|
||||||
|
|
||||||
|
# 5. 按每组数量降序排列,再按前缀升序
|
||||||
|
intervals.sort(key=lambda x: (-x['count'], x['prefix']))
|
||||||
|
|
||||||
|
# 6. 构建返回结果
|
||||||
|
result = []
|
||||||
|
for item in intervals:
|
||||||
|
prefix = item['prefix']
|
||||||
|
start = item['start']
|
||||||
|
end = item['end']
|
||||||
|
result.append({
|
||||||
|
"group": f"{prefix}({start}-{end})",
|
||||||
|
"count": item['count'],
|
||||||
|
"latest": item['latest']
|
||||||
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
Reference in New Issue
Block a user