feat: 新增多类功能并优化现有流程
1. 工序工位支持0号上线位,更新解析逻辑与注释 2. 物料清单模块重命名为产品物料清单并优化文案 3. WMS与工位端新增用户/角色详情抽屉组件 4. 工单模块新增自动生成工单号、工位分组选择器 5. 日排产支持批量生成与详情查看 6. 工单列表重构操作菜单与表单优化
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
# 为列表页自动注入「详情」按钮 + DetailDrawer 抽屉。
|
||||
# 字段从已有 <el-table-column> 抽取(中文 label 复用,type:time 自动识别)。
|
||||
import re, sys, os
|
||||
|
||||
SKIP_LABELS = {'操作', '图片', '操作人', '附件', '明细', '记录', '步骤'}
|
||||
|
||||
def parse_columns(tpl):
|
||||
fields = []
|
||||
seen = set()
|
||||
col_re = re.compile(r'<el-table-column\b([^>]*?)(/?>)', re.S)
|
||||
i = 0
|
||||
while True:
|
||||
m = col_re.search(tpl, i)
|
||||
if not m:
|
||||
break
|
||||
attrs = m.group(1)
|
||||
closing = m.group(2)
|
||||
if closing == '/>':
|
||||
block = m.group(0)
|
||||
i = m.end()
|
||||
else:
|
||||
k = tpl.find('</el-table-column>', m.end())
|
||||
if k < 0:
|
||||
i = m.end()
|
||||
continue
|
||||
block = tpl[m.start():k + len('</el-table-column>')]
|
||||
i = k + len('</el-table-column>')
|
||||
m_prop = re.search(r'prop="([^"]+)"', block)
|
||||
m_label = re.search(r'label="([^"]+)"', block)
|
||||
m_time = re.search(r'fmtTime\(row\.(\w+)\)', block)
|
||||
m_dynamic = re.search(r':label=', block)
|
||||
if not m_label or m_dynamic:
|
||||
continue
|
||||
label = m_label.group(1)
|
||||
if label in SKIP_LABELS:
|
||||
continue
|
||||
if m_time:
|
||||
key = m_time.group(1)
|
||||
if key not in seen:
|
||||
fields.append({'key': key, 'label': label, 'type': 'time'})
|
||||
seen.add(key)
|
||||
continue
|
||||
if m_prop:
|
||||
key = m_prop.group(1)
|
||||
if key not in seen:
|
||||
fields.append({'key': key, 'label': label})
|
||||
seen.add(key)
|
||||
return fields
|
||||
|
||||
def fmt_field(f):
|
||||
if f.get('type') == 'time':
|
||||
return " { key: '%s', label: '%s', type: 'time' }," % (f['key'], f['label'])
|
||||
return " { key: '%s', label: '%s' }," % (f['key'], f['label'])
|
||||
|
||||
def inject(path):
|
||||
s = open(path, encoding='utf-8').read()
|
||||
if 'DetailDrawer' in s:
|
||||
print(' SKIP (already has DetailDrawer):', path)
|
||||
return False
|
||||
if 'openDetail(' in s:
|
||||
print(' SKIP (already has openDetail):', path)
|
||||
return False
|
||||
# script + template
|
||||
m_script = re.search(r'<script setup>(.*?)</script>', s, re.S)
|
||||
m_tpl = re.search(r'<template>(.*?)</template>', s, re.S)
|
||||
if not m_script or not m_tpl:
|
||||
print(' SKIP (no script/template):', path)
|
||||
return False
|
||||
script = m_script.group(1)
|
||||
tpl = m_tpl.group(1)
|
||||
|
||||
fields = parse_columns(tpl)
|
||||
if not fields:
|
||||
print(' SKIP (no columns parsed):', path)
|
||||
return False
|
||||
|
||||
# 1) import
|
||||
imports = list(re.finditer(r"^\s*import .* from '[^']+'\s*$", script, re.M))
|
||||
if not imports:
|
||||
print(' SKIP (no import lines):', path)
|
||||
return False
|
||||
last_import = imports[-1]
|
||||
ins_import = "import DetailDrawer from '../components/DetailDrawer.vue'\n"
|
||||
# 若路径是 ../../components(子目录页)则调整
|
||||
if '../components/' not in script and '../../components/' in s:
|
||||
ins_import = "import DetailDrawer from '../../components/DetailDrawer.vue'\n"
|
||||
script_new = script[:last_import.end()] + "\n" + ins_import + script[last_import.end():]
|
||||
|
||||
# 2) openDetail + detail state before </script>
|
||||
fields_block = ",\n".join(fmt_field(f) for f in fields)
|
||||
open_detail = (
|
||||
"\n// 详情抽屉\n"
|
||||
"const detail = reactive({ show: false, title: '', fields: [], row: null })\n"
|
||||
"function openDetail(row) {\n"
|
||||
" detail.row = row\n"
|
||||
" detail.title = `详情 · #${row.id}`\n"
|
||||
" detail.fields = [\n" + fields_block + "\n ]\n"
|
||||
" detail.show = true\n"
|
||||
"}\n"
|
||||
)
|
||||
script_new = script_new.rstrip()
|
||||
if not script_new.endswith('}'):
|
||||
script_new = script_new + "\n"
|
||||
script_new = script_new + open_detail
|
||||
|
||||
# 3) 详情 column right after <el-table
|
||||
detail_col = (
|
||||
" <el-table-column label=\"详情\" width=\"80\" align=\"center\">\n"
|
||||
" <template #default=\"{ row }\">\n"
|
||||
" <el-button link type=\"primary\" size=\"small\" @click=\"openDetail(row)\">详情</el-button>\n"
|
||||
" </template>\n"
|
||||
" </el-table-column>\n"
|
||||
)
|
||||
mt = re.search(r'<el-table\b[^>]*>', tpl)
|
||||
if not mt:
|
||||
print(' SKIP (no el-table):', path)
|
||||
return False
|
||||
# 插入到 <el-table ...> 之后(同一行或下一行)
|
||||
insert_pos = mt.end()
|
||||
tpl_new = tpl[:insert_pos] + "\n" + detail_col + tpl[insert_pos:]
|
||||
|
||||
# 4) DetailDrawer before last </div> in template
|
||||
last_div = tpl_new.rfind('</div>')
|
||||
drawer = (
|
||||
"\n <DetailDrawer :visible=\"detail.show\" @update:visible=\"detail.show = $event\"\n"
|
||||
" :title=\"detail.title\" :fields=\"detail.fields\" :data=\"detail.row\" />\n"
|
||||
)
|
||||
tpl_new = tpl_new[:last_div] + drawer + tpl_new[last_div:]
|
||||
|
||||
new_s = s
|
||||
new_s = new_s[:m_script.start(1)] + script_new + new_s[m_script.end(1):]
|
||||
# 重新定位 template(script 长度变化不影响 template 区域位置,因 template 在 script 之后)
|
||||
new_s = new_s[:m_tpl.start(1)] + tpl_new + new_s[m_tpl.end(1):]
|
||||
|
||||
open(path, 'w', encoding='utf-8').write(new_s)
|
||||
print(' OK fields=%d : %s' % (len(fields), path))
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
for p in sys.argv[1:]:
|
||||
print('FILE', p)
|
||||
try:
|
||||
inject(p)
|
||||
except Exception as e:
|
||||
print(' ERROR', p, e)
|
||||
Reference in New Issue
Block a user