hou hace 3 semanas
padre
commit
c7a6e965fa
Se han modificado 100 ficheros con 25498 adiciones y 408 borrados
  1. 496 0
      _apk_work/build_manuals_pdf.py
  2. 36 0
      _apk_work/dump_db.py
  3. 138 0
      _apk_work/extract_manual_images.py
  4. 478 0
      _apk_work/extract_mes_icons_files.py
  5. 26 0
      _apk_work/extract_pdfs.py
  6. 79 0
      _apk_work/extract_strings.py
  7. 3000 0
      _apk_work/extracted/ascii_hits.txt
  8. 8627 0
      _apk_work/extracted/classes.txt
  9. 2992 0
      _apk_work/extracted/cn_strings.txt
  10. 8 0
      _apk_work/extracted/db_categories.txt
  11. 45 0
      _apk_work/extracted/db_config.txt
  12. 22 0
      _apk_work/extracted/db_hidden_menus.txt
  13. 47 0
      _apk_work/extracted/db_icons.txt
  14. 122 0
      _apk_work/extracted/db_menus.txt
  15. 60 0
      _apk_work/extracted/db_process.txt
  16. BIN
      _apk_work/extracted/extract_mes_icons_log.txt
  17. 28 0
      _apk_work/extracted/mes_icons_image_files_to_copy.txt
  18. 114 0
      _apk_work/extracted/mes_icons_image_map_current_only.txt
  19. 229 0
      _apk_work/extracted/mes_icons_image_map_from_old.txt
  20. 586 0
      _apk_work/extracted/restore_mes_icons_image_mapping.sql
  21. 297 0
      _apk_work/extracted/urls.txt
  22. 0 0
      _apk_work/extracted/utf16_cn.txt
  23. 91 0
      _apk_work/img_meta_preview.txt
  24. 169 0
      _apk_work/insert_manual_images.py
  25. 429 0
      _apk_work/manuals_text/1、系统管理操作手册.txt
  26. 221 0
      _apk_work/manuals_text/2、设备管理操作手册.txt
  27. 301 0
      _apk_work/manuals_text/3、物料管理操作手册.txt
  28. 263 0
      _apk_work/manuals_text/4、质量管理操作手册.txt
  29. 386 0
      _apk_work/manuals_text/5、生产管理操作手册.txt
  30. 212 0
      _apk_work/manuals_text/6、ERP对接操作手册.txt
  31. 251 0
      _apk_work/manuals_text/7、生产线管理操作手册.txt
  32. 509 0
      _apk_work/manuals_text/8、PDA操作说明操作手册.txt
  33. 120 0
      _apk_work/manuals_text/9、MES系统客户端员工扫码操作手册.txt
  34. 2127 0
      _apk_work/manuals_text/大洋交付-操作手册合订版.txt
  35. 144 0
      _apk_work/md_to_docx.py
  36. 10 0
      _apk_work/pdf_img_count.txt
  37. 25 0
      _apk_work/query_menus.sql
  38. 247 0
      _apk_work/regen_mes_icons_current_sql.py
  39. BIN
      _apk_work/tools/apktool.jar
  40. 12 0
      db/mysql/add_mes_gp12_pack_lines_config.sql
  41. 3 0
      db/mysql/add_mes_process_param_limit_gun_type.sql
  42. 4 0
      db/mysql/add_mes_process_param_limit_line_oprno.sql
  43. 10 0
      db/mysql/add_mes_product_check_one_permission.sql
  44. 5 0
      db/mysql/add_mes_product_check_one_remark.sql
  45. 39 0
      db/mysql/optimize_process_param_list_indexes.sql
  46. 13 0
      db/mysql/restore_sys_config_menu.sql
  47. 3 0
      db/mysql/restrict_sys_config_to_super_admin.sql
  48. 130 0
      db/mysql/scale_spot_welding_current.py
  49. 128 0
      db/mysql/scale_spot_welding_current.sql
  50. 12 4
      docs/PDAGP12检查接口说明.md
  51. 192 0
      hs_err_pid7152.log
  52. 2 0
      src/main/java/com/jeesite/modules/mes/dao/MesAdw300DataDao.java
  53. 2 0
      src/main/java/com/jeesite/modules/mes/dao/MesLineProcessDao.java
  54. 9 0
      src/main/java/com/jeesite/modules/mes/dao/MesProductArcWeldingDao.java
  55. 6 0
      src/main/java/com/jeesite/modules/mes/dao/MesProductCmtDao.java
  56. 6 1
      src/main/java/com/jeesite/modules/mes/dao/MesProductProdDao.java
  57. 36 3
      src/main/java/com/jeesite/modules/mes/entity/MesProcessParamLimit.java
  58. 2 7
      src/main/java/com/jeesite/modules/mes/entity/MesProductArcWelding.java
  59. 4 1
      src/main/java/com/jeesite/modules/mes/entity/MesProductCheckOne.java
  60. 1 1
      src/main/java/com/jeesite/modules/mes/entity/MesProductCmt.java
  61. 20 0
      src/main/java/com/jeesite/modules/mes/entity/MesProductGlueDuration.java
  62. 27 0
      src/main/java/com/jeesite/modules/mes/entity/MesProductProd.java
  63. 74 0
      src/main/java/com/jeesite/modules/mes/service/MesAdw300DataService.java
  64. 8 0
      src/main/java/com/jeesite/modules/mes/service/MesLineProcessService.java
  65. 231 16
      src/main/java/com/jeesite/modules/mes/service/MesProcessParamLimitCheckService.java
  66. 15 0
      src/main/java/com/jeesite/modules/mes/service/MesProductArcWeldingService.java
  67. 177 0
      src/main/java/com/jeesite/modules/mes/service/MesProductCheckOneService.java
  68. 7 0
      src/main/java/com/jeesite/modules/mes/service/MesProductCmtService.java
  69. 14 0
      src/main/java/com/jeesite/modules/mes/service/MesProductProdService.java
  70. 2 47
      src/main/java/com/jeesite/modules/mes/service/MesProductRecordService.java
  71. 38 1
      src/main/java/com/jeesite/modules/mes/service/MesProductService.java
  72. 36 0
      src/main/java/com/jeesite/modules/mes/util/CommonUitl.java
  73. 18 5
      src/main/java/com/jeesite/modules/mes/web/MesBatchSnController.java
  74. 11 1
      src/main/java/com/jeesite/modules/mes/web/MesElectricTorqueController.java
  75. 142 0
      src/main/java/com/jeesite/modules/mes/web/MesProcessParamLimitController.java
  76. 208 5
      src/main/java/com/jeesite/modules/mes/web/MesProductArcWeldingController.java
  77. 25 0
      src/main/java/com/jeesite/modules/mes/web/MesProductCheckOneController.java
  78. 46 1
      src/main/java/com/jeesite/modules/mes/web/MesProductCmtController.java
  79. 3 3
      src/main/java/com/jeesite/modules/mes/web/MesProductController.java
  80. 9 0
      src/main/java/com/jeesite/modules/mes/web/MesProductFswController.java
  81. 8 0
      src/main/java/com/jeesite/modules/mes/web/MesProductGlueDurationController.java
  82. 2 12
      src/main/java/com/jeesite/modules/mes/web/MesProductGp12CheckController.java
  83. 3 2
      src/main/java/com/jeesite/modules/mes/web/MesProductGp12Controller.java
  84. 72 3
      src/main/java/com/jeesite/modules/mes/web/MesProductProdController.java
  85. 12 0
      src/main/java/com/jeesite/modules/mes/web/MesProductQmController.java
  86. 17 144
      src/main/java/com/jeesite/modules/mes/web/MesProductRecordController.java
  87. 9 0
      src/main/java/com/jeesite/modules/mes/web/MesTorsionalProcessController.java
  88. 104 0
      src/main/java/com/jeesite/modules/sys/web/ConfigSuperAdminAspect.java
  89. 11 6
      src/main/resources/config/application.yml
  90. 44 0
      src/main/resources/mappings/modules/mes/MesAdw300DataDao.xml
  91. 10 1
      src/main/resources/mappings/modules/mes/MesLineProcessDao.xml
  92. 45 12
      src/main/resources/mappings/modules/mes/MesProductArcWeldingDao.xml
  93. 24 5
      src/main/resources/mappings/modules/mes/MesProductCmtDao.xml
  94. 35 9
      src/main/resources/mappings/modules/mes/MesProductProdDao.xml
  95. 10 0
      src/main/resources/views/modules/mes/mesElectricTorqueList.html
  96. 46 9
      src/main/resources/views/modules/mes/mesEnergyScreen.html
  97. 173 1
      src/main/resources/views/modules/mes/mesProcessCheckRecordInfo.html
  98. 177 106
      src/main/resources/views/modules/mes/mesProcessParamLimitForm.html
  99. 31 2
      src/main/resources/views/modules/mes/mesProcessParamLimitList.html
  100. 0 0
      src/main/resources/views/modules/mes/mesProductCheckOneInfo.html

+ 496 - 0
_apk_work/build_manuals_pdf.py

@@ -0,0 +1,496 @@
+# -*- coding: utf-8 -*-
+"""Build 分册 + 合订版 Word/PDF for 大洋 MES manuals 9.19."""
+import os, re, html as htmlmod
+from pathlib import Path
+
+import fitz
+from docx import Document
+from docx.shared import Pt, Cm, RGBColor, Emu
+from docx.oxml.ns import qn
+from docx.enum.table import WD_TABLE_ALIGNMENT
+from docx.enum.text import WD_ALIGN_PARAGRAPH
+
+ROOT = Path(r"D:\产线\大洋\大洋操作手册汇总9.19")
+FONT_FILE = r"C:\Windows\Fonts\simhei.ttf"
+FONT_FILE_REG = r"C:\Windows\Fonts\msyh.ttc"
+DATE = "2026年9月19日"
+A4 = fitz.paper_rect("a4")
+
+FASCICLES = [
+    ("1、系统管理操作手册.md", "系统管理操作手册", "分册一"),
+    ("2、设备管理操作手册.md", "设备管理操作手册", "分册二"),
+    ("3、物料管理操作手册.md", "物料管理操作手册", "分册三"),
+    ("4、质量管理操作手册.md", "质量管理操作手册", "分册四"),
+    ("5、生产管理操作手册.md", "生产管理操作手册", "分册五"),
+    ("6、ERP对接操作手册.md", "ERP对接操作手册", "分册六"),
+    ("7、生产线管理操作手册.md", "生产线管理操作手册", "分册七"),
+    ("8、PDA操作说明操作手册.md", "PDA操作说明操作手册", "分册八"),
+    ("9、MES系统客户端员工扫码操作手册.md", "MES系统客户端员工扫码操作手册", "分册九"),
+]
+
+
+def esc(s):
+    return htmlmod.escape(s, quote=True)
+
+
+def md_inline_html(text):
+    text = esc(text)
+    text = re.sub(r"\*\*([^*]+)\*\*", r"<b>\1</b>", text)
+    text = re.sub(r"`([^`]+)`", r"<code>\1</code>", text)
+    return text
+
+
+def is_sep_row(cells):
+    return all(re.match(r"^:?-+:?$", c.replace(" ", "")) for c in cells if c != "")
+
+
+def md_to_html_body(md_text, skip_first_h1=False):
+    lines = md_text.splitlines()
+    out = []
+    i = 0
+    skipped = False
+    while i < len(lines):
+        line = lines[i].rstrip()
+        if not line:
+            i += 1
+            continue
+        if line.strip() == "---":
+            i += 1
+            continue
+        if line.startswith("# "):
+            title = line[2:].strip()
+            if skip_first_h1 and not skipped:
+                skipped = True
+                i += 1
+                continue
+            out.append("<h1>%s</h1>" % md_inline_html(title))
+            i += 1
+            continue
+        m = re.match(r"^(#{2,6})\s+(.*)$", line)
+        if m:
+            lv = len(m.group(1))
+            out.append("<h%d>%s</h%d>" % (lv, md_inline_html(m.group(2).strip()), lv))
+            i += 1
+            continue
+        if line.startswith("|"):
+            rows = []
+            while i < len(lines) and lines[i].startswith("|"):
+                cells = [c.strip() for c in lines[i].strip().strip("|").split("|")]
+                if not is_sep_row(cells):
+                    rows.append(cells)
+                i += 1
+            if rows:
+                out.append("<table>")
+                for ri, row in enumerate(rows):
+                    out.append("<tr>")
+                    tag = "th" if ri == 0 else "td"
+                    for c in row:
+                        out.append("<%s>%s</%s>" % (tag, md_inline_html(c), tag))
+                    out.append("</tr>")
+                out.append("</table>")
+            continue
+        if line.startswith("- "):
+            out.append("<ul>")
+            while i < len(lines) and lines[i].startswith("- "):
+                out.append("<li>%s</li>" % md_inline_html(lines[i][2:].strip()))
+                i += 1
+            out.append("</ul>")
+            continue
+        if re.match(r"^\d+\.\s", line):
+            out.append("<ol>")
+            while i < len(lines) and re.match(r"^\d+\.\s", lines[i]):
+                out.append("<li>%s</li>" % md_inline_html(re.sub(r"^\d+\.\s+", "", lines[i])))
+                i += 1
+            out.append("</ol>")
+            continue
+        img = re.match(r"^!\[(.*?)\]\((.*?)\)$", line.strip())
+        if img:
+            cap, src = img.group(1), img.group(2).replace("\\", "/")
+            rel = src.split("images/")[-1] if "images/" in src else src.split("/")[-1]
+            member = rel.replace("/", "__")
+            out.append('<p class="shot"><img src="%s" alt="%s"/></p>' % (esc(member), esc(cap)))
+            out.append('<p class="imgcap">%s</p>' % md_inline_html(cap))
+            i += 1
+            continue
+        if line.strip().startswith("*(界面截图") and "为准" in line:
+            i += 1
+            continue
+        out.append("<p>%s</p>" % md_inline_html(line))
+        i += 1
+    return "\n".join(out)
+
+
+CSS = r"""
+@font-face { font-family: bodyfont; src: url("simhei.ttf"); }
+body { font-family: bodyfont, sans-serif; font-size: 10.5pt; line-height: 1.5; color: #222; }
+h1 { font-size: 18pt; color: #1F4E79; margin: 18pt 0 8pt 0; page-break-before: auto; }
+h2 { font-size: 14pt; color: #2E75B6; margin: 14pt 0 6pt 0; }
+h3 { font-size: 12.5pt; color: #2E75B6; margin: 12pt 0 5pt 0; }
+h4 { font-size: 11.5pt; color: #1F4E79; margin: 10pt 0 4pt 0; }
+h5, h6 { font-size: 11pt; margin: 8pt 0 4pt 0; }
+p { margin: 0 0 6pt 0; }
+ul, ol { margin: 0 0 8pt 18pt; padding: 0; }
+li { margin: 0 0 3pt 0; }
+table { border-collapse: collapse; width: 100%; margin: 6pt 0 10pt 0; }
+th { background: #1F4E79; color: #fff; font-weight: bold; }
+th, td { border: 1px solid #8aa; padding: 4pt 6pt; font-size: 9.5pt; vertical-align: top; }
+code { font-size: 9.5pt; }
+p.shot { text-align: center; margin: 8pt 0 2pt 0; }
+p.shot img { max-width: 100%; max-height: 380pt; }
+p.imgcap { text-align: center; font-size: 9pt; color: #555; margin: 0 0 10pt 0; }
+"""
+
+
+def make_cover(title, subtitle, extra=""):
+    doc = fitz.open()
+    page = doc.new_page(width=A4.width, height=A4.height)
+    page.insert_font(fontname="hei", fontfile=FONT_FILE)
+    cx = A4.width / 2
+    page.draw_rect(fitz.Rect(40, 40, A4.width - 40, A4.height - 40), color=(0.12, 0.31, 0.47), width=1.5)
+    page.draw_rect(fitz.Rect(48, 48, A4.width - 48, A4.height - 48), color=(0.18, 0.46, 0.71), width=0.6)
+    page.insert_text((cx - 120, 180), "安徽大洋  ·  MES", fontname="hei", fontsize=14, fill=(0.18, 0.46, 0.71))
+    # wrap title
+    y = 250
+    for line in title.split("\n"):
+        w = fitz.get_text_length(line, fontname="hei", fontsize=26, fontfile=FONT_FILE) if False else None
+        tw = fitz.Font(fontfile=FONT_FILE).text_length(line, 26)
+        page.insert_text((cx - tw / 2, y), line, fontname="hei", fontsize=26, fill=(0.12, 0.31, 0.47))
+        y += 40
+    if subtitle:
+        tw = fitz.Font(fontfile=FONT_FILE).text_length(subtitle, 16)
+        page.insert_text((cx - tw / 2, y + 10), subtitle, fontname="hei", fontsize=16, fill=(0.3, 0.3, 0.3))
+        y += 40
+    if extra:
+        tw = fitz.Font(fontfile=FONT_FILE).text_length(extra, 13)
+        page.insert_text((cx - tw / 2, y + 20), extra, fontname="hei", fontsize=13, fill=(0.35, 0.35, 0.35))
+    tw = fitz.Font(fontfile=FONT_FILE).text_length(DATE, 12)
+    page.insert_text((cx - tw / 2, A4.height - 120), DATE, fontname="hei", fontsize=12, fill=(0.2, 0.2, 0.2))
+    return doc
+
+
+def html_to_pdf_pages(html_body, header_text):
+    css = CSS
+    html = "<html><body>%s</body></html>" % html_body
+    import tempfile, shutil
+    img_tmp = tempfile.mkdtemp(prefix="mesimg_")
+    img_root = str(ROOT / "images")
+    if os.path.isdir(img_root):
+        for dirpath, _, files in os.walk(img_root):
+            for fn in files:
+                if fn.lower().endswith((".png", ".jpg", ".jpeg")):
+                    full = os.path.join(dirpath, fn)
+                    rel = os.path.relpath(full, img_root).replace("\\", "/")
+                    member = rel.replace("/", "__")
+                    shutil.copy2(full, os.path.join(img_tmp, member))
+    arch = fitz.Archive(os.path.dirname(FONT_FILE))
+    arch.add(img_tmp)
+    story = fitz.Story(html=html, user_css=css, archive=arch)
+    where = fitz.Rect(48, 52, A4.width - 48, A4.height - 48)
+    import tempfile
+    tmp = tempfile.mktemp(suffix=".pdf")
+    writer = fitz.DocumentWriter(tmp)
+    more = 1
+    while more:
+        dev = writer.begin_page(A4)
+        more, _ = story.place(where)
+        story.draw(dev)
+        writer.end_page()
+    writer.close()
+    try:
+        shutil.rmtree(img_tmp, ignore_errors=True)
+    except Exception:
+        pass
+    body = fitz.open(tmp)
+    try:
+        os.remove(tmp)
+    except Exception:
+        pass
+    font = fitz.Font(fontfile=FONT_FILE)
+    for i, page in enumerate(body):
+        page.insert_font(fontname="hei", fontfile=FONT_FILE)
+        page.insert_text((48, 32), header_text, fontname="hei", fontsize=8, fill=(0.4, 0.4, 0.4))
+        pn = str(i + 1)
+        tw = font.text_length(pn, 9)
+        page.insert_text((A4.width - 48 - tw, A4.height - 32), pn, fontname="hei", fontsize=9, fill=(0.3, 0.3, 0.3))
+        page.draw_line(fitz.Point(48, 40), fitz.Point(A4.width - 48, 40), color=(0.75, 0.75, 0.75), width=0.4)
+        page.draw_line(fitz.Point(48, A4.height - 40), fitz.Point(A4.width - 48, A4.height - 40), color=(0.75, 0.75, 0.75), width=0.4)
+    return body
+
+
+def stamp_page_numbers(doc, header_text, start=1):
+    font = fitz.Font(fontfile=FONT_FILE)
+    for i, page in enumerate(doc):
+        # skip cover (first page) header already different
+        page.insert_font(fontname="hei", fontfile=FONT_FILE)
+        if i == 0:
+            continue
+        page.insert_text((48, 32), header_text, fontname="hei", fontsize=8, fill=(0.4, 0.4, 0.4))
+        pn = str(start + i - 1)
+        tw = font.text_length(pn, 9)
+        page.insert_text((A4.width - 48 - tw, A4.height - 32), pn, fontname="hei", fontsize=9, fill=(0.3, 0.3, 0.3))
+        page.draw_line(fitz.Point(48, 40), fitz.Point(A4.width - 48, 40), color=(0.75, 0.75, 0.75), width=0.4)
+        page.draw_line(fitz.Point(48, A4.height - 40), fitz.Point(A4.width - 48, A4.height - 40), color=(0.75, 0.75, 0.75), width=0.4)
+
+
+def build_pdf(cover_title, cover_sub, extra, html_body, header, out_path):
+    cover = make_cover(cover_title, cover_sub, extra)
+    body = html_to_pdf_pages(html_body, header)
+    final = fitz.open()
+    final.insert_pdf(cover)
+    final.insert_pdf(body)
+    # restamp body pages only
+    font = fitz.Font(fontfile=FONT_FILE)
+    for i, page in enumerate(final):
+        if i == 0:
+            continue
+        page.insert_font(fontname="hei", fontfile=FONT_FILE)
+        # html_to_pdf_pages already stamped; cover inserted shifts numbers.
+    final.save(out_path, deflate=True, garbage=4)
+    cover.close()
+    body.close()
+    final.close()
+    print("PDF", out_path.name, "pages ok")
+
+
+# ---- docx (reuse simplified converter) ----
+from importlib.machinery import SourceFileLoader
+# inline converter to avoid path issues
+
+def set_run_font(run, size=11, bold=False, color=None):
+    run.bold = bold
+    run.font.size = Pt(size)
+    run.font.name = "微软雅黑"
+    rPr = run._element.get_or_add_rPr()
+    rFonts = rPr.find(qn("w:rFonts"))
+    if rFonts is None:
+        rFonts = rPr.makeelement(qn("w:rFonts"), {})
+        rPr.append(rFonts)
+    rFonts.set(qn("w:eastAsia"), "微软雅黑")
+    rFonts.set(qn("w:ascii"), "微软雅黑")
+    rFonts.set(qn("w:hAnsi"), "微软雅黑")
+    if color:
+        run.font.color.rgb = RGBColor(*color)
+
+
+def add_runs(p, text, size=11, bold=False):
+    parts = re.split(r"(\*\*[^*]+\*\*)", text)
+    for part in parts:
+        if part.startswith("**") and part.endswith("**"):
+            run = p.add_run(part[2:-2])
+            set_run_font(run, size=size, bold=True)
+        else:
+            run = p.add_run(part)
+            set_run_font(run, size=size, bold=bold)
+
+
+def md_to_docx(md_text, docx_path, heading_shift=0):
+    doc = Document()
+    section = doc.sections[0]
+    section.top_margin = Cm(2)
+    section.bottom_margin = Cm(2)
+    section.left_margin = Cm(2.2)
+    section.right_margin = Cm(2.2)
+    style = doc.styles["Normal"]
+    style.font.name = "微软雅黑"
+    style.font.size = Pt(11)
+    style.element.rPr.rFonts.set(qn("w:eastAsia"), "微软雅黑")
+    lines = md_text.splitlines()
+    i = 0
+    while i < len(lines):
+        line = lines[i].rstrip()
+        if not line or line.strip() == "---":
+            i += 1
+            continue
+        if line.startswith("#"):
+            hashes = len(line) - len(line.lstrip("#"))
+            title = line[hashes:].strip()
+            level = min(max(hashes - 1 + heading_shift, 0), 4)
+            p = doc.add_heading("", level=level)
+            p.clear()
+            run = p.add_run(title)
+            sizes = {0: 18, 1: 16, 2: 14, 3: 12, 4: 12}
+            set_run_font(run, size=sizes.get(level, 12), bold=True, color=(0x1F, 0x4E, 0x79))
+            i += 1
+            continue
+        if line.startswith("|"):
+            rows = []
+            while i < len(lines) and lines[i].startswith("|"):
+                cells = [c.strip() for c in lines[i].strip().strip("|").split("|")]
+                if not is_sep_row(cells):
+                    rows.append(cells)
+                i += 1
+            if rows:
+                cols = max(len(r) for r in rows)
+                table = doc.add_table(rows=len(rows), cols=cols)
+                table.style = "Table Grid"
+                table.alignment = WD_TABLE_ALIGNMENT.CENTER
+                for r_idx, row in enumerate(rows):
+                    for c_idx in range(cols):
+                        cell = table.cell(r_idx, c_idx)
+                        cell.text = ""
+                        p = cell.paragraphs[0]
+                        val = row[c_idx] if c_idx < len(row) else ""
+                        add_runs(p, val, size=10, bold=(r_idx == 0))
+            continue
+        if line.startswith("- "):
+            p = doc.add_paragraph(style="List Bullet")
+            p.clear()
+            add_runs(p, line[2:].strip())
+            i += 1
+            continue
+        if re.match(r"^\d+\.\s", line):
+            p = doc.add_paragraph(style="List Number")
+            p.clear()
+            add_runs(p, re.sub(r"^\d+\.\s+", "", line))
+            i += 1
+            continue
+        img = re.match(r"^!\[(.*?)\]\((.*?)\)$", line.strip())
+        if img:
+            cap, src = img.group(1), img.group(2).replace("/", os.sep)
+            img_path = src if os.path.isabs(src) else str(ROOT / src)
+            p = doc.add_paragraph()
+            p.alignment = WD_ALIGN_PARAGRAPH.CENTER
+            if os.path.exists(img_path):
+                run = p.add_run()
+                try:
+                    run.add_picture(img_path, width=Cm(14.5))
+                except Exception:
+                    add_runs(p, "[图片无法插入] " + cap)
+            cap_p = doc.add_paragraph()
+            cap_p.alignment = WD_ALIGN_PARAGRAPH.CENTER
+            add_runs(cap_p, cap, size=9)
+            i += 1
+            continue
+        if line.strip().startswith("*(界面截图"):
+            i += 1
+            continue
+        p = doc.add_paragraph()
+        add_runs(p, line)
+        i += 1
+        try:
+            doc.save(str(docx_path))
+        except PermissionError:
+            alt = str(docx_path).replace(".docx", "_新.docx")
+            doc.save(alt)
+            print("docx locked, wrote", alt)
+
+
+def strip_toc(md):
+    # drop ## 目录 ... until next ##
+    return re.sub(r"\n## 目录\n[\s\S]*?(?=\n## )", "\n", md, count=1)
+
+
+def remap_headings(md, delta):
+    def repl(m):
+        hashes = m.group(1)
+        rest = m.group(2)
+        n = min(len(hashes) + delta, 6)
+        return "#" * n + " " + rest
+    return re.sub(r"^(#{1,6})\s+(.*)$", repl, md, flags=re.M)
+
+
+def build_combined_md():
+    intro = (ROOT / "_合订版_导言.md").read_text(encoding="utf-8")
+    parts = [intro, ""]
+    mapping = [
+        (FASCICLES[0][0], "#### 3.1.3 系统管理", 3),
+        (FASCICLES[1][0], "#### 3.1.4 设备管理", 3),
+        (FASCICLES[2][0], "#### 3.1.5 物料管理", 3),
+        (FASCICLES[3][0], "#### 3.1.6 质量管理", 3),
+        (FASCICLES[4][0], "#### 3.1.7 生产管理", 3),
+        (FASCICLES[5][0], "#### 3.1.8 ERP 对接", 3),
+        (FASCICLES[6][0], "#### 3.1.9 生产线管理", 3),
+        (FASCICLES[7][0], "### 3.2 PDA 软件操作说明", 2),
+        (FASCICLES[8][0], "### 3.3 工控机软件操作说明", 2),
+    ]
+    for fname, section_title, delta in mapping:
+        raw = (ROOT / fname).read_text(encoding="utf-8")
+        raw = strip_toc(raw)
+        # drop first h1
+        raw = re.sub(r"^# .*\n+", "", raw)
+        raw = re.sub(r"^20\d{2} 年.*\n+", "", raw)
+        raw = remap_headings(raw, delta)
+        parts.append(section_title)
+        parts.append("")
+        parts.append(raw.strip())
+        parts.append("")
+    changelog = (ROOT / "00-修订对照说明.md").read_text(encoding="utf-8")
+    changelog = remap_headings(re.sub(r"^# .*\n+", "## 附录 本次修订对照说明\n\n", changelog, count=1), 0)
+    parts.append(changelog)
+    text = "\n".join(parts)
+    out = ROOT / "大洋交付-操作手册合订版.md"
+    out.write_text(text, encoding="utf-8")
+    return text
+
+
+def fix_toc_numbers(md):
+    """Avoid '4. 常见问题' in TOC being parsed as a new ordered list."""
+    def repl(m):
+        block = m.group(0)
+        block = re.sub(r"^(\d+)\.\s+", r"\1、", block, flags=re.M)
+        return block
+    return re.sub(r"(## 目录\n)([\s\S]*?)(?=\n## )", lambda m: m.group(1) + re.sub(r"^(\d+)\.\s+", r"\1、", m.group(2), flags=re.M), md, count=1)
+
+
+def main():
+    import shutil
+    # 分册 PDF + 刷新 docx
+    for fname, short, extra in FASCICLES:
+        md_path = ROOT / fname
+        md = fix_toc_numbers(md_path.read_text(encoding="utf-8"))
+        md_path.write_text(md, encoding="utf-8")
+        stem = fname[:-3]
+        html_body = md_to_html_body(md, skip_first_h1=False)
+        build_pdf(
+            "大洋MES 生产管理系统",
+            "——" + short + "——",
+            extra,
+            html_body,
+            "大洋MES · " + short + " · 分册",
+            ROOT / (stem + ".pdf"),
+        )
+        md_to_docx(md, ROOT / (stem + ".docx"))
+
+    # 对照说明
+    ch = (ROOT / "00-修订对照说明.md").read_text(encoding="utf-8")
+    build_pdf("大洋MES 操作手册", "修订对照说明", "相对 8.28 版本", md_to_html_body(ch), "大洋MES · 修订对照说明", ROOT / "00-修订对照说明.pdf")
+    md_to_docx(ch, ROOT / "00-修订对照说明.docx")
+
+    combined = build_combined_md()
+    build_pdf(
+        "大洋MES 生产管理系统\n操作手册合订版",
+        "——(MES 后台 + PDA + 工控机)——",
+        "分册合订 · 现行菜单与 PDA 1.0.6",
+        md_to_html_body(combined, skip_first_h1=True),
+        "大洋MES 生产管理系统 · 操作手册合订版",
+        ROOT / "大洋交付-操作手册合订版.pdf",
+    )
+    md_to_docx(combined, ROOT / "大洋交付-操作手册合订版.docx")
+
+    fen = ROOT / "分册"
+    he = ROOT / "合订版"
+    fen.mkdir(exist_ok=True)
+    he.mkdir(exist_ok=True)
+    for fname, short, extra in FASCICLES:
+        stem = fname[:-3]
+        for ext in (".pdf", ".docx", ".md"):
+            src = ROOT / (stem + ext)
+            if src.exists():
+                shutil.copy2(src, fen / src.name)
+    for name in ("大洋交付-操作手册合订版.pdf", "大洋交付-操作手册合订版.docx", "大洋交付-操作手册合订版.md"):
+        src = ROOT / name
+        if src.exists():
+            shutil.copy2(src, he / name)
+    for name in ("00-修订对照说明.pdf", "00-修订对照说明.docx", "00-修订对照说明.md"):
+        src = ROOT / name
+        if src.exists():
+            shutil.copy2(src, fen / name)
+            shutil.copy2(src, he / name)
+    chk = ROOT / "_pdf_check.txt"
+    if chk.exists():
+        chk.unlink()
+    print("done")
+
+
+if __name__ == "__main__":
+    main()

+ 36 - 0
_apk_work/dump_db.py

@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+import subprocess, os
+mysql = r"D:\mysql-5.7\mysql-5.7.24-winx64\bin\mysql.exe"
+out = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\extracted"
+base = [
+    mysql, "--user=root", "--password=123456", "--host=127.0.0.1", "--port=3306",
+    "--database=mes_cloud_ahdy", "--default-character-set=utf8mb4", "--batch", "--raw"
+]
+queries = {
+    "db_categories.txt": "SELECT id, title, sort_order, status FROM mes_icons_category ORDER BY sort_order, title",
+    "db_icons.txt": (
+        "SELECT IFNULL(c.title,'未分类') AS category, i.title AS icon, i.mode, i.auth, i.status "
+        "FROM mes_icons i LEFT JOIN mes_icons_category c ON c.id = i.category_id "
+        "WHERE i.status='0' ORDER BY IFNULL(c.sort_order,9999), i.title"
+    ),
+    "db_menus.txt": (
+        "SELECT tree_level, menu_name, menu_href, parent_code, menu_code "
+        "FROM js_sys_menu WHERE status='0' AND is_show='1' AND menu_type IN ('1','0') "
+        "ORDER BY tree_sorts, tree_sort"
+    ),
+    "db_hidden_menus.txt": (
+        "SELECT tree_level, menu_name, menu_href, is_show, status "
+        "FROM js_sys_menu WHERE menu_name LIKE '%扫码%' OR menu_name LIKE '%涂胶%' "
+        "OR menu_name LIKE '%恢复%' OR menu_name LIKE '%样件%' OR menu_name LIKE '%物料批次%' "
+        "OR menu_name LIKE '%钉钉%' OR menu_name LIKE '%GP12%' OR menu_name LIKE '%采购%' "
+        "OR menu_name LIKE '%上下限%' OR menu_name LIKE '%工具寿命%'"
+    ),
+}
+for fn, q in queries.items():
+    data = subprocess.check_output(base + ["--execute", q], stderr=subprocess.STDOUT)
+    if data.startswith(b"mysql:"):
+        data = data.split(b"\n", 1)[1]
+    path = os.path.join(out, fn)
+    with open(path, "wb") as f:
+        f.write(data)
+    print("wrote", fn, len(data))

+ 138 - 0
_apk_work/extract_manual_images.py

@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+"""Extract screenshots from 8.28 manuals with captions."""
+import os, re, json
+from pathlib import Path
+import fitz
+
+SRC = Path(r"D:\产线\大洋\大洋操作手册汇总8.28")
+OUT = Path(r"D:\产线\大洋\大洋操作手册汇总9.19\images")
+MIN_W, MIN_H = 180, 80
+MIN_PIXELS = 25000
+
+FASCICLES = [
+    "1、系统管理操作手册.pdf",
+    "2、设备管理操作手册.pdf",
+    "3、物料管理操作手册.pdf",
+    "4、质量管理操作手册.pdf",
+    "5、生产管理操作手册.pdf",
+    "6、ERP对接操作手册.pdf",
+    "7、生产线管理操作手册.pdf",
+    "8、PDA操作说明操作手册.pdf",
+    "9、MES系统客户端员工扫码操作手册.pdf",
+]
+
+
+def caption_from_page(page, img_bbox):
+    blocks = page.get_text("blocks")
+    texts = []
+    for b in blocks:
+        x0, y0, x1, y1, text, *_ = b[:6]
+        text = (text or "").strip()
+        if not text:
+            continue
+        # caption usually below image, short
+        texts.append((y0, y1, text.replace("\n", " ").strip()))
+    # find nearest text below image
+    below = [t for t in texts if t[0] >= img_bbox[3] - 8]
+    below.sort(key=lambda t: t[0])
+    for y0, y1, text in below[:3]:
+        t = re.sub(r"\s+", " ", text)
+        if 2 <= len(t) <= 40 and not t.startswith("第") and "PAGE" not in t:
+            if not re.match(r"^\d+(\.\d+)*\.?\s*$", t):
+                return t
+    # fallback: last short line above
+    above = [t for t in texts if t[1] <= img_bbox[1] + 8]
+    if above:
+        t = re.sub(r"\s+", " ", above[-1][2])
+        if 2 <= len(t) <= 50:
+            return t
+    return ""
+
+
+def heading_from_page(page):
+    blocks = page.get_text("blocks")
+    heads = []
+    for b in blocks:
+        text = (b[4] or "").strip()
+        if not text:
+            continue
+        first = text.split("\n")[0].strip()
+        if re.match(r"^\d+(\.\d+)*\.?\s+\S+", first) or first.startswith("3."):
+            heads.append(first)
+    return heads[0] if heads else ""
+
+
+def safe_name(s):
+    s = re.sub(r'[\\/:*?"<>|]', "", s)
+    s = re.sub(r"\s+", "_", s.strip())
+    return s[:40]
+
+
+def extract_one(pdf_name):
+    doc = fitz.open(SRC / pdf_name)
+    stem = pdf_name[:-4]
+    dest = OUT / stem
+    dest.mkdir(parents=True, exist_ok=True)
+    meta = []
+    seen_xref = {}
+    idx = 0
+    for pi, page in enumerate(doc, 1):
+        heading = heading_from_page(page)
+        images = page.get_images(full=True)
+        # also get image bboxes via dict
+        img_info = []
+        d = page.get_text("dict")
+        for block in d.get("blocks", []):
+            if block.get("type") != 1:
+                continue
+            bbox = block.get("bbox")
+            w = bbox[2] - bbox[0]
+            h = bbox[3] - bbox[1]
+            img_info.append((bbox, w, h))
+        # extract by xref, map to bbox by order
+        for ii, img in enumerate(images):
+            xref = img[0]
+            try:
+                pix = fitz.Pixmap(doc, xref)
+            except Exception:
+                continue
+            if pix.n - pix.alpha > 3:
+                pix = fitz.Pixmap(fitz.csRGB, pix)
+            if pix.width < MIN_W or pix.height < MIN_H or pix.width * pix.height < MIN_PIXELS:
+                continue
+            # skip near-duplicates of same xref on same page
+            key = (pi, xref, pix.width, pix.height)
+            if key in seen_xref:
+                continue
+            seen_xref[key] = True
+            bbox = img_info[ii][0] if ii < len(img_info) else (0, 0, pix.width, pix.height)
+            cap = caption_from_page(page, bbox)
+            idx += 1
+            fname = "%03d_p%02d_%s.png" % (idx, pi, safe_name(cap) or "img")
+            path = dest / fname
+            pix.save(str(path))
+            meta.append({
+                "file": str(path.relative_to(OUT.parent)).replace("\\", "/"),
+                "page": pi,
+                "caption": cap,
+                "heading": heading,
+                "w": pix.width,
+                "h": pix.height,
+            })
+    doc.close()
+    (dest / "manifest.json").write_text(json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8")
+    print(stem, "images", len(meta))
+    return meta
+
+
+def main():
+    OUT.mkdir(parents=True, exist_ok=True)
+    allm = {}
+    for name in FASCICLES:
+        allm[name] = extract_one(name)
+    (OUT / "all_manifest.json").write_text(json.dumps(allm, ensure_ascii=False, indent=2), encoding="utf-8")
+    print("total", sum(len(v) for v in allm.values()))
+
+
+if __name__ == "__main__":
+    main()

+ 478 - 0
_apk_work/extract_mes_icons_files.py

@@ -0,0 +1,478 @@
+# -*- coding: utf-8 -*-
+"""Extract mes_icons image mappings from large mysqldump; generate restore SQL."""
+from __future__ import print_function
+
+import os
+import re
+import sys
+
+DUMP = r"d:\产线\大洋\mes_cloud_20260919.sql\mes_cloud_20260919.sql"
+OUT_DIR = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\extracted"
+os.makedirs(OUT_DIR, exist_ok=True)
+
+CHUNK = 16 * 1024 * 1024
+
+
+def find_offsets(path, names):
+    needles = [(("INSERT INTO `%s`" % n).encode("ascii"), n) for n in names]
+    needles += [(("CREATE TABLE `%s`" % n).encode("ascii"), "CREATE:" + n) for n in names]
+    keep = max(len(n) for n, _ in needles)
+    buf = b""
+    pos = 0
+    found = []
+    with open(path, "rb") as f:
+        while True:
+            chunk = f.read(CHUNK)
+            if not chunk:
+                break
+            data = buf + chunk
+            base = pos - len(buf)
+            for needle, name in needles:
+                start = 0
+                while True:
+                    i = data.find(needle, start)
+                    if i < 0:
+                        break
+                    found.append((base + i, name))
+                    start = i + len(needle)
+            buf = data[-keep:]
+            pos += len(chunk)
+            if pos % (512 * 1024 * 1024) < CHUNK:
+                print("scanned %d MB, hits=%d" % (pos // (1024 * 1024), len(found)), flush=True)
+    seen = set()
+    out = []
+    for p, name in sorted(found):
+        if p in seen:
+            continue
+        seen.add(p)
+        out.append((p, name))
+    return out
+
+
+def read_until_stmt_end(path, offset, max_bytes=500 * 1024 * 1024):
+    """Read SQL statement starting at offset until top-level ');' end (string-aware)."""
+    with open(path, "rb") as f:
+        f.seek(offset)
+        parts = []
+        total = 0
+        in_str = False
+        prev = None
+        # We need to detect end: ) then ; outside string
+        # Process incrementally with a small rolling window of decoded... keep as bytes, track quote state for '
+        # MySQL dump uses \' escapes inside strings.
+        while total < max_bytes:
+            chunk = f.read(4 * 1024 * 1024)
+            if not chunk:
+                break
+            parts.append(chunk)
+            total += len(chunk)
+            data = b"".join(parts)
+            i = 0
+            # Re-scan whole each time is O(n^2) — better keep state across chunks
+            # Restart parse from 0 each time is bad for GB. Use stateful scan on new chunk only.
+            break
+        # Stateful:
+    with open(path, "rb") as f:
+        f.seek(offset)
+        out = bytearray()
+        in_str = False
+        total = 0
+        while total < max_bytes:
+            chunk = f.read(1024 * 1024)
+            if not chunk:
+                break
+            i = 0
+            while i < len(chunk):
+                c = chunk[i]
+                out.append(c)
+                total += 1
+                if in_str:
+                    if c == 0x5C and i + 1 < len(chunk):  # backslash
+                        out.append(chunk[i + 1])
+                        i += 2
+                        total += 1
+                        continue
+                    if c == 0x5C and i + 1 >= len(chunk):
+                        # escape at boundary: pull next byte
+                        nxt = f.read(1)
+                        if nxt:
+                            out.append(nxt[0])
+                            total += 1
+                        i += 1
+                        continue
+                    if c == 0x27:  # '
+                        in_str = False
+                    i += 1
+                    continue
+                else:
+                    if c == 0x27:
+                        in_str = True
+                        i += 1
+                        continue
+                    # end of statement: );
+                    if c == 0x3B and len(out) >= 2 and out[-2] == 0x29:  # );
+                        return out.decode("utf-8", "replace")
+                    i += 1
+        return out.decode("utf-8", "replace")
+
+
+def parse_create_columns(stmt):
+    m = re.search(r"CREATE TABLE `[^`]+`\s*\((.*)\)\s*ENGINE", stmt, re.S | re.I)
+    if not m:
+        return []
+    cols = []
+    for line in m.group(1).split("\n"):
+        cm = re.match(r"\s*`([^`]+)`\s+", line)
+        if cm:
+            cols.append(cm.group(1))
+    return cols
+
+
+def iter_value_rows(path, insert_offset):
+    """
+    Yield list-of-field-strings for each VALUES row of an INSERT statement.
+    Does not load whole statement into memory.
+    """
+    with open(path, "rb") as f:
+        f.seek(insert_offset)
+        # skip to VALUES
+        buf = b""
+        while True:
+            chunk = f.read(1024 * 1024)
+            if not chunk:
+                return
+            buf += chunk
+            m = re.search(br"\bVALUES\b", buf, re.I)
+            if m:
+                # position after VALUES
+                start_in_buf = m.end()
+                # leftover after VALUES
+                leftover = buf[start_in_buf:]
+                break
+            # keep tail
+            if len(buf) > 64:
+                buf = buf[-64:]
+
+        # Now stream leftover + rest of file for rows
+        def byte_iter(first):
+            for b in first:
+                yield b
+            while True:
+                ch = f.read(1024 * 1024)
+                if not ch:
+                    break
+                for b in ch:
+                    yield b
+
+        it = byte_iter(leftover)
+        # parse rows
+        try:
+            while True:
+                # skip whitespace and commas
+                c = next(it)
+                while c in (0x20, 0x09, 0x0A, 0x0D, 0x2C):
+                    c = next(it)
+                if c == 0x3B:  # ;
+                    return
+                if c != 0x28:  # (
+                    # unexpected
+                    return
+                fields = []
+                cur = bytearray()
+                in_str = False
+                while True:
+                    c = next(it)
+                    if in_str:
+                        if c == 0x5C:
+                            cur.append(c)
+                            cur.append(next(it))
+                            continue
+                        cur.append(c)
+                        if c == 0x27:
+                            in_str = False
+                        continue
+                    if c == 0x27:
+                        in_str = True
+                        cur.append(c)
+                        continue
+                    if c == 0x2C:  # ,
+                        fields.append(cur.decode("utf-8", "replace").strip())
+                        cur = bytearray()
+                        continue
+                    if c == 0x29:  # )
+                        fields.append(cur.decode("utf-8", "replace").strip())
+                        yield fields
+                        break
+                    cur.append(c)
+        except StopIteration:
+            return
+
+
+def unquote(s):
+    if s is None:
+        return None
+    s = s.strip()
+    if s.upper() == "NULL":
+        return None
+    if len(s) >= 2 and s[0] == "'" and s[-1] == "'":
+        inner = s[1:-1]
+        inner = (
+            inner.replace("\\\\", "\\")
+            .replace("\\'", "'")
+            .replace('\\"', '"')
+            .replace("\\n", "\n")
+            .replace("\\r", "\r")
+            .replace("\\t", "\t")
+            .replace("\\0", "\0")
+            .replace("\\Z", "\x1a")
+        )
+        return inner
+    return s
+
+
+def sql_quote(s):
+    if s is None:
+        return "NULL"
+    return "'" + str(s).replace("\\", "\\\\").replace("'", "''") + "'"
+
+
+def row_to_dict(fields, cols):
+    d = {}
+    for i, v in enumerate(fields):
+        key = cols[i] if i < len(cols) else "col%d" % i
+        d[key] = unquote(v)
+    return d
+
+
+def main():
+    size_gb = os.path.getsize(DUMP) / (1024.0 ** 3)
+    print("Dump size: %.2f GB" % size_gb, flush=True)
+    names = ["mes_icons", "js_sys_file_upload", "js_sys_file_entity"]
+    hits = find_offsets(DUMP, names)
+    for off, name in hits:
+        print("  %s @ %d" % (name, off), flush=True)
+
+    create_cols = {}
+    inserts = {}
+    for off, name in hits:
+        if name.startswith("CREATE:"):
+            t = name.split(":", 1)[1]
+            print("Reading CREATE %s..." % t, flush=True)
+            stmt = read_until_stmt_end(DUMP, off, max_bytes=200 * 1024)
+            create_cols[t] = parse_create_columns(stmt)
+            print("  cols=%d: %s" % (len(create_cols[t]), create_cols[t][:12]), flush=True)
+        else:
+            inserts[name] = off
+
+    icons_cols = create_cols.get("mes_icons") or []
+    upload_cols = create_cols.get("js_sys_file_upload") or []
+    entity_cols = create_cols.get("js_sys_file_entity") or []
+
+    # 1) Load mes_icons (small)
+    print("Loading mes_icons...", flush=True)
+    icons = []
+    for fields in iter_value_rows(DUMP, inserts["mes_icons"]):
+        icons.append(row_to_dict(fields, icons_cols))
+    print("  mes_icons rows=%d" % len(icons), flush=True)
+
+    # 2) Stream file_upload, keep only mesIcons_image
+    print("Scanning js_sys_file_upload for mesIcons_image...", flush=True)
+    biz_type_idx = upload_cols.index("biz_type") if "biz_type" in upload_cols else None
+    icon_uploads = []
+    n = 0
+    for fields in iter_value_rows(DUMP, inserts["js_sys_file_upload"]):
+        n += 1
+        if n % 200000 == 0:
+            print("  scanned upload rows=%d kept=%d" % (n, len(icon_uploads)), flush=True)
+        if biz_type_idx is not None:
+            bt = unquote(fields[biz_type_idx] if biz_type_idx < len(fields) else None)
+            if bt != "mesIcons_image":
+                continue
+        else:
+            # fallback: any field equals mesIcons_image
+            if not any(unquote(x) == "mesIcons_image" for x in fields):
+                continue
+        icon_uploads.append(row_to_dict(fields, upload_cols))
+    print("  upload total scanned=%d, mesIcons_image=%d" % (n, len(icon_uploads)), flush=True)
+
+    needed_ids = set(u["file_id"] for u in icon_uploads if u.get("file_id"))
+    print("  needed file_entity ids=%d" % len(needed_ids), flush=True)
+
+    # 3) Stream file_entity, keep needed
+    print("Scanning js_sys_file_entity for needed ids...", flush=True)
+    file_id_idx = entity_cols.index("file_id") if "file_id" in entity_cols else 0
+    entities = {}
+    n = 0
+    for fields in iter_value_rows(DUMP, inserts["js_sys_file_entity"]):
+        n += 1
+        if n % 200000 == 0:
+            print("  scanned entity rows=%d kept=%d" % (n, len(entities)), flush=True)
+        fid = unquote(fields[file_id_idx] if file_id_idx < len(fields) else None)
+        if fid in needed_ids:
+            entities[fid] = row_to_dict(fields, entity_cols)
+            if len(entities) == len(needed_ids):
+                print("  all needed entities found early at row %d" % n, flush=True)
+                break
+    print("  entity scanned=%d kept=%d / needed=%d" % (n, len(entities), len(needed_ids)), flush=True)
+
+    icon_by_id = {i["id"]: i for i in icons}
+
+    # Mapping TSV
+    map_path = os.path.join(OUT_DIR, "mes_icons_image_map_from_old.txt")
+    with open(map_path, "w", encoding="utf-8") as wf:
+        wf.write("icon_id\ttitle\tmode\tstatus\tupload_id\tfile_id\tfile_name\tfile_path\tfile_md5\text\tdisk_rel\n")
+        for u in sorted(icon_uploads, key=lambda x: (x.get("biz_key") or "", x.get("id") or "")):
+            e = entities.get(u.get("file_id") or "", {})
+            ic = icon_by_id.get(u.get("biz_key") or "", {})
+            path = (e.get("file_path") or "").replace("\\", "/")
+            md5 = e.get("file_md5") or ""
+            ext = e.get("file_extension") or ""
+            disk = ("%s%s.%s" % (path, md5, ext)) if ext else ("%s%s" % (path, md5))
+            wf.write(
+                "\t".join(
+                    [
+                        u.get("biz_key") or "",
+                        ic.get("title") or "",
+                        ic.get("mode") or "",
+                        ic.get("status") or "",
+                        u.get("id") or "",
+                        u.get("file_id") or "",
+                        u.get("file_name") or "",
+                        path,
+                        md5,
+                        ext,
+                        disk,
+                    ]
+                )
+                + "\n"
+            )
+    print("Wrote", map_path, flush=True)
+
+    # Restore SQL
+    sql_path = os.path.join(OUT_DIR, "restore_mes_icons_image_mapping.sql")
+    by_biz = {}
+    for u in icon_uploads:
+        by_biz.setdefault(u.get("biz_key"), []).append(u)
+
+    with open(sql_path, "w", encoding="utf-8") as wf:
+        wf.write("-- ============================================================\n")
+        wf.write("-- Restore PDA功能模块(mes_icons) 图片映射,来源: mes_cloud_20260919.sql\n")
+        wf.write("-- 关联: js_sys_file_upload.biz_key = mes_icons.id\n")
+        wf.write("--       js_sys_file_upload.biz_type = 'mesIcons_image'\n")
+        wf.write("--       js_sys_file_upload.file_id  = js_sys_file_entity.file_id\n")
+        wf.write("-- 注意: 还须把磁盘文件拷到新服务器 userfiles 下(见同目录 files_to_copy 列表)\n")
+        wf.write("-- ============================================================\n")
+        wf.write("SET NAMES utf8mb4;\nSTART TRANSACTION;\n\n")
+
+        wf.write("-- 1) 写入/覆盖老库中的文件实体\n")
+        for fid in sorted(needed_ids):
+            e = entities.get(fid)
+            if not e:
+                wf.write("-- WARN missing entity file_id=%s\n" % fid)
+                continue
+            size = e.get("file_size")
+            size_sql = size if size is not None else "NULL"
+            wf.write(
+                "INSERT INTO `js_sys_file_entity` "
+                "(`file_id`,`file_md5`,`file_path`,`file_content_type`,`file_extension`,`file_size`,`file_meta`,`file_preview`) "
+                "VALUES (%s,%s,%s,%s,%s,%s,%s,%s) "
+                "ON DUPLICATE KEY UPDATE "
+                "`file_md5`=VALUES(`file_md5`),`file_path`=VALUES(`file_path`),"
+                "`file_content_type`=VALUES(`file_content_type`),`file_extension`=VALUES(`file_extension`),"
+                "`file_size`=VALUES(`file_size`),`file_meta`=VALUES(`file_meta`),`file_preview`=VALUES(`file_preview`);\n"
+                % (
+                    sql_quote(e.get("file_id")),
+                    sql_quote(e.get("file_md5")),
+                    sql_quote(e.get("file_path")),
+                    sql_quote(e.get("file_content_type")),
+                    sql_quote(e.get("file_extension")),
+                    size_sql,
+                    sql_quote(e.get("file_meta")),
+                    sql_quote(e.get("file_preview")),
+                )
+            )
+
+        wf.write("\n-- 2) 按功能模块 id 替换图片绑定\n")
+        for biz_key in sorted(k for k in by_biz if k):
+            ic = icon_by_id.get(biz_key, {})
+            wf.write(
+                "\n-- id=%s title=%s mode=%s\n"
+                % (biz_key, ic.get("title") or "", ic.get("mode") or "")
+            )
+            wf.write(
+                "DELETE FROM `js_sys_file_upload` WHERE `biz_type`='mesIcons_image' AND `biz_key`=%s;\n"
+                % sql_quote(biz_key)
+            )
+            for u in by_biz[biz_key]:
+                sortv = u.get("file_sort")
+                sort_sql = sortv if sortv is not None else "NULL"
+                wf.write(
+                    "INSERT INTO `js_sys_file_upload` "
+                    "(`id`,`file_id`,`file_name`,`file_type`,`file_sort`,`biz_key`,`biz_type`,`status`,"
+                    "`create_by`,`create_date`,`update_by`,`update_date`,`remarks`) "
+                    "VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);\n"
+                    % (
+                        sql_quote(u.get("id")),
+                        sql_quote(u.get("file_id")),
+                        sql_quote(u.get("file_name")),
+                        sql_quote(u.get("file_type")),
+                        sort_sql,
+                        sql_quote(u.get("biz_key")),
+                        sql_quote(u.get("biz_type")),
+                        sql_quote(u.get("status") or "0"),
+                        sql_quote(u.get("create_by") or "system"),
+                        sql_quote(u.get("create_date")),
+                        sql_quote(u.get("update_by") or "system"),
+                        sql_quote(u.get("update_date")),
+                        sql_quote(u.get("remarks")),
+                    )
+                )
+
+        missing = [
+            i
+            for i in icons
+            if i.get("id") not in by_biz and (i.get("status") or "0") == "0"
+        ]
+        if missing:
+            wf.write("\n-- 老库中正常状态但无图片的模块(未改绑定):\n")
+            for i in missing:
+                wf.write(
+                    "--   id=%s title=%s mode=%s\n"
+                    % (i.get("id"), i.get("title"), i.get("mode"))
+                )
+
+        wf.write("\nCOMMIT;\n")
+        wf.write(
+            "\n-- 校验:\n"
+            "-- SELECT u.biz_key, i.title, i.mode, u.file_name, e.file_path, e.file_md5, e.file_extension\n"
+            "-- FROM js_sys_file_upload u\n"
+            "-- LEFT JOIN js_sys_file_entity e ON e.file_id = u.file_id\n"
+            "-- LEFT JOIN mes_icons i ON i.id = u.biz_key\n"
+            "-- WHERE u.biz_type = 'mesIcons_image'\n"
+            "-- ORDER BY i.title;\n"
+        )
+    print("Wrote", sql_path, flush=True)
+
+    files_list = os.path.join(OUT_DIR, "mes_icons_image_files_to_copy.txt")
+    seen = set()
+    with open(files_list, "w", encoding="utf-8") as wf:
+        wf.write("# 相对路径(位于 {file.baseDir}/userfiles/ 下)\n")
+        wf.write("# 实际文件名一般为: {file_path}{file_md5}.{file_extension}\n")
+        for u in icon_uploads:
+            e = entities.get(u.get("file_id") or "")
+            if not e:
+                continue
+            path = (e.get("file_path") or "").replace("\\", "/")
+            md5 = e.get("file_md5") or ""
+            ext = e.get("file_extension") or ""
+            rel = ("%s%s.%s" % (path, md5, ext)) if ext else ("%s%s" % (path, md5))
+            if rel in seen:
+                continue
+            seen.add(rel)
+            wf.write(rel + "\n")
+    print("Wrote %s (%d unique files)" % (files_list, len(seen)), flush=True)
+    print("DONE", flush=True)
+
+
+if __name__ == "__main__":
+    main()

+ 26 - 0
_apk_work/extract_pdfs.py

@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+import os, fitz
+
+src = r"D:\产线\大洋\大洋操作手册汇总8.28"
+out = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\manuals_text"
+os.makedirs(out, exist_ok=True)
+
+for name in os.listdir(src):
+    if not name.lower().endswith(".pdf"):
+        continue
+    path = os.path.join(src, name)
+    print("extracting", name)
+    doc = fitz.open(path)
+    parts = []
+    for i, page in enumerate(doc):
+        text = page.get_text("text")
+        parts.append("\n\n===== PAGE %d =====\n" % (i + 1))
+        parts.append(text)
+    base = os.path.splitext(name)[0]
+    # skip huge combined book last or still extract
+    dest = os.path.join(out, base + ".txt")
+    with open(dest, "w", encoding="utf-8") as f:
+        f.write("".join(parts))
+    print("  pages", doc.page_count, "chars", sum(len(p) for p in parts), "->", dest)
+    doc.close()
+print("done")

+ 79 - 0
_apk_work/extract_strings.py

@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+import os, re, sys, collections
+
+DEX_DIR = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\unzipped"
+OUT = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\extracted"
+os.makedirs(OUT, exist_ok=True)
+
+CN = re.compile(r"[\u4e00-\u9fff]{2,}")
+# printable ascii strings
+ASCII = re.compile(rb"[\x20-\x7e]{6,}")
+UTF16 = re.compile(rb"(?:[\x20-\x7e]\x00){4,}")
+
+keywords = (
+    "Activity", "Fragment", "menu", "Menu", "pda", "PDA", "http", "mes",
+    "scan", "Scan", "login", "Login", "com.", "/a/", "api"
+)
+
+all_cn = collections.Counter()
+ascii_hits = collections.Counter()
+utf16_cn = collections.Counter()
+urls = set()
+classes = set()
+
+def walk_files():
+    for root, dirs, files in os.walk(DEX_DIR):
+        for f in files:
+            p = os.path.join(root, f)
+            if f.endswith((".dex", ".xml", ".lst", ".txt", ".properties")) or "classes" in f:
+                yield p
+            elif f.endswith(".arsc"):
+                yield p
+
+for path in walk_files():
+    data = open(path, "rb").read()
+    # utf-8 / latin
+    try:
+        text = data.decode("utf-8", "ignore")
+    except Exception:
+        text = ""
+    for m in CN.findall(text):
+        if 2 <= len(m) <= 40:
+            all_cn[m] += 1
+    for m in ASCII.findall(data):
+        s = m.decode("ascii", "ignore")
+        if any(k in s for k in keywords):
+            ascii_hits[s] += 1
+        if s.startswith("http") or s.startswith("/a/") or "mes/" in s:
+            urls.add(s)
+        if "Activity" in s or "Fragment" in s:
+            classes.add(s)
+    for m in UTF16.findall(data):
+        try:
+            s = m.decode("utf-16le", "ignore")
+        except Exception:
+            continue
+        for c in CN.findall(s):
+            if 2 <= len(c) <= 40:
+                utf16_cn[c] += 1
+        if s.startswith("http") or "/a/" in s:
+            urls.add(s)
+
+def dump(name, items, n=None):
+    path = os.path.join(OUT, name)
+    with open(path, "w", encoding="utf-8") as f:
+        for i, item in enumerate(items):
+            if n is not None and i >= n:
+                break
+            if isinstance(item, tuple):
+                f.write("%s\t%s\n" % (item[0], item[1]))
+            else:
+                f.write("%s\n" % item)
+    print("wrote", path, "count", min(len(items), n or len(items)))
+
+dump("cn_strings.txt", all_cn.most_common())
+dump("utf16_cn.txt", utf16_cn.most_common())
+dump("ascii_hits.txt", ascii_hits.most_common(3000))
+dump("urls.txt", sorted(urls))
+dump("classes.txt", sorted(classes))
+print("cn unique", len(all_cn), "utf16 unique", len(utf16_cn), "urls", len(urls), "classes", len(classes))

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3000 - 0
_apk_work/extracted/ascii_hits.txt


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 8627 - 0
_apk_work/extracted/classes.txt


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2992 - 0
_apk_work/extracted/cn_strings.txt


+ 8 - 0
_apk_work/extracted/db_categories.txt

@@ -0,0 +1,8 @@
+id	title	sort_order	status
+2075123882678665216	HEV产线扫码	1	0
+2075123969815330816	ERP对接	2	0
+2075400585556545536	生产管理	3	0
+2075400750170394624	设备管理	4	0
+2075400793979899904	质量管理	5	0
+2075402085934583808	115产线扫码	7	0
+1000000000000000001	其他	9999	0

+ 45 - 0
_apk_work/extracted/db_config.txt

@@ -0,0 +1,45 @@
+config_key	config_value
+mes.batch.count	12
+mes.check.productSn	1
+mes.pass.oprno.xt	OP050,OP050A
+mes.batch.last.times	20
+mes.oprno.important	
+mes.universal.sn	0476966613765214
+mes.gp12.photograph	0
+mes.qm.check	0
+mes.bind.material.check	0
+mes.dhb.check	1
+mes.device.stop	0
+mes.qm.ng.time	1
+mes.alarm.verify	1
+mes.hlzl.second	90
+mes.search.days	3
+mes.log	1
+mes.oprno.dynamic	OP510
+mes.qm.oprnos	OP370,OP400,OP410
+mes.qm.nocheck	op410
+mes.qm.nong.time	OP170,OP410
+mes.xt.OP370.ok	0050011000300H7183335C290007
+mes.xt.OP370.ng	0050011000300H71833361300006
+mes.xt.OP400.ok	0050011000300H71833361310009
+mes.xt.OP400.ng	0050011000300H7183335C170020
+mes.tjTime	120
+mes.qm.css	3
+mes.jjTime	3
+mes.ccd.ng	0050011000300H7183335C170022
+mes.check.dj	OP110
+mes.OP430.jj.time	3
+mes.Hwtime.isOpen	1
+mes.xt.OP370.testNgRangeS	34
+mes.xt.OP370.testOkRangeE	-2
+mes.xt.OP370.testOkRangeS	5.5
+mes.xt.OP370.testNgRangeE	28
+mes.xt.OP400.testOkRangeS	5.5
+mes.xt.OP400.testOkRangeE	-2
+mes.xt.OP400.testNgRangeS	28
+mes.xt.OP400.testNgRangeE	22
+mes.email.controller	0
+mes.planCount	50
+mes.icons.grouped	1
+mes.check.one	1
+mes.check.oneOprno	HEVXT:OP150A,HEVXT:OP210A,115XT:OP130A,115XT:OP150A,115XT:OP070A,115XT:OP080A

+ 22 - 0
_apk_work/extracted/db_hidden_menus.txt

@@ -0,0 +1,22 @@
+tree_level	menu_name	menu_href	is_show	status
+1	恢复记录	/mes/mesRecover/list	1	2
+1	恢复生产		1	0
+1	工具寿命管理	/mes/mesToolLife/list	1	0
+1	工具寿命更换		1	0
+1	工位绑定物料批次	/mes/mesMaterialPrebind/list	1	2
+1	工具寿命更换记录	/mes/mesToolReplaceRecord/list	1	0
+1	工件GP12拍照		1	2
+1	框架涂胶拍照		1	1
+1	涂胶拍照		1	1
+1	GP12		1	2
+1	检测样件设置	/mes/mesProductSample/list	1	2
+1	检测样件记录	/mes/mesProductSampleRecord/list	0	0
+1	ERP采购订单查询	/mes/erpPurchaseOrder/list	1	0
+1	ERP采购入库单查询	/mes/erpInStock/list	1	0
+2	涂胶加工时长	/mes/mesProductGlueDuration/list	1	2
+1	PDA扫码记录	/mes/mesPdaScanRecord/list	1	2
+2	钉钉消息推送	/mes/mesDingMsgConfig/list	1	0
+1	GP12	/mes/mesProductGp12/list	1	0
+2	参数上下限维护	/mes/mesProcessParamLimit/list	1	0
+1	GP12		1	0
+1	GP12检查项	/mes/mesProductGp12Check/list	1	0

+ 47 - 0
_apk_work/extracted/db_icons.txt

@@ -0,0 +1,47 @@
+category	icon	mode	auth	status
+HEV产线扫码	HEVOP010镭雕	200	mes:mesOP010:api	0
+HEV产线扫码	HEVOP070电池壳分总成 1 点焊	204	mes:mesOP070:api	0
+HEV产线扫码	HEVOP080电池壳分总成 1 点焊补焊	205	mes:mesOP080:api	0
+HEV产线扫码	HEVOP090电池壳分总成 2 点焊	206	mes:mesOP090:api	0
+HEV产线扫码	HEVOP100电池壳分总成 2 点焊补焊	207	mes:mesOP100:api	0
+HEV产线扫码	HEVOP110电池壳分总成 3 点焊	208	mes:mesOP110:api	0
+HEV产线扫码	HEVOP120电池壳分总成 4 点焊	209	mes:mesOP120:api	0
+HEV产线扫码	HEVOP130电池壳分总成 5 点焊补焊	210	mes:mesOP130:api	0
+HEV产线扫码	HEVOP140电池壳分总成 6 弧焊	211	mes:mesOP140:api	0
+HEV产线扫码	HEVOP150电池壳分总成 7 弧焊	212	mes:mesOP150:api	0
+HEV产线扫码	HEVOP160电池壳分总成8弧焊	213	mes:mesOP160:api	0
+HEV产线扫码	HEVOP190A白件气密检测	214	mes:mesOP190:api	0
+HEV产线扫码	HEVOP190B白件气密检测	233	mes:mesOP190:api	0
+HEV产线扫码	HEVOP210拉铆	215	mes:mesOP210:api	0
+HEV产线扫码	HEVOP220总成气密检测	216	mes:mesOP220:api	0
+ERP对接	打包	231	mes:mesBatchSn:view	0
+ERP对接	生产入库	229	mes:erpPrdInStock:view	0
+ERP对接	生产领料	228	mes:erpPickMaterialBill:view	0
+ERP对接	直接调拨单	230	mes:erpTransferDirect:view	0
+生产管理	开班点检	240	mes:meslineKBDJ:api	0
+生产管理	打印	202	mes:mesOP050:api	0
+生产管理	汇报查询	234	mes:mesProductRecord:api	0
+设备管理	紧急性维修	18	mes:mesDeviceUrgency:api	0
+设备管理	预防性维护	19	mes:mesDevicePreventTask:api	0
+质量管理	GP12检验	241	mes:GP12:view	0
+质量管理	MES辅助	25	mes:mesProductRecord1:api	0
+质量管理	MES辅助修改记录	235	mes:mesProductModifyRecord:api	0
+质量管理	PDA首件检	238	mes:mesProd1Ckeck:api	0
+质量管理	不良处理	45	mes:mesRepair:api2	0
+质量管理	发货检	236	mes:mesBatchQuality:api	0
+质量管理	工具寿命更换	47	mes:mesToolReplaceRecord:api	0
+质量管理	报废	9	mes:mesProductScrap:api	0
+质量管理	抽检	27	mes:mesQuality:api	0
+质量管理	质量追溯	34	mes:mesProduct:api	0
+质量管理	返修	232	mes:mesRepair:api	0
+质量管理	返修检查	23	mes:mesRepairQuality:api	0
+质量管理	首件检确认	239	mes:oneqr:view	0
+115产线扫码	115OP010镭雕	217	mes:mes115OP010:api	0
+115产线扫码	115OP040左右边框总成	218	mes:mes115OP040:api	0
+115产线扫码	115OP060前后边框总成	219	mes:mes115OP060:api	0
+115产线扫码	115OP070总成框架拼焊-A	220	mes:mes115OP070:api	0
+115产线扫码	115OP080总成框架弧焊-B	221	mes:mes115OP080:api	0
+115产线扫码	115OP110白件气密检测	222	mes:mes115OP110:api	0
+115产线扫码	115OP130拉铆框架正面	223	mes:mes115OP130:api	0
+115产线扫码	115OP150液冷板装配拉铆	224	mes:mes115OP150:api	0
+115产线扫码	115OP180总成气密检测	225	mes:mes115OP180:api	0

+ 122 - 0
_apk_work/extracted/db_menus.txt

@@ -0,0 +1,122 @@
+tree_level	menu_name	menu_href	parent_code	menu_code
+0	系统管理		0	1582259822626603008
+1	组织管理		1582259822626603008	1582259826871238656
+2	用户管理	/sys/empUser/index	1582259826871238656	1582259826942541824
+2	员工信息管理	/mes/mesEmployee/list	1582259826871238656	mesEmployee
+2	机构管理	/sys/office/index	1582259826871238656	1582259827366166528
+2	岗位管理	/sys/post/list	1582259826871238656	1582259827630407680
+1	权限管理		1582259822626603008	1582259827773014016
+2	角色管理	/sys/role/list	1582259827773014016	1582259827814957056
+2	二级管理员	/sys/secAdmin/list	1582259827773014016	1582259827865288704
+2	租户管理员	/sys/corpAdmin/list	1582259827773014016	1582259827911426048
+1	系统设置		1582259822626603008	1582259828007895040
+2	菜单管理	/sys/menu/index	1582259828007895040	1582259828049838080
+2	参数设置	/sys/config/list	1582259828007895040	1582259828133724160
+2	字典管理	/sys/dictType/list	1582259828007895040	1582259828175667200
+2	功能模块分类	/mes/mesIconsCategory/list	1582259828007895040	mesIconsCategory
+2	功能模块	/mes/mesIcons/list	1582259828007895040	1676421052120719360
+2	安卓版本	/mes/mesApp/list	1582259828007895040	1689799527188008960
+2	客户端版本管理	/mes/mesClient/list	1582259828007895040	2059201212292587520
+2	钉钉消息推送	/mes/mesDingMsgConfig/list	1582259828007895040	mesDingMsgConfig
+2	jar包管理	/mes/mesClientUpgrade/list	1582259828007895040	2081650156451221504
+1	系统监控		1582259822626603008	1582259828507017216
+2	访问日志	/sys/log/list	1582259828507017216	1582259828548960256
+2	在线用户	/sys/online/list	1582259828507017216	1582259828750286848
+1	研发工具		1582259822626603008	1582259828976779264
+2	代码生成工具	/gen/genTable/list	1582259828976779264	1582259829010333696
+2	代码生成实例		1582259828976779264	1582259829052276736
+3	单表/主子表	/test/testData/list	1582259829052276736	1582259829094219776
+3	树表/树结构表	/test/testTree/list	1582259829052276736	1582259829144551424
+2	数据表格实例		1582259828976779264	1582259829211660288
+3	多表头分组小计合计	/demo/dataGrid/groupGrid	1582259829211660288	1582259829287157760
+3	编辑表格多行编辑	/demo/dataGrid/editGrid	1582259829211660288	1582259829329100800
+3	多表联动示例	/demo/dataGrid/multiGrid	1582259829211660288	1582259829366849536
+2	表单组件实例		1582259828976779264	1582259829400403968
+3	组件应用实例	/demo/form/editForm	1582259829400403968	1582259829433958400
+3	栅格布局实例	/demo/form/layoutForm	1582259829400403968	1582259829471707136
+3	表格表单实例	/demo/form/tableForm	1582259829400403968	1582259829513650176
+3	多页签应用示例	/demo/form/tabPage	1582259829400403968	1582259829559787520
+2	前端界面实例		1582259828976779264	1582259829614313472
+3	图标样式查找	//tags/iconselect	1582259829614313472	1582259829681422336
+1	文档管理		1582259822626603008	1696698845793292288
+2	文档类型管理	/mes/mesDocumentCate/list	1696698845793292288	1672118677579489280
+2	文档管理	/mes/mesDocument/list	1696698845793292288	1672124886409920512
+1	我的工作	/desktop/workbench	1582259829991800832	1582259830012772352
+1	关于我们	/desktop/about	1582259829991800832	1582259830046326784
+1	内容发布	/cms/index	1582259846450249728	1582259846475415552
+1	栏目管理	/cms/category/list	1582259846450249728	1582259846517358592
+1	站点设置	/cms/site/list	1582259846450249728	1582259846546718720
+1	模版管理	/cms/template/list	1582259846450249728	1582259846584467456
+0	设备管理		0	1582259848270577664
+1	基础信息		1582259848270577664	1692433921554501632
+2	设备分类	/mes/mesDeviceCate/list	1692433921554501632	1681834707716517888
+2	设备清单	/mes/mesDevice/list	1692433921554501632	1670611859729502208
+2	易耗品	/mes/mesDeviceConsumable/list	1692433921554501632	1670617516196806656
+2	易耗品记录	/mes/mesDeviceConsumableRecord/list	1692433921554501632	1670633317229928448
+1	预防性维护		1582259848270577664	1692048122847490048
+2	任务清单	/mes/mesDevicePrevent/list	1692048122847490048	1692054885933551616
+2	维护计划	/mes/mesDevicePreventTask/list	1692048122847490048	1692055045677813760
+2	我的维护计划	/mes/mesDevicePreventTask/mylist	1692048122847490048	1693424373231202304
+1	紧急性维修		1582259848270577664	1693423816215048192
+2	维修记录管理	/mes/mesDeviceUrgency/list	1693423816215048192	1670611886522716160
+2	我的维修记录	/mes/mesDeviceUrgency/mylist	1693423816215048192	1693425048161824768
+1	设备运行状态	/mes/mesDeviceState/list	1582259848270577664	1692004116580499456
+1	工具寿命管理	/mes/mesToolLife/list	1582259848270577664	1759420983356002304
+1	工具寿命更换记录	/mes/mesToolReplaceRecord/list	1582259848270577664	1797101310215589888
+0	物料管理		0	1667359431003865088
+1	物料总库存	/mes/mesMaterialKcTotal/list	1667359431003865088	mesMaterialKcTotal
+1	物料列表	/mes/mesMaterial/list	1667359431003865088	1773512685374181376
+1	来料库存记录	/mes/mesMaterialKcLog/list	1667359431003865088	1777946394836418560
+0	质量管理		0	1669218434433699840
+1	返修问题清单	/mes/mesRepairItems/list	1669218434433699840	1717346097626963968
+1	抽检记录	/mes/mesQuality/list	1669218434433699840	1726866658463903744
+1	返修记录	/mes/mesRepair/list	1669218434433699840	1717349275620364288
+1	报废记录	/mes/mesScrap/list	1669218434433699840	1728946177197289472
+1	首件检查记录	/mes/mesProductCheckFirst/list	1669218434433699840	1796152788824604672
+1	发货检记录	/mes/mesBatchQuality/list	1669218434433699840	mesBatchQuality
+1	GP12检查项	/mes/mesProductGp12Check/list	1669218434433699840	mesProductGp12Check
+1	GP12	/mes/mesProductGp12/list	1669218434433699840	2098339896428965888
+0	生产管理		0	1672118505143263232
+1	产品生产记录	/mes/mesProductRecord/list	1672118505143263232	1670635223128064000
+1	产品修改记录	/mes/mesProductModifyRecord/list	1672118505143263232	1866289761851342848
+1	加工消耗扣料日志	/mes/mesProcessConsumeLog/list	1672118505143263232	mesProcessConsumeLog
+1	大屏通知	/mes/mesScreenNotice/list	1672118505143263232	mesScreenNotice
+1	荣誉榜单	/mes/mesScreenHonor/list	1672118505143263232	mesScreenHonor
+1	产品管理	/mes/mesProduct/list	1672118505143263232	1670621400999313408
+1	工艺过程参数		1672118505143263232	2042038662094802944
+2	CCD视觉检测记录	/mes/mesProductCcd/list	2042038662094802944	1735472070091292672
+2	白件气密	/mes/mesProductQm/listWhitePart	2042038662094802944	1735472135350468608
+2	总成气密	/mes/mesProductQm/listAssembly	2042038662094802944	mesProductQmAssembly
+2	115拉铆框架正面	/mes/mesProductProd/list?oprno=OP130A&lineSn=115XT	2042038662094802944	1752212831940280320
+2	115弧焊参数	/mes/mesProductCmt/list	2042038662094802944	1796904137003200512
+2	HEV点焊参数	/mes/mesProductArcWelding/listSpot	2042038662094802944	2059200943810994176
+2	凸焊数据	/mes/mesWelderParamRecord/list	2042038662094802944	mesWelderParamRecord
+2	HEV弧焊参数	/mes/mesProductArcWelding/listArc	2042038662094802944	mesProductArcWeldingArc
+2	参数上下限维护	/mes/mesProcessParamLimit/list	2042038662094802944	2069800000000000000
+2	115液冷板装配拉铆	/mes/mesProductProd/list?oprno=OP150A&lineSn=115XT	2042038662094802944	2100129109350502400
+2	HEV拉铆	/mes/mesProductProd/list?oprno=OP210A&lineSn=HEVXT	2042038662094802944	2100129219237072896
+1	工位生产时间	/mes/mesDeviceTime/list	1672118505143263232	1693827878116536320
+1	工位当前产品	/mes/mesProcessProduct/list	1672118505143263232	1709768485367869440
+1	批次码记录表	/mes/mesBatchSn/list	1672118505143263232	1778585758407135232
+1	开班点检记录	/mes/mesProcessCheckRecord/list	1672118505143263232	1786192519127437312
+1	打印记录	/mes/mesOp050Record/list	1672118505143263232	2082747045724708864
+1	工资核算	/mes/mesPieceSalaryReport/list	1672118505143263232	2083358713959845888
+0	ERP对接		0	2069696607455440896
+1	ERP生产领料单查询	/mes/erpPickMaterialBill/list	2069696607455440896	erpPickMaterialBill
+1	ERP采购订单查询	/mes/erpPurchaseOrder/list	2069696607455440896	erpPurchaseOrder
+1	ERP采购入库单查询	/mes/erpInStock/list	2069696607455440896	erpInStock
+1	ERP生产订单查询	/mes/erpProductionOrder/list	2069696607455440896	erpProductionOrder
+1	ERP排产计划	/mes/mesErpSchedule/list	2069696607455440896	mesErpSchedule
+1	ERP直接调拨单查询	/mes/erpTransferDirect/list	2069696607455440896	erpTransferDirect
+1	ERP生产入库单查询	/mes/erpPrdInStock/list	2069696607455440896	erpPrdInStock
+1	生产入库批次绑定	/mes/mesErpPrdInstockLog/list	2069696607455440896	mesErpPrdInstockLog
+1	ERP下推日志	/mes/mesErpInteractionLog/list	2069696607455440896	mesErpInteractionLog
+1	ERP排产看板	/mes/mesErpSchedule/board	2069696607455440896	mesErpScheduleBoard
+0	生产线管理		0	1680784143702568960
+1	生产线管理	/mes/mesLine/list	1680784143702568960	1669219875734966272
+1	生产工位管理	/mes/mesLineProcess/list	1680784143702568960	1669223760170397696
+1	生产模板	/mes/mesTemplate/list	1680784143702568960	1686214906791092224
+1	工件类型	/mes/mesProductCate/list	1680784143702568960	1686215376427311104
+1	班次表	/mes/mesShift/list	1680784143702568960	1700685671751245824
+1	大屏管理	mes/mesScreenConfig/list	1680784143702568960	2061733136426876928
+1	大屏播放器	mes/mesScreenConfig/player	1680784143702568960	2061733293943963648

+ 60 - 0
_apk_work/extracted/db_process.txt

@@ -0,0 +1,60 @@
+line_sn	line_title	oprno	process_title	sorts	status	type
+115XT	115	OP010A	闀洉	0	0	NULL
+115XT	115	OP030A	鍑哥剨	0	0	NULL
+115XT	115	OP040A	宸﹀彸杈规鎬绘垚	0	0	NULL
+115XT	115	OP060A	鍓嶅悗杈规鎬绘垚	0	0	NULL
+115XT	115	OP070A	鎬绘垚妗嗘灦鎷肩剨-A	0	0	NULL
+115XT	115	OP080A	鎬绘垚妗嗘灦寮х剨-B	0	0	NULL
+115XT	115	OP110A	姘斿瘑妫€娴?0	0	NULL
+115XT	115	OP130A	鎷夐搯妗嗘灦姝i潰	0	0	NULL
+115XT	115	OP150A	娑插喎鏉胯閰嶆媺閾?0	0	NULL
+115XT	115	OP180A	鎬绘垚姘斿瘑妫€娴?0	0	NULL
+115XT	115	OP190A	鍦ㄧ嚎妫€娴?0	0	NULL
+115XT	115	OP390A	CCD	0	0	NULL
+115XT	115	OP390B	CCD	0	0	NULL
+115XT	115	OP010	闀洉	10	0	4
+115XT	115	OP030	鍑哥剨	30	0	3
+115XT	115	OP040	宸﹀彸杈规鎬绘垚	40	0	0
+115XT	115	OP060	鍓嶅悗杈规鎬绘垚	60	0	0
+115XT	115	OP070	鎬绘垚妗嗘灦鎷肩剨-A	70	0	0
+115XT	115	OP080	鎬绘垚妗嗘灦寮х剨-B	80	0	0
+115XT	115	OP110	鐧戒欢姘斿瘑妫€娴?110	0	0
+115XT	115	OP130	鎷夐搯妗嗘灦姝i潰	130	0	0
+115XT	115	OP140	娑傝兌	140	0	0
+115XT	115	OP150	娑插喎鏉胯閰嶆媺閾?150	0	0
+115XT	115	OP180	鎬绘垚姘斿瘑妫€娴?180	0	0
+115XT	115	OP390	CCD瑙嗚妫€娴?390	0	1
+HEVXT	HEV	OP010A	闀洉	0	0	NULL
+HEVXT	HEV	OP050A	鎵撳嵃	0	0	NULL
+HEVXT	HEV	OP060A	宸﹀彸鍚婅€崇粍浠剁偣鐒?0	0	NULL
+HEVXT	HEV	OP070A	鐢垫睜澹冲垎鎬绘垚1鐐圭剨	0	0	NULL
+HEVXT	HEV	OP080A	鐢垫睜澹冲垎鎬绘垚1鐐圭剨琛ョ剨	0	0	NULL
+HEVXT	HEV	OP090A	鐢垫睜澹冲垎鎬绘垚2鐐圭剨	0	0	NULL
+HEVXT	HEV	OP100A	鐢垫睜澹冲垎鎬绘垚2鐐圭剨琛ョ剨	0	0	NULL
+HEVXT	HEV	OP110A	鐢垫睜澹冲垎鎬绘垚3鐐圭剨	0	0	NULL
+HEVXT	HEV	OP120A	鐢垫睜澹冲垎鎬绘垚4鐐圭剨	0	0	NULL
+HEVXT	HEV	OP130A	鐢垫睜澹冲垎鎬绘垚5鐐圭剨琛ョ剨	0	0	NULL
+HEVXT	HEV	OP140A	鐢垫睜澹冲垎鎬绘垚6寮х剨	0	0	NULL
+HEVXT	HEV	OP150A	鐢垫睜澹冲垎鎬绘垚7寮х剨	0	0	NULL
+HEVXT	HEV	OP160A	鐢垫睜澹冲垎鎬绘垚8寮х剨	0	0	NULL
+HEVXT	HEV	OP190A	姘斿瘑妫€娴?0	0	NULL
+HEVXT	HEV	OP190B	鐧戒欢姘斿瘑妫€娴?0	0	NULL
+HEVXT	HEV	OP210A	鎷夐搯	0	0	NULL
+HEVXT	HEV	OP220A	鎬绘垚姘斿瘑妫€娴?0	0	NULL
+HEVXT	HEV	OP390A	ccd	0	0	NULL
+HEVXT	HEV	OP010	闀洉	10	0	4
+HEVXT	HEV	OP050	鎵撳嵃	50	0	3
+HEVXT	HEV	OP070	鐢垫睜澹冲垎鎬绘垚1鐐圭剨	70	0	0
+HEVXT	HEV	OP080	鐢垫睜澹冲垎鎬绘垚1鐐圭剨琛ョ剨	80	0	0
+HEVXT	HEV	OP090	鐢垫睜澹冲垎鎬绘垚2鐐圭剨	90	0	0
+HEVXT	HEV	OP100	鐢垫睜澹冲垎鎬绘垚2鐐圭剨琛ョ剨	100	0	0
+HEVXT	HEV	OP110	鐢垫睜澹冲垎鎬绘垚3鐐圭剨	110	0	0
+HEVXT	HEV	OP120	鐢垫睜澹冲垎鎬绘垚4鐐圭剨	120	0	0
+HEVXT	HEV	OP130	鐢垫睜澹冲垎鎬绘垚5鐐圭剨琛ョ剨	130	0	0
+HEVXT	HEV	OP140	鐢垫睜澹冲垎鎬绘垚6寮х剨	140	0	0
+HEVXT	HEV	OP150	鐢垫睜澹冲垎鎬绘垚7寮х剨	150	0	0
+HEVXT	HEV	OP160	鐢垫睜澹冲垎鎬绘垚8寮х剨	160	0	0
+HEVXT	HEV	OP190	鐧戒欢姘斿瘑妫€娴?190	0	0
+HEVXT	HEV	OP210	鎷夐搯	210	0	0
+HEVXT	HEV	OP220	鎬绘垚姘斿瘑妫€娴?220	0	1
+HEVXT	HEV	OP390	ccd	390	0	

BIN
_apk_work/extracted/extract_mes_icons_log.txt


+ 28 - 0
_apk_work/extracted/mes_icons_image_files_to_copy.txt

@@ -0,0 +1,28 @@
+# 拷到新服务器 {file.baseDir}/userfiles/ 下,保持相对路径
+files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+files1/202604/3075767d1c31dde8214bef1ade82a485.png
+files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+files1/202605/ddf9a09f5244fa53588f65354389a118.png
+files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png
+files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+files1/202607/491c4642bb309bcd02907fbc060812b1.png
+files1/202607/17d8fae4fed7ec9ebc3252c903720f40.png
+files1/202607/9f3220081c71a53e4069bd847b223b3a.png
+files1/202607/4575235bc7555828c969d515ef329728.png
+files1/202607/cafa130aca7d58987943f423acb29dd7.png
+files1/202607/4d4c9dfb1f7fb6b86dfe503a77a16fcc.png
+files1/202607/acbaff57bd755d21dc946532f074c866.png
+files1/202607/6e191a5fe709287d42f74af66d1e2e3a.png
+files1/202607/07dced747bf44b1eb732854d0f3d9452.png
+files1/202607/2f10b39d74803937eb1337c965e20efb.png
+files1/202607/aececec6e4902ce686c02f17ae0c752a.png
+files1/202607/03b41070da9492dce4d39b8a3d7dbe69.png
+files1/202607/fec1d4f6ede84199087e93c425bd844c.png
+files1/202608/fec1d4f6ede84199087e93c425bd844c.png
+files1/202608/4575235bc7555828c969d515ef329728.png
+files1/202608/2f10b39d74803937eb1337c965e20efb.png
+files1/202608/bbfbdaa0b381324d074fdeb9aacd50f8.png
+files1/202609/bd34249f6c19f4ef37c53a928f5b6e98.png
+files1/202609/39de4b60f6a8d768ae60a4e806d5e9b8.png
+files1/202609/393169b5e1a634c5398f3690f01f21a2.png
+files1/202609/e602ff50a67b021e8200d3c9693503fc.png

+ 114 - 0
_apk_work/extracted/mes_icons_image_map_current_only.txt

@@ -0,0 +1,114 @@
+icon_id	title	mode	icon_status	upload_id	file_id	file_name	file_path	file_md5	ext	disk_rel	update_date
+1676458476180168704	设备点检	1	2	2060590763032502273	2060590763032502272	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-06-03 11:16:40
+1693504849036443648	紧急性维修	18	0	2075472212578066433	2075472212578066432	紧急性维护.png	files1/202607/	aececec6e4902ce686c02f17ae0c752a	png	files1/202607/aececec6e4902ce686c02f17ae0c752a.png	2026-07-10 14:48:31
+1693505108391231488	预防性维护	19	0	2075472279338803201	2075472279338803200	预防性维护 .png	files1/202607/	03b41070da9492dce4d39b8a3d7dbe69	png	files1/202607/03b41070da9492dce4d39b8a3d7dbe69.png	2026-07-10 14:48:47
+1728947786721284096	报废记录	22	2	2075471147564589057	2075471147564589056	报废.png	files1/202607/	9f3220081c71a53e4069bd847b223b3a	png	files1/202607/9f3220081c71a53e4069bd847b223b3a.png	2026-07-10 14:44:18
+1733029906386014208	返修检查	23	0	2075471196910575617	2075471196910575616	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png	2026-07-11 15:14:01
+1735131463639654400	恢复生产	24	2	2075471082053754881	2075471082053754880	恢复.png	files1/202607/	17d8fae4fed7ec9ebc3252c903720f40	png	files1/202607/17d8fae4fed7ec9ebc3252c903720f40.png	2026-07-10 14:44:03
+1744167567379628032	设备工装	26	2	2060905868945317889	2060905868945317888	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-31 10:07:04
+1744167797504311297	抽检	27	0	2075472173810114561	2075472173810114560	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png	2026-07-10 14:48:22
+1759757875126980608	质量追溯	34	0	2075471239918968833	2075471239918968832	产品追溯.png	files1/202607/	cafa130aca7d58987943f423acb29dd7	png	files1/202607/cafa130aca7d58987943f423acb29dd7.png	2026-09-19 12:17:10
+1777980592925036544	入库管理	35	2	2032110802713563137	2032110802713563136	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png	2026-03-12 23:05:48
+1777980756737773568	出库管理	36	2	2041694866829680641	2041694866829680640	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png	2026-04-08 09:49:25
+1796352784753975296	来料报检	40	2	2060906150525722625	2060906150525722624	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-31 10:08:12
+1796352877641031680	首件检查	41	2	2075471278171021313	2075471278171021312	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png	2026-07-11 15:13:54
+1811640472306368512	MES辅助	25	0	2075471827322855425	2075471827322855424	转发,流转,旋转.png	files1/202607/	2f10b39d74803937eb1337c965e20efb	png	files1/202607/2f10b39d74803937eb1337c965e20efb.png	2026-07-11 15:14:18
+1815195808698114048	GP12拍照	44	2	2048299087549280257	2048299087549280256	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png	2026-05-26 16:01:03
+1815561111483330560	不良处理	45	0	2075471027771072513	2075471027771072512	报不良.png	files1/202607/	491c4642bb309bcd02907fbc060812b1	png	files1/202607/491c4642bb309bcd02907fbc060812b1.png	2026-07-30 08:59:03
+1852155649429696512	工具寿命更换	47	0	2075471789284712449	2075471789284712448	currency-生产维修工单.png	files1/202607/	07dced747bf44b1eb732854d0f3d9452	png	files1/202607/07dced747bf44b1eb732854d0f3d9452.png	2026-07-10 14:46:50
+1871129621552787456	工件入库	50	2	2060590483784130561	2060590483784130560	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-30 13:13:51
+1909774845221371904	漏点补焊	51	2	2032111060113805313	2032111060113805312	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png	2026-03-12 23:06:47
+1912831403259744256	不良上报	52	2	2041692473580789761	2041692473580789760	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png	2026-04-08 09:39:56
+1912831570910269440	维修	53	2	2060906819345244161	2060906819345244160	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-31 10:10:51
+1912831959340568576	返修记录	54	2	2041694146583797761	2041694146583797760	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png	2026-04-08 09:46:33
+1912832146297475072	返修审核	55	2	2041699438121472001	2041699438121472000	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png	2026-04-08 10:07:35
+1916603628886962176	底护板绑定	56	2	2032110859894509569	2032110859894509568	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png	2026-03-12 23:06:00
+1924278376214405120	禁用设备	57	2	2060590378041532417	2060590378041532416	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-30 13:13:26
+1927526300241469440	报警处理	58	2	2060590423470039041	2060590423470039040	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-30 13:13:40
+1937787743392026624	解绑工件	59	2	2041693128538136577	2041693128538136576	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png	2026-04-08 09:42:31
+2008045568203612160	GP12	60	2	2048299752086417409	2048299752086417408	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png	2026-04-26 15:14:52
+2039245063986479104	CCD复测	89	2	2060906600075419649	2060906600075419648	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-31 10:09:58
+2041753218108116992	OP380底护板安装	90	2	2041753212198342657	2041753212198342656	1972113784531521536.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png	2026-04-08 13:41:16
+2042204468847316992	恒温静置	88	2	2042204462631358465	2042204462631358464	1972113784531521536.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png	2026-04-09 19:34:22
+2055099103921139712	HEVOP010镭雕	200	0	2075472449078091777	2075472449078091776	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:49:28
+2055099663919443968	HEVOP030凸焊	201	1	2055099659238600705	2055099659238600704	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-15 10:16:30
+2055100722444333056	HEVOP030凸焊	201	2	2055100717897707521	2055100717897707520	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-15 10:12:33
+2055101313237217280	HEVOP060左右吊耳组件点焊	203	2	2075472519676616705	2075472519676616704	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:49:44
+2055101811688304640	HEVOP070电池壳分总成 1 点焊	204	0	2075472571706957825	2075472571706957824	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:49:57
+2055102191365091328	HEVOP080电池壳分总成 1 点焊补焊	205	0	2075472741651767297	2075472741651767296	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:50:37
+2055102400157544448	HEVOP090电池壳分总成 2 点焊	206	0	2075472330458980353	2075472330458980352	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:48:59
+2055102592025980928	HEVOP100电池壳分总成 2 点焊补焊	207	0	2075472787218685953	2075472787218685952	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:50:48
+2055102841721286656	HEVOP110电池壳分总成 3 点焊	208	0	2075472876825796609	2075472876825796608	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:51:09
+2055103002711257088	HEVOP120电池壳分总成 4 点焊	209	0	2075470926512185345	2075470926512185344	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:43:26
+2055103158730977280	HEVOP130电池壳分总成 5 点焊补焊	210	0	2075472909197434881	2075472909197434880	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:51:17
+2055103410875756544	HEVOP140电池壳分总成 6 弧焊	211	0	2075473011978854401	2075473011978854400	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:51:42
+2055103587430789120	HEVOP150电池壳分总成 7 弧焊	212	0	2075473043520020481	2075473043520020480	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:51:49
+2055103750283030528	HEVOP160电池壳分总成8弧焊	213	0	2075473130086260737	2075473130086260736	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:52:10
+2055104128126906368	HEVOP190A白件气密检测	214	0	2075473172616503298	2075473172616503297	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-21 09:11:51
+2055104298524700672	HEVOP210拉铆	215	0	2075473208016429057	2075473208016429056	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:52:29
+2055104458021498880	HEVOP220总成气密检测	216	0	2075473239930888192	2075473239926693888	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:52:36
+2055107245774041088	115OP010镭雕	217	0	2075473271870513153	2075473271870513152	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-11 15:13:06
+2055107492160040960	115OP040左右边框总成	218	0	2075473315851984897	2075473315851984896	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:52:54
+2055107872222703616	115OP060前后边框总成	219	0	2075473445225291777	2075473445225291776	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:53:25
+2055108029320359936	115OP070总成框架拼焊-A	220	0	2075473476783235073	2075473476783235072	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:53:33
+2055109345304211456	打印	202	0	2075472487728603137	2075472487728603136	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-13 09:29:32
+2055110761007640576	115OP080总成框架弧焊-B	221	0	2075473512497733633	2075473512497733632	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:53:41
+2055111168886927360	115OP110白件气密检测	222	0	2075473552951795714	2075473552951795713	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-13 13:57:35
+2055111456809119744	115OP130拉铆框架正面	223	0	2075473711496486913	2075473711496486912	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:54:29
+2055111609590837248	115OP150液冷板装配拉铆	224	0	2075473744535019521	2075473744535019520	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:54:37
+2055111801694154752	115OP180总成气密检测	225	0	2075473788399050753	2075473788399050752	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:54:47
+2055112013066104832	115OP190在线检测	226	2	2075473820640665601	2075473820640665600	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-10 14:54:55
+2056554322425556992	设备维保	1	2	2056554300225105921	2056554300225105920	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-07-10 10:11:03
+2056554677582442496	质量检查	2	2	2056554674210222081	2056554674210222080	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 09:56:59
+2056555575796838400	下线目视检查	3	2	2056555571497676801	2056555571497676800	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:00:33
+2056555756592312320	返修	4	2	2056555753886986241	2056555753886986240	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-07-10 10:11:14
+2056556129067479040	物料入库	5	2	2056556126085328897	2056556126085328896	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:02:45
+2056556300576763904	物料出库	6	2	2056556293240926209	2056556293240926208	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:03:26
+2056556815054286848	产品用料	7	2	2056556811573014529	2056556811573014528	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:05:28
+2056557069493350400	成品批次入库	8	2	2056557067417169921	2056557067417169920	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:06:29
+2056557268030730240	报废	9	0	2092510050241404929	2092510050241404928	ashbin.png	files1/202608/	bbfbdaa0b381324d074fdeb9aacd50f8	png	files1/202608/bbfbdaa0b381324d074fdeb9aacd50f8.png	2026-08-26 15:10:50
+2056557453662236672	返修审核	10	2	2056557449488904193	2056557449488904192	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:08:01
+2056557686303502336	返工审核	11	2	2056557681148702720	2056557681144508416	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:08:56
+2056557873323323392	返工SOP	12	2	2056557869800108033	2056557869800108032	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:09:41
+2056558144317304832	返修SOP	13	2	2056558131482734593	2056558131482734592	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:10:45
+2056558433900441600	返工复检	14	2	2056558429194432513	2056558429194432512	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:11:54
+2056558784087076864	返修复检	15	2	2056558778810642433	2056558778810642432	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:13:18
+2056559509533896704	返修让步接收	16	2	2056559506501414913	2056559506501414912	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:16:11
+2056559704027967488	让步入库审核	17	2	2056559699221295105	2056559699221295104	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:16:57
+2056559931136946176	紧急性维修	18	1	2056559928020578305	2056559928020578304	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:17:51
+2056560068454264832	预防性维护	19	1	2056560065870573569	2056560065870573568	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:18:24
+2056560236209647616	生产管理返修	20	2	2056560228680871937	2056560228680871936	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:19:04
+2056560493320482816	OP110	21	2	2056560489595940865	2056560489595940864	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:20:05
+2056560657867223040	报废记录	22	1	2056560654193012737	2056560654193012736	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:20:45
+2056561115256074240	返修检查	23	1	2056561111430868993	2056561111430868992	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:22:34
+2056561762579787776	恢复生产	24	1	2056561759274676225	2056561759274676224	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:25:08
+2056561918779863040	MES辅助	25	1	2056561915835461633	2056561915835461632	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:25:45
+2056562172010967040	设备工装	26	1	2056562169372749825	2056562169372749824	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:26:46
+2056562379939393536	抽检	27	1	2056562375136915457	2056562375136915456	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:27:35
+2056562635351535616	箱体OP050	28	2	2056562631228534785	2056562631228534784	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 10:28:36
+2056575342603677696	箱体OP070	29	2	2056575339625721857	2056575339625721856	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:19:06
+2056575763208482816	箱体OP290	30	2	2056575757663612929	2056575757663612928	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:20:46
+2056575984139251712	冷板OP120	31	2	2056575980855111681	2056575980855111680	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:21:39
+2056576269515501568	NG处理	32	2	2056576264725606401	2056576264725606400	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:22:47
+2056576444413784064	周期性维护	33	2	2056576439477088257	2056576439477088256	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:23:28
+2056577957794164736	IQC检测	37	2	2056577953276899329	2056577953276899328	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-27 15:14:13
+2056578375563620352	成品出货	38	2	2056578372594053121	2056578372594053120	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:31:09
+2056578525371576320	批次解绑	39	2	2056578521714143233	2056578521714143232	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png	2026-05-19 11:31:44
+2059171432658120704	入库管理	35	2	2059171418967912449	2059171418967912448	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png	2026-05-26 15:20:14
+2059171528892231680	出库管理	36	2	2059171525201244161	2059171525201244160	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png	2026-05-26 15:20:10
+2059174587043164160	成品入库	42	2	2059174532777259009	2059174532777259008	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png	2026-05-26 15:27:34
+2059174771756118016	成品出货	38	2	2059174766966222849	2059174766966222848	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png	2026-05-26 15:28:18
+2072243445574942720	来料检	227	2	2075471312673366017	2075471312673366016	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png	2026-07-10 15:30:42
+2072565056097198080	生产领料	228	0	2075471377836072961	2075471377836072960	生产入库.png	files1/202607/	4d4c9dfb1f7fb6b86dfe503a77a16fcc	png	files1/202607/4d4c9dfb1f7fb6b86dfe503a77a16fcc.png	2026-07-10 14:45:13
+2072856530422153216	生产入库	229	0	2075472407596425217	2075472407596425216	生产入库.png	files1/202607/	4d4c9dfb1f7fb6b86dfe503a77a16fcc	png	files1/202607/4d4c9dfb1f7fb6b86dfe503a77a16fcc.png	2026-07-10 14:49:18
+2074368075992731648	直接调拨单	230	0	2075472372079058945	2075472372079058944	调拨单.png	files1/202607/	fec1d4f6ede84199087e93c425bd844c	png	files1/202607/fec1d4f6ede84199087e93c425bd844c.png	2026-07-10 14:49:09
+2074786819844612096	打包	231	0	2075471503556141057	2075471503556141056	集成打包.png	files1/202607/	6e191a5fe709287d42f74af66d1e2e3a	png	files1/202607/6e191a5fe709287d42f74af66d1e2e3a.png	2026-07-11 15:13:32
+2074786917819359232	返修	232	0	2075471435142848513	2075471435142848512	返修.png	files1/202607/	acbaff57bd755d21dc946532f074c866	png	files1/202607/acbaff57bd755d21dc946532f074c866.png	2026-07-10 14:45:26
+2079031276184727552	HEVOP190B白件气密检测	233	0	2079031089466896385	2079031089466896384	2075473172616503297.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png	2026-07-20 10:30:57
+2085624372223152128	汇报查询	234	0	2085624355160723457	2085624355160723456	调拨单.png	files1/202608/	fec1d4f6ede84199087e93c425bd844c	png	files1/202608/fec1d4f6ede84199087e93c425bd844c.png	2026-09-19 12:16:48
+2089545591848103936	MES辅助修改记录	235	0	2092506248876580865	2092506248876580864	2075471827322855424.png	files1/202608/	2f10b39d74803937eb1337c965e20efb	png	files1/202608/2f10b39d74803937eb1337c965e20efb.png	2026-08-26 14:55:44
+2090000000000000235	发货检	236	0	2092505903379177473	2092505903379177472	2075472173810114560 (1).png	files1/202608/	4575235bc7555828c969d515ef329728	png	files1/202608/4575235bc7555828c969d515ef329728.png	2026-08-26 14:54:23
+2099454537145536512	PDA首件检	238	0	2101196827405029377	2101196827405029376	shoujianjian.png	files1/202609/	393169b5e1a634c5398f3690f01f21a2	png	files1/202609/393169b5e1a634c5398f3690f01f21a2.png	2026-09-19 14:28:58
+2100025671279136768	首件检确认	239	0	2101197449537753089	2101197449537753088	shoujianjianqueren.png	files1/202609/	e602ff50a67b021e8200d3c9693503fc	png	files1/202609/e602ff50a67b021e8200d3c9693503fc.png	2026-09-19 14:31:27
+2100025890246971392	GP12检验	241	0	2101196732911554561	2101196732911554560	GP12jianyan.png	files1/202609/	39de4b60f6a8d768ae60a4e806d5e9b8	png	files1/202609/39de4b60f6a8d768ae60a4e806d5e9b8.png	2026-09-19 14:28:36
+2100026067586338816	开班点检	240	0	2101196661214121985	2101196661214121984	kaibandianjian.png	files1/202609/	bd34249f6c19f4ef37c53a928f5b6e98	png	files1/202609/bd34249f6c19f4ef37c53a928f5b6e98.png	2026-09-19 14:28:20

+ 229 - 0
_apk_work/extracted/mes_icons_image_map_from_old.txt

@@ -0,0 +1,229 @@
+icon_id	title	mode	status	upload_id	file_id	file_name	file_path	file_md5	ext	disk_rel
+1676458476180168704	设备点检	1	2	2032111295191961601	2032111295191961600	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1676458476180168704	设备点检	1	2	2041692943774851073	2041692943774851072	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1676458476180168704	设备点检	1	2	2060590763032502273	2060590763032502272	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1693504849036443648	紧急性维修	18	0	2032111320995319809	2032111320995319808	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1693504849036443648	紧急性维修	18	0	2041692899227148289	2041692899227148288	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1693504849036443648	紧急性维修	18	0	2060590527182594049	2060590527182594048	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1693504849036443648	紧急性维修	18	0	2075472212578066433	2075472212578066432	紧急性维护.png	files1/202607/	aececec6e4902ce686c02f17ae0c752a	png	files1/202607/aececec6e4902ce686c02f17ae0c752a.png
+1693505108391231488	预防性维护	19	0	2032111349231374337	2032111349231374336	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1693505108391231488	预防性维护	19	0	2041692719849349121	2041692719849349120	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1693505108391231488	预防性维护	19	0	2060590572292333569	2060590572292333568	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1693505108391231488	预防性维护	19	0	2075472279338803201	2075472279338803200	预防性维护 .png	files1/202607/	03b41070da9492dce4d39b8a3d7dbe69	png	files1/202607/03b41070da9492dce4d39b8a3d7dbe69.png
+1728947786721284096	报废记录	22	2	2032111376657928193	2032111376657928192	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1728947786721284096	报废记录	22	2	2041692653126361089	2041692653126361088	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1728947786721284096	报废记录	22	2	2048300025286602753	2048300025286602752	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1728947786721284096	报废记录	22	2	2060905699206029313	2060905699206029312	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1728947786721284096	报废记录	22	2	2075471147564589057	2075471147564589056	报废.png	files1/202607/	9f3220081c71a53e4069bd847b223b3a	png	files1/202607/9f3220081c71a53e4069bd847b223b3a.png
+1733029906386014208	返修检查	23	0	2041703214475661313	2041703214475661312	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1733029906386014208	返修检查	23	0	2048298869743267841	2048298869743267840	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1733029906386014208	返修检查	23	0	2060906492881592321	2060906492881592320	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1733029906386014208	返修检查	23	0	2075471196910575617	2075471196910575616	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png
+1735131463639654400	恢复生产	24	2	2032111402150907905	2032111402150907904	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1735131463639654400	恢复生产	24	2	2041692610667421697	2041692610667421696	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1735131463639654400	恢复生产	24	2	2048300090784854017	2048300090784854016	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1735131463639654400	恢复生产	24	2	2060905597422854145	2060905597422854144	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1735131463639654400	恢复生产	24	2	2075471082053754881	2075471082053754880	恢复.png	files1/202607/	17d8fae4fed7ec9ebc3252c903720f40	png	files1/202607/17d8fae4fed7ec9ebc3252c903720f40.png
+1744167567379628032	设备工装	26	2	2032110495623401473	2032110495623401472	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1744167567379628032	设备工装	26	2	2041694808805679105	2041694808805679104	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1744167567379628032	设备工装	26	2	2041699021119574017	2041699021119574016	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1744167567379628032	设备工装	26	2	2048299549333762049	2048299549333762048	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1744167567379628032	设备工装	26	2	2060905868945317889	2060905868945317888	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1744167797504311297	抽检	27	0	2032111096797188097	2032111096797188096	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1744167797504311297	抽检	27	0	2041693493937512449	2041693493937512448	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1744167797504311297	抽检	27	0	2048299871468892161	2048299871468892160	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1744167797504311297	抽检	27	0	2060905775345229825	2060905775345229824	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1744167797504311297	抽检	27	0	2075472173810114561	2075472173810114560	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png
+1759757875126980608	质量追溯	34	0	2032110549222412289	2032110549222412288	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1759757875126980608	质量追溯	34	0	2041694721828397057	2041694721828397056	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1759757875126980608	质量追溯	34	0	2041699060034326529	2041699060034326528	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1759757875126980608	质量追溯	34	0	2048299364272680961	2048299364272680960	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1759757875126980608	质量追溯	34	0	2060906906263805953	2060906906263805952	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1759757875126980608	质量追溯	34	0	2075471239918968833	2075471239918968832	产品追溯.png	files1/202607/	cafa130aca7d58987943f423acb29dd7	png	files1/202607/cafa130aca7d58987943f423acb29dd7.png
+1777980592925036544	入库管理	35	2	2032110802713563137	2032110802713563136	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1777980756737773568	出库管理	36	2	2032110751836655617	2032110751836655616	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1777980756737773568	出库管理	36	2	2041694866829680641	2041694866829680640	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1796352784753975296	来料报检	40	2	2032110592369217537	2032110592369217536	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1796352784753975296	来料报检	40	2	2041694673904279553	2041694673904279552	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1796352784753975296	来料报检	40	2	2041699105299255297	2041699105299255296	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1796352784753975296	来料报检	40	2	2048299298464051201	2048299298464051200	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1796352784753975296	来料报检	40	2	2060906150525722625	2060906150525722624	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1796352877641031680	首件检查	41	2	2032110643028021249	2032110643028021248	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1796352877641031680	首件检查	41	2	2041694612940070913	2041694612940070912	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1796352877641031680	首件检查	41	2	2041699151008780289	2041699151008780288	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1796352877641031680	首件检查	41	2	2048299165408145409	2048299165408145408	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1796352877641031680	首件检查	41	2	2060906994348384257	2060906994348384256	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1796352877641031680	首件检查	41	2	2075471278171021313	2075471278171021312	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png
+1811640472306368512	MES辅助	25	0	2032110461167194113	2032110461167194112	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1811640472306368512	MES辅助	25	0	2041694919346561025	2041694919346561024	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1811640472306368512	MES辅助	25	0	2041698948528754689	2041698948528754688	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1811640472306368512	MES辅助	25	0	2048299408514199553	2048299408514199552	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1811640472306368512	MES辅助	25	0	2060905947739512833	2060905947739512832	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1811640472306368512	MES辅助	25	0	2075471827322855425	2075471827322855424	转发,流转,旋转.png	files1/202607/	2f10b39d74803937eb1337c965e20efb	png	files1/202607/2f10b39d74803937eb1337c965e20efb.png
+1815195808698114048	GP12拍照	44	2	2032110681577869313	2032110681577869312	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1815195808698114048	GP12拍照	44	2	2041694547387293697	2041694547387293696	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1815195808698114048	GP12拍照	44	2	2041699225147297793	2041699225147297792	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1815195808698114048	GP12拍照	44	2	2048299087549280257	2048299087549280256	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1815561111483330560	不良处理	45	0	2041703052453892097	2041703052453892096	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1815561111483330560	不良处理	45	0	2048298927859544065	2048298927859544064	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1815561111483330560	不良处理	45	0	2060590125208887297	2060590125208887296	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1815561111483330560	不良处理	45	0	2075471027771072513	2075471027771072512	报不良.png	files1/202607/	491c4642bb309bcd02907fbc060812b1	png	files1/202607/491c4642bb309bcd02907fbc060812b1.png
+1852155649429696512	工具寿命更换	47	0	2032110713962090497	2032110713962090496	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1852155649429696512	工具寿命更换	47	0	2041694491447861249	2041694491447861248	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1852155649429696512	工具寿命更换	47	0	2041699268940025857	2041699268940025856	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1852155649429696512	工具寿命更换	47	0	2048298995043905537	2048298995043905536	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1852155649429696512	工具寿命更换	47	0	2060907079631167490	2060907079631167489	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1852155649429696512	工具寿命更换	47	0	2075471789284712449	2075471789284712448	currency-生产维修工单.png	files1/202607/	07dced747bf44b1eb732854d0f3d9452	png	files1/202607/07dced747bf44b1eb732854d0f3d9452.png
+1871129621552787456	工件入库	50	2	2032111265034915841	2032111265034915840	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1871129621552787456	工件入库	50	2	2041693001454919681	2041693001454919680	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1871129621552787456	工件入库	50	2	2060590483784130561	2060590483784130560	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1909774845221371904	漏点补焊	51	2	2032111060113805313	2032111060113805312	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1912831403259744256	不良上报	52	2	2032111021408768001	2032111021408768000	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1912831403259744256	不良上报	52	2	2034098595135991809	2034098595135991808	1972113784531521536.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1912831403259744256	不良上报	52	2	2041692473580789761	2041692473580789760	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1912831570910269440	维修	53	2	2032110982137499649	2032110982137499648	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1912831570910269440	维修	53	2	2041693540649476097	2041693540649476096	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1912831570910269440	维修	53	2	2048299602291044353	2048299602291044352	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+1912831570910269440	维修	53	2	2060906819345244161	2060906819345244160	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1912831959340568576	返修记录	54	2	2032110927162757121	2032110927162757120	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1912831959340568576	返修记录	54	2	2041694146583797761	2041694146583797760	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1912832146297475072	返修审核	55	2	2032110893042094081	2032110893042094080	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1912832146297475072	返修审核	55	2	2041694208206512129	2041694208206512128	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1912832146297475072	返修审核	55	2	2041699438121472001	2041699438121472000	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1916603628886962176	底护板绑定	56	2	2032110859894509569	2032110859894509568	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1924278376214405120	禁用设备	57	2	2032111123389075457	2032111123389075456	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1924278376214405120	禁用设备	57	2	2041693349489876993	2041693349489876992	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1924278376214405120	禁用设备	57	2	2060590378041532417	2060590378041532416	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1927526300241469440	报警处理	58	2	2032111150710771713	2032111150710771712	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1927526300241469440	报警处理	58	2	2041693213749616641	2041693213749616640	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+1927526300241469440	报警处理	58	2	2060590423470039041	2060590423470039040	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+1937787743392026624	解绑工件	59	2	2032111190263058433	2032111190263058432	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+1937787743392026624	解绑工件	59	2	2041693128538136577	2041693128538136576	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+2008045568203612160	GP12	60	2	2008045554458877953	2008045554458877952	1972113784531521536.png	files1/202601/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202601/c9ed812c21468a07cfee2e966e45f3c8.png
+2008045568203612160	GP12	60	2	2032110401796820993	2032110401796820992	2012787622889033728.png	files1/202603/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202603/c9ed812c21468a07cfee2e966e45f3c8.png
+2008045568203612160	GP12	60	2	2041694998681821185	2041694998681821184	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+2008045568203612160	GP12	60	2	2041698909614002177	2041698909614002176	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+2008045568203612160	GP12	60	2	2048299752086417409	2048299752086417408	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+2039245063986479104	CCD复测	89	2	2039246065892458497	2039246065892458496	image.png	files1/202604/	ddf9a09f5244fa53588f65354389a118	png	files1/202604/ddf9a09f5244fa53588f65354389a118.png
+2039245063986479104	CCD复测	89	2	2041692415821029377	2041692415821029376	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+2039245063986479104	CCD复测	89	2	2041704043576315905	2041704043576315904	1901306954353692672.png	files1/202604/	3075767d1c31dde8214bef1ade82a485	png	files1/202604/3075767d1c31dde8214bef1ade82a485.png
+2039245063986479104	CCD复测	89	2	2048298820703465473	2048298820703465472	2047965281738039296.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+2039245063986479104	CCD复测	89	2	2060906600075419649	2060906600075419648	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2041753218108116992	OP380底护板安装	90	2	2041753212198342657	2041753212198342656	1972113784531521536.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+2042204468847316992	恒温静置	88	2	2042204462631358465	2042204462631358464	1972113784531521536.png	files1/202604/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202604/c9ed812c21468a07cfee2e966e45f3c8.png
+2055099103921139712	HEVOP010镭雕	200	0	2055099093913530369	2055099093913530368	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055099103921139712	HEVOP010镭雕	200	0	2075472449078091777	2075472449078091776	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055099663919443968	HEVOP030凸焊	201	1	2055099659238600705	2055099659238600704	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055100722444333056	HEVOP030凸焊	201	2	2055100717897707521	2055100717897707520	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055101313237217280	HEVOP060左右吊耳组件点焊	203	2	2055101310036963329	2055101310036963328	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055101313237217280	HEVOP060左右吊耳组件点焊	203	2	2075472519676616705	2075472519676616704	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055101811688304640	HEVOP070电池壳分总成 1 点焊	204	0	2055101806520922113	2055101806520922112	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055101811688304640	HEVOP070电池壳分总成 1 点焊	204	0	2075472571706957825	2075472571706957824	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055102191365091328	HEVOP080电池壳分总成 1 点焊补焊	205	0	2055102185195270145	2055102185195270144	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055102191365091328	HEVOP080电池壳分总成 1 点焊补焊	205	0	2075472741651767297	2075472741651767296	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055102400157544448	HEVOP090电池壳分总成 2 点焊	206	0	2055102394663006209	2055102394663006208	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055102400157544448	HEVOP090电池壳分总成 2 点焊	206	0	2075472330458980353	2075472330458980352	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055102592025980928	HEVOP100电池壳分总成 2 点焊补焊	207	0	2055102586862792705	2055102586862792704	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055102592025980928	HEVOP100电池壳分总成 2 点焊补焊	207	0	2075472787218685953	2075472787218685952	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055102841721286656	HEVOP110电池壳分总成 3 点焊	208	0	2055102837321461761	2055102837321461760	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055102841721286656	HEVOP110电池壳分总成 3 点焊	208	0	2075472876825796609	2075472876825796608	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055103002711257088	HEVOP120电池壳分总成 4 点焊	209	0	2055102998869274625	2055102998869274624	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055103002711257088	HEVOP120电池壳分总成 4 点焊	209	0	2075470926512185345	2075470926512185344	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055103158730977280	HEVOP130电池壳分总成 5 点焊补焊	210	0	2055103148819836929	2055103148819836928	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055103158730977280	HEVOP130电池壳分总成 5 点焊补焊	210	0	2075472909197434881	2075472909197434880	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055103410875756544	HEVOP140电池壳分总成 6 弧焊	211	0	2055103393918185473	2055103393918185472	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055103410875756544	HEVOP140电池壳分总成 6 弧焊	211	0	2075473011978854401	2075473011978854400	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055103587430789120	HEVOP150电池壳分总成 7 弧焊	212	0	2055103583089684481	2055103583089684480	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055103587430789120	HEVOP150电池壳分总成 7 弧焊	212	0	2075473043520020481	2075473043520020480	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055103750283030528	HEVOP160电池壳分总成8弧焊	213	0	2055103745132425217	2055103745132425216	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055103750283030528	HEVOP160电池壳分总成8弧焊	213	0	2075473130086260737	2075473130086260736	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055104128126906368	HEVOP190A白件气密检测	214	0	2055104124666605569	2055104124666605568	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055104128126906368	HEVOP190A白件气密检测	214	0	2075473172616503298	2075473172616503297	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055104298524700672	HEVOP210拉铆	215	0	2055104294389116929	2055104294389116928	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055104298524700672	HEVOP210拉铆	215	0	2075473208016429057	2075473208016429056	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055104458021498880	HEVOP220总成气密检测	216	0	2055104452849922049	2055104452849922048	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055104458021498880	HEVOP220总成气密检测	216	0	2075473239930888192	2075473239926693888	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055107245774041088	115OP010镭雕	217	0	2055107203134746625	2055107203134746624	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055107245774041088	115OP010镭雕	217	0	2075473271870513153	2075473271870513152	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055107492160040960	115OP040左右边框总成	218	0	2055107480692813825	2055107480692813824	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055107492160040960	115OP040左右边框总成	218	0	2075473315851984897	2075473315851984896	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055107872222703616	115OP060前后边框总成	219	0	2055107868166811649	2055107868166811648	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055107872222703616	115OP060前后边框总成	219	0	2075473445225291777	2075473445225291776	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055108029320359936	115OP070总成框架拼焊-A	220	0	2055108025461600257	2055108025461600256	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055108029320359936	115OP070总成框架拼焊-A	220	0	2075473476783235073	2075473476783235072	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055109345304211456	打印	202	0	2055109336634585089	2055109336634585088	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055109345304211456	打印	202	0	2075472487728603137	2075472487728603136	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055110761007640576	115OP080总成框架弧焊-B	221	0	2055110756695896065	2055110756695896064	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055110761007640576	115OP080总成框架弧焊-B	221	0	2075473512497733633	2075473512497733632	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055111168886927360	115OP110白件气密检测	222	0	2055111164818452481	2055111164818452480	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055111168886927360	115OP110白件气密检测	222	0	2075473552951795714	2075473552951795713	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055111456809119744	115OP130拉铆框架正面	223	0	2055111453080383489	2055111453080383488	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055111456809119744	115OP130拉铆框架正面	223	0	2075473711496486913	2075473711496486912	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055111609590837248	115OP150液冷板装配拉铆	224	0	2055111605925015553	2055111605925015552	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055111609590837248	115OP150液冷板装配拉铆	224	0	2075473744535019521	2075473744535019520	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055111801694154752	115OP180总成气密检测	225	0	2055111797185277953	2055111797185277952	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055111801694154752	115OP180总成气密检测	225	0	2075473788399050753	2075473788399050752	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2055112013066104832	115OP190在线检测	226	2	2055112011111559169	2055112011111559168	system.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2055112013066104832	115OP190在线检测	226	2	2075473820640665601	2075473820640665600	扫码.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2056554322425556992	设备维保	1	2	2056554300225105921	2056554300225105920	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056554677582442496	质量检查	2	2	2056554674210222081	2056554674210222080	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056555575796838400	下线目视检查	3	2	2056555571497676801	2056555571497676800	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056555756592312320	返修	4	2	2056555753886986241	2056555753886986240	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056556129067479040	物料入库	5	2	2056556126085328897	2056556126085328896	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056556300576763904	物料出库	6	2	2056556293240926209	2056556293240926208	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056556815054286848	产品用料	7	2	2056556811573014529	2056556811573014528	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056557069493350400	成品批次入库	8	2	2056557067417169921	2056557067417169920	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056557268030730240	报废	9	0	2056557264381685761	2056557264381685760	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056557268030730240	报废	9	0	2076936538465665025	2076936538465665024	恢复.png	files1/202607/	17d8fae4fed7ec9ebc3252c903720f40	png	files1/202607/17d8fae4fed7ec9ebc3252c903720f40.png
+2056557268030730240	报废	9	0	2092510050241404929	2092510050241404928	ashbin.png	files1/202608/	bbfbdaa0b381324d074fdeb9aacd50f8	png	files1/202608/bbfbdaa0b381324d074fdeb9aacd50f8.png
+2056557453662236672	返修审核	10	2	2056557449488904193	2056557449488904192	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056557686303502336	返工审核	11	2	2056557681148702720	2056557681144508416	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056557873323323392	返工SOP	12	2	2056557869800108033	2056557869800108032	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056558144317304832	返修SOP	13	2	2056558131482734593	2056558131482734592	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056558433900441600	返工复检	14	2	2056558429194432513	2056558429194432512	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056558784087076864	返修复检	15	2	2056558778810642433	2056558778810642432	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056559509533896704	返修让步接收	16	2	2056559506501414913	2056559506501414912	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056559704027967488	让步入库审核	17	2	2056559699221295105	2056559699221295104	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056559931136946176	紧急性维修	18	1	2056559928020578305	2056559928020578304	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056560068454264832	预防性维护	19	1	2056560065870573569	2056560065870573568	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056560236209647616	生产管理返修	20	2	2056560228680871937	2056560228680871936	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056560493320482816	OP110	21	2	2056560489595940865	2056560489595940864	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056560657867223040	报废记录	22	1	2056560654193012737	2056560654193012736	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056561115256074240	返修检查	23	1	2056561111430868993	2056561111430868992	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056561762579787776	恢复生产	24	1	2056561759274676225	2056561759274676224	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056561918779863040	MES辅助	25	1	2056561915835461633	2056561915835461632	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056562172010967040	设备工装	26	1	2056562169372749825	2056562169372749824	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056562379939393536	抽检	27	1	2056562375136915457	2056562375136915456	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056562635351535616	箱体OP050	28	2	2056562631228534785	2056562631228534784	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056575342603677696	箱体OP070	29	2	2056575339625721857	2056575339625721856	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056575763208482816	箱体OP290	30	2	2056575757663612929	2056575757663612928	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056575984139251712	冷板OP120	31	2	2056575980855111681	2056575980855111680	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056576269515501568	NG处理	32	2	2056576264725606401	2056576264725606400	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056576444413784064	周期性维护	33	2	2056576439477088257	2056576439477088256	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056577957794164736	IQC检测	37	2	2056577953276899329	2056577953276899328	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056578375563620352	成品出货	38	2	2056578372594053121	2056578372594053120	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2056578525371576320	批次解绑	39	2	2056578521714143233	2056578521714143232	2055102394663006208.png	files1/202605/	ddf9a09f5244fa53588f65354389a118	png	files1/202605/ddf9a09f5244fa53588f65354389a118.png
+2059171432658120704	入库管理	35	2	2059171418967912449	2059171418967912448	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png
+2059171528892231680	出库管理	36	2	2059171525201244161	2059171525201244160	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png
+2059174587043164160	成品入库	42	2	2059174532777259009	2059174532777259008	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png
+2059174771756118016	成品出货	38	2	2059174766966222849	2059174766966222848	1972113784531521536.png	files1/202605/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202605/c9ed812c21468a07cfee2e966e45f3c8.png
+2072243445574942720	来料检	227	2	2072243630573699073	2072243630573699072	1972113784531521536.png	files1/202607/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202607/c9ed812c21468a07cfee2e966e45f3c8.png
+2072243445574942720	来料检	227	2	2075471312673366017	2075471312673366016	检查_o.png	files1/202607/	4575235bc7555828c969d515ef329728	png	files1/202607/4575235bc7555828c969d515ef329728.png
+2072565056097198080	生产领料	228	0	2072565233622794241	2072565233622794240	1972113784531521536.png	files1/202607/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202607/c9ed812c21468a07cfee2e966e45f3c8.png
+2072565056097198080	生产领料	228	0	2075471377836072961	2075471377836072960	生产入库.png	files1/202607/	4d4c9dfb1f7fb6b86dfe503a77a16fcc	png	files1/202607/4d4c9dfb1f7fb6b86dfe503a77a16fcc.png
+2072856530422153216	生产入库	229	0	2072856525464485889	2072856525464485888	1972113784531521536.png	files1/202607/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202607/c9ed812c21468a07cfee2e966e45f3c8.png
+2072856530422153216	生产入库	229	0	2075472407596425217	2075472407596425216	生产入库.png	files1/202607/	4d4c9dfb1f7fb6b86dfe503a77a16fcc	png	files1/202607/4d4c9dfb1f7fb6b86dfe503a77a16fcc.png
+2074368075992731648	直接调拨单	230	0	2074368202447167489	2074368202447167488	1972113784531521536.png	files1/202607/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202607/c9ed812c21468a07cfee2e966e45f3c8.png
+2074368075992731648	直接调拨单	230	0	2075472372079058945	2075472372079058944	调拨单.png	files1/202607/	fec1d4f6ede84199087e93c425bd844c	png	files1/202607/fec1d4f6ede84199087e93c425bd844c.png
+2074786819844612096	打包	231	0	2074787102645198849	2074787102645198848	1972113784531521536.png	files1/202607/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202607/c9ed812c21468a07cfee2e966e45f3c8.png
+2074786819844612096	打包	231	0	2075471503556141057	2075471503556141056	集成打包.png	files1/202607/	6e191a5fe709287d42f74af66d1e2e3a	png	files1/202607/6e191a5fe709287d42f74af66d1e2e3a.png
+2074786917819359232	返修	232	0	2074787046663823361	2074787046663823360	1972113784531521536.png	files1/202607/	c9ed812c21468a07cfee2e966e45f3c8	png	files1/202607/c9ed812c21468a07cfee2e966e45f3c8.png
+2074786917819359232	返修	232	0	2075471435142848513	2075471435142848512	返修.png	files1/202607/	acbaff57bd755d21dc946532f074c866	png	files1/202607/acbaff57bd755d21dc946532f074c866.png
+2079031276184727552	HEVOP190B白件气密检测	233	0	2079031089466896385	2079031089466896384	2075473172616503297.png	files1/202607/	ef0a1675fbc95922a1660bb1647df7de	png	files1/202607/ef0a1675fbc95922a1660bb1647df7de.png
+2085624372223152128	汇报查询	234	0	2085624355160723457	2085624355160723456	调拨单.png	files1/202608/	fec1d4f6ede84199087e93c425bd844c	png	files1/202608/fec1d4f6ede84199087e93c425bd844c.png
+2089545591848103936	MES辅助修改记录	235	0	2092506248876580865	2092506248876580864	2075471827322855424.png	files1/202608/	2f10b39d74803937eb1337c965e20efb	png	files1/202608/2f10b39d74803937eb1337c965e20efb.png
+2090000000000000235	发货检	236	0	2092505903379177473	2092505903379177472	2075472173810114560 (1).png	files1/202608/	4575235bc7555828c969d515ef329728	png	files1/202608/4575235bc7555828c969d515ef329728.png
+2099454537145536512	PDA首件检	238	0	2101196827405029377	2101196827405029376	shoujianjian.png	files1/202609/	393169b5e1a634c5398f3690f01f21a2	png	files1/202609/393169b5e1a634c5398f3690f01f21a2.png
+2100025671279136768	首件检确认	239	0	2101197449537753089	2101197449537753088	shoujianjianqueren.png	files1/202609/	e602ff50a67b021e8200d3c9693503fc	png	files1/202609/e602ff50a67b021e8200d3c9693503fc.png
+2100025890246971392	GP12检验	241	0	2101196732911554561	2101196732911554560	GP12jianyan.png	files1/202609/	39de4b60f6a8d768ae60a4e806d5e9b8	png	files1/202609/39de4b60f6a8d768ae60a4e806d5e9b8.png
+2100026067586338816	开班点检	240	0	2101196661214121985	2101196661214121984	kaibandianjian.png	files1/202609/	bd34249f6c19f4ef37c53a928f5b6e98	png	files1/202609/bd34249f6c19f4ef37c53a928f5b6e98.png

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 586 - 0
_apk_work/extracted/restore_mes_icons_image_mapping.sql


+ 297 - 0
_apk_work/extracted/urls.txt

@@ -0,0 +1,297 @@
+.http://testedst.nat200.top/js/a/mes/mesApp/ver
+/http://testedst.nat200.top/js/a/mes/mesLine/all
+/http://testedst.nat200.top/js/a/mes/mesNg/getNg
+/http://testedst.nat200.top/js/a/mes/mesNg/ulist
+0http://testedst.nat200.top/js/a/mes/mesCheck/all
+0http://testedst.nat200.top/js/a/mes/mesNg/saveNg
+0http://testedst.nat200.top/js/a/mes/mesScrap/add
+1http://testedst.nat200.top/js/a/mes//mesIqc/ulist
+1http://testedst.nat200.top/js/a/mes/mesNg/uDetail
+1http://testedst.nat200.top/js/a/mes/mesRepair/add
+1http://testedst.nat200.top/js/a/mes/mesScrap/info
+2http://testedst.nat200.top/js/a/mes/mesIcons/icons
+2http://testedst.nat200.top/js/a/mes/mesIqc/addSave
+2http://testedst.nat200.top/js/a/mes/mesJbLog/ulist
+2http://testedst.nat200.top/js/a/mes/mesLine/oprnos
+2http://testedst.nat200.top/js/a/mes/mesRecover/add
+2http://testedst.nat200.top/js/a/mes/mesRepair/info
+2http://testedst.nat200.top/js/a/mes/mesScrap/ulist
+3http://testedst.nat200.top/js/a/mes/mesProduct/info
+3http://testedst.nat200.top/js/a/mes/mesQuality/info
+3http://testedst.nat200.top/js/a/mes/mesQuality/wtqd
+3http://testedst.nat200.top/js/a/mes/mesRecover/info
+3http://testedst.nat200.top/js/a/mes/mesRepair/ulist
+4http://testedst.nat200.top/js/a/mes/mesJbLog/addSave
+4http://testedst.nat200.top/js/a/mes/mesRecover/ulist
+4http://testedst.nat200.top/js/a/mes/mesWarehouse/all
+5http://testedst.nat200.top/js/a/mes/mesHwdgTime/ulist
+5http://testedst.nat200.top/js/a/mes/mesProduct/addImg
+5http://testedst.nat200.top/js/a/mes/mesProductNg/deal
+5http://testedst.nat200.top/js/a/mes/mesQuality/cjList
+6http://testedst.nat200.top/js/a/mes/mesDevice/infoBySn
+6http://testedst.nat200.top/js/a/mes/mesDeviceState/all
+6http://testedst.nat200.top/js/a/mes/mesHwdgTime/addApi
+6http://testedst.nat200.top/js/a/mes/mesIqc/ulistDetail
+6http://testedst.nat200.top/js/a/mes/mesProduct/records
+6http://testedst.nat200.top/js/a/mes/mesProductNg/ulist
+6http://testedst.nat200.top/js/a/mes/mesRepairItems/all
+6http://testedst.nat200.top/js/a/mes/mesWarehouseIn/add
+7http://testedst.nat200.top/js/a/mes/mesBatchQuality/add
+7http://testedst.nat200.top/js/a/mes/mesCheck/checkItems
+7http://testedst.nat200.top/js/a/mes/mesDeviceRecord/add
+7http://testedst.nat200.top/js/a/mes/mesDeviceState/edit
+7http://testedst.nat200.top/js/a/mes/mesDeviceState/info
+7http://testedst.nat200.top/js/a/mes/mesProductCheck/add
+7http://testedst.nat200.top/js/a/mes/mesProductDhb/ulist
+7http://testedst.nat200.top/js/a/mes/mesProductGp12/info
+7http://testedst.nat200.top/js/a/mes/mesProductNg/detail
+7http://testedst.nat200.top/js/a/mes/mesRepair/getRepair
+8http://testedst.nat200.top/js/a/mes//mesShippOrder/ulist
+8http://testedst.nat200.top/js/a/mes/erpInStock/stockList
+8http://testedst.nat200.top/js/a/mes/erpPrdInStock/submit
+8http://testedst.nat200.top/js/a/mes/mesBatchQuality/info
+8http://testedst.nat200.top/js/a/mes/mesDeviceRecord/info
+8http://testedst.nat200.top/js/a/mes/mesDeviceUrgency/add
+8http://testedst.nat200.top/js/a/mes/mesMaterialKw/kwList
+8http://testedst.nat200.top/js/a/mes/mesProcessAlarm/deal
+8http://testedst.nat200.top/js/a/mes/mesProductPicgk/info
+8http://testedst.nat200.top/js/a/mes/mesProductScrap/scan
+8http://testedst.nat200.top/js/a/mes/mesQuality/checkSave
+8http://testedst.nat200.top/js/a/mes/mesRepair/saveRepair
+8http://testedst.nat200.top/js/a/mes/mesRepairQuality/add
+8http://testedst.nat200.top/js/a/mes/mesWarehouseIn/types
+8http://testedst.nat200.top/js/a/mes/mesWarehouseIn/ulist
+9http://testedst.nat200.top/js/a/mes/erpStockPda/stockList
+9http://testedst.nat200.top/js/a/mes/mesDeviceTask/getList
+9http://testedst.nat200.top/js/a/mes/mesHwdgTime/updateApi
+9http://testedst.nat200.top/js/a/mes/mesJbLog/getBatchInfo
+9http://testedst.nat200.top/js/a/mes/mesProcessRecord/deal
+9http://testedst.nat200.top/js/a/mes/mesProductCheck/ulist
+9http://testedst.nat200.top/js/a/mes/mesProductGp12/submit
+9http://testedst.nat200.top/js/a/mes/mesProductPicgk/lists
+9http://testedst.nat200.top/js/a/mes/mesProductRepair/scan
+9http://testedst.nat200.top/js/a/mes/mesProductScrap/ulist
+9http://testedst.nat200.top/js/a/mes/mesRepair/editRepair1
+9http://testedst.nat200.top/js/a/mes/mesShippOrder/addSave
+9http://testedst.nat200.top/js/a/mes/mesWarehouseIn/detail
+:http://testedst.nat200.top/js/a/mes/erpInStock/inspectInit
+:http://testedst.nat200.top/js/a/mes/mesBatchSn/bindProduct
+:http://testedst.nat200.top/js/a/mes/mesDeviceUrgency/ulist
+:http://testedst.nat200.top/js/a/mes/mesProcessAlarm/alarms
+:http://testedst.nat200.top/js/a/mes/mesProcessAlarm/detail
+:http://testedst.nat200.top/js/a/mes/mesProductCheck/detail
+:http://testedst.nat200.top/js/a/mes/mesProductPicgk/lists1
+:http://testedst.nat200.top/js/a/mes/mesProductPicgk/submit
+:http://testedst.nat200.top/js/a/mes/mesRepairQuality/ulist
+:http://testedst.nat200.top/js/a/mes/mesWarehouseRefund/add
+;http://testedst.nat200.top/js/a/mes/erpInStock/pda/listData
+;http://testedst.nat200.top/js/a/mes/erpPrdInStock/batchScan
+;http://testedst.nat200.top/js/a/mes/mesBatchSn/pda/listData
+;http://testedst.nat200.top/js/a/mes/mesDeviceRecord/getList
+;http://testedst.nat200.top/js/a/mes/mesDeviceUrgency/detail
+;http://testedst.nat200.top/js/a/mes/mesMaterialPrebind/bind
+;http://testedst.nat200.top/js/a/mes/mesProduct/infoByRepair
+;http://testedst.nat200.top/js/a/mes/mesProductPicgk/submit1
+;http://testedst.nat200.top/js/a/mes/mesProductRepair/wxList
+;http://testedst.nat200.top/js/a/mes/mesProductRepair/wxSave
+;http://testedst.nat200.top/js/a/mes/mesQuality/checkProduct
+;http://testedst.nat200.top/js/a/mes/mesRepairItems/allItems
+<http://testedst.nat200.top/js/a/mes/erpInStock/pda/lotSearch
+<http://testedst.nat200.top/js/a/mes/erpInStock/submitInStock
+<http://testedst.nat200.top/js/a/mes/erpTransferDirect/submit
+<http://testedst.nat200.top/js/a/mes/mesBatchSn/createBatchSn
+<http://testedst.nat200.top/js/a/mes/mesCcdInspection/padInfo
+<http://testedst.nat200.top/js/a/mes/mesMaterialReport/submit
+<http://testedst.nat200.top/js/a/mes/mesProcessRecord/devices
+<http://testedst.nat200.top/js/a/mes/mesProductRecord/binddhb
+<http://testedst.nat200.top/js/a/mes/mesProductRecord/list310
+<http://testedst.nat200.top/js/a/mes/mesProductRecord/padInfo
+<http://testedst.nat200.top/js/a/mes/mesProductRepair/allList
+<http://testedst.nat200.top/js/a/mes/mesProductRepair/badList
+<http://testedst.nat200.top/js/a/mes/mesProductRepair/badSave
+=http://testedst.nat200.top/js/a/mes/erpInStock/pda/lotOptions
+=http://testedst.nat200.top/js/a/mes/mesDeviceTask/getTaskForm
+=http://testedst.nat200.top/js/a/mes/mesLineProcess/getParents
+=http://testedst.nat200.top/js/a/mes/mesMaterialLlRecord/ulist
+=http://testedst.nat200.top/js/a/mes/mesMaterialRkRecord/ulist
+=http://testedst.nat200.top/js/a/mes/mesProductGp12/selectList
+=http://testedst.nat200.top/js/a/mes/mesProductGp12/submitGP12
+=http://testedst.nat200.top/js/a/mes/mesProductRecord/getCurSn
+=http://testedst.nat200.top/js/a/mes/mesProductRecord/pdaGetSn
+=http://testedst.nat200.top/js/a/mes/mesProductRecord/pdacheck
+=http://testedst.nat200.top/js/a/mes/mesProductRepair/wxDetail
+=http://testedst.nat200.top/js/a/mes/mesShippOrder/ulistDetail
+=http://testedst.nat200.top/js/a/mes/mesToolReplaceRecord/info
+>http://testedst.nat200.top/js/a/mes/erpInStock/stockLocOptions
+>http://testedst.nat200.top/js/a/mes/erpPrdInStock/pda/listData
+>http://testedst.nat200.top/js/a/mes/erpTransferDirect/formInit
+>http://testedst.nat200.top/js/a/mes/mesCcdInspection/pdaresult
+>http://testedst.nat200.top/js/a/mes/mesDevicePreventTask/ulist
+>http://testedst.nat200.top/js/a/mes/mesLineProcess/editDevices
+>http://testedst.nat200.top/js/a/mes/mesLineProcess/processList
+>http://testedst.nat200.top/js/a/mes/mesPeriodicMaintenance/all
+>http://testedst.nat200.top/js/a/mes/mesProcessAlarm/alarmCount
+>http://testedst.nat200.top/js/a/mes/mesProductLeakagePoint/add
+>http://testedst.nat200.top/js/a/mes/mesProductRecord/pdaresult
+>http://testedst.nat200.top/js/a/mes/mesProductRecord/unbinddhb
+>http://testedst.nat200.top/js/a/mes/mesProductRepair/allDetail
+>http://testedst.nat200.top/js/a/mes/mesProductRepair/applylist
+>http://testedst.nat200.top/js/a/mes/mesProductRepair/badDetail
+>http://testedst.nat200.top/js/a/mes/mesRepairQuality/apiDetail
+?http://testedst.nat200.top/js/a/mes/erpStockPda/stockLocOptions
+?http://testedst.nat200.top/js/a/mes/erpTransferDirect/batchScan
+?http://testedst.nat200.top/js/a/mes/mesDeviceConsumable/getList
+?http://testedst.nat200.top/js/a/mes/mesDevicePreventTask/detail
+?http://testedst.nat200.top/js/a/mes/mesMaterialLlRecord/addSave
+?http://testedst.nat200.top/js/a/mes/mesMaterialLlRecord/delBind
+?http://testedst.nat200.top/js/a/mes/mesMaterialRkRecord/addSave
+?http://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/lists
+?http://testedst.nat200.top/js/a/mes/mesProductCheckFirst/submit
+?http://testedst.nat200.top/js/a/mes/mesProductRepair/detailBySn
+?http://testedst.nat200.top/js/a/mes/mesProductRepair/wxSnDetail
+?http://testedst.nat200.top/js/a/mes/mesToolReplaceRecord/change
+?http://testedst.nat200.top/js/a/mes/mesWarehouseInItems/idetail
+@http://testedst.nat200.top/js/a/mes/mesCcdInspection/padListData
+@http://testedst.nat200.top/js/a/mes/mesMaterialLlRecord/ckDetail
+@http://testedst.nat200.top/js/a/mes/mesMaterialReport/selectById
+@http://testedst.nat200.top/js/a/mes/mesMaterialReport/selectList
+@http://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/checks
+@http://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/detail
+@http://testedst.nat200.top/js/a/mes/mesProductGp12/pdaCheckItems
+@http://testedst.nat200.top/js/a/mes/mesProductLeakagePoint/lists
+@http://testedst.nat200.top/js/a/mes/mesProductRecord/editProduct
+@http://testedst.nat200.top/js/a/mes/mesProductRecord/padListData
+@http://testedst.nat200.top/js/a/mes/mesProductStorageRecord/info
+Ahttp://testedst.nat200.top/js/a/mes/mesCcdInspection/checkQuality
+Ahttp://testedst.nat200.top/js/a/mes/mesDevicePreventTask/dealsave
+Ahttp://testedst.nat200.top/js/a/mes/mesProductRecord/checkProduct
+Ahttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaQueryBySn
+Ahttp://testedst.nat200.top/js/a/mes/mesProductRecord/pea310Detail
+Ahttp://testedst.nat200.top/js/a/mes/mesProductRecord/queryProduct
+Ahttp://testedst.nat200.top/js/a/mes/mesToolReplaceRecord/getName1
+Ahttp://testedst.nat200.top/js/a/mes/mesToolReplaceRecord/getTitle
+Ahttp://testedst.nat200.top/js/a/mes/mesWarehouseInItems/applyList
+Bhttp://testedst.nat200.top/js/a/mes/erpInStock/pda/selectOrderData
+Bhttp://testedst.nat200.top/js/a/mes/erpTransferDirect/pda/listData
+Bhttp://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/addCheck
+Bhttp://testedst.nat200.top/js/a/mes/mesProductFinishPackage/submit
+Bhttp://testedst.nat200.top/js/a/mes/mesProductRecord/createProduct
+Bhttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaQueryOprno
+Bhttp://testedst.nat200.top/js/a/mes/mesProductRepairQuality/detail
+Bhttp://testedst.nat200.top/js/a/mes/mesProductRepairQuality/jcList
+Bhttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/submit
+Bhttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/unbind
+Chttp://testedst.nat200.top/js/a/mes/erpInStock/pda/selectDetailData
+Chttp://testedst.nat200.top/js/a/mes/mesMaterialLlRecord/ulistDetail
+Chttp://testedst.nat200.top/js/a/mes/mesMaterialRkRecord/ulistDetail
+Chttp://testedst.nat200.top/js/a/mes/mesProductCheckFirst/selectList
+Chttp://testedst.nat200.top/js/a/mes/mesProductModel/getProductModel
+Chttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaQueryLineSn
+Chttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getLeak
+Chttp://testedst.nat200.top/js/a/mes/mesToolReplaceRecord/selectList
+Dhttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/materialInit
+Dhttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/pda/listData
+Dhttp://testedst.nat200.top/js/a/mes/erpTransferDirect/pda/lotOptions
+Dhttp://testedst.nat200.top/js/a/mes/mesLineProcessMaterial/materials
+Dhttp://testedst.nat200.top/js/a/mes/mesPeriodicMaintenanceRecord/add
+Dhttp://testedst.nat200.top/js/a/mes/mesProductLeakagePointRepair/add
+Dhttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaCheckOneInfo
+Dhttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaCheckOneList
+Dhttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaQueryQuality
+Ehttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/pda/lotSearch
+Ehttp://testedst.nat200.top/js/a/mes/erpPrdInStock/pda/selectOrderData
+Ehttp://testedst.nat200.top/js/a/mes/mesMaterialReport/getMaterialInfo
+Ehttp://testedst.nat200.top/js/a/mes/mesProductModifyRecord/selectList
+Fhttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/pda/lotOptions
+Fhttp://testedst.nat200.top/js/a/mes/erpPrdInStock/pda/selectDetailData
+Fhttp://testedst.nat200.top/js/a/mes/mesPeriodicMaintenanceRecord/ulist
+Fhttp://testedst.nat200.top/js/a/mes/mesProductFinishPackage/selectList
+Fhttp://testedst.nat200.top/js/a/mes/mesProductLeakagePointRepair/ulist
+Fhttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaCheckOneSubmit
+Fhttp://testedst.nat200.top/js/a/mes/mesProductRepairQuality/addQuailty
+Fhttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/selectList
+Fhttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/unbindList
+Ghttp://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/pdaCheckItems
+Ghttp://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/pdaQueryOprno
+Ghttp://testedst.nat200.top/js/a/mes/mesProductLeakagePointRepair/detail
+Ghttp://testedst.nat200.top/js/a/mes/mesProductRecord/pdaQueryScanRecord
+Hhttp://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/pdaCheckSubmit
+Hhttp://testedst.nat200.top/js/a/mes/mesProcessCheckRecord/pdaQueryLineSn
+Ihttp://testedst.nat200.top/js/a/mes/erpTransferDirect/pda/selectOrderData
+Ihttp://testedst.nat200.top/js/a/mes/mesProductFinishPackage/selectByBatch
+Ihttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getBindStatus
+Ihttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getDetailById
+Ihttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getDetailBySn
+Jhttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/submitPickMaterial
+Jhttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getNewTrayCode
+Khttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/pda/selectOrderData
+Khttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getTrayCodeBySn
+Lhttp://testedst.nat200.top/js/a/mes/erpPickMaterialBill/pda/selectDetailData
+Phttp://testedst.nat200.top/js/a/mes/mesProductLeakagePointRepair/getLeakagePoint
+Thttp://testedst.nat200.top/js/a/mes/mesProductStorageRecord/getProductListByTrayCode
+http client execute error:
+http get error, e=
+http get failed, code=
+http get success, result=
+http get success, url=
+http get url=
+http post  error:
+http post Exception error:
+http post IOException error:
+http post data failed, code=
+http post error, e=
+http post failed, code=
+http post failed: 
+http post success, offset: 
+http post success, result=
+http post success, url=
+http post task is executing
+http post url=
+http upload success json=
+http.agent
+http.proxyHost
+http.proxyPort
+http/1.0
+http/1.1
+http2Connection
+http2HeadersList
+http://
+http://121.36.53.58:8980/js
+http://121.36.53.58:8980/js/
+http://182.92.20.189:9099/
+http://192.168.9.180:8980/
+http://rqd.uu.qq.com/rqd/sync
+http://schemas.android.com/aapt
+http://testedst.nat200.top/
+http://www.w3.org/ns/ttml
+http://wy4.baolijinkang.com/uploads/file/20230222/dc31b2cd8fe519bfa044a8c1ff4a1761.jpg,http://wy4.baolijinkang.com/uploads/file/20220615/e62d18ceaec9781cfa96f39b51e4531b.jpeg
+httpBody
+httpCode
+httpCodec
+httpGet
+httpGetIconBytes failed:
+httpGetIconBytes statusCode:
+httpGetString
+httpHeaders
+httpMethod
+httpOnly
+httpPost
+httpPostString
+httpStream
+http_code
+http_report
+httphookReconnect
+httponly
+https:
+https://
+https://dr.netease.im/1.gif
+https://imtest.netease.im/1.gif
+https://nosup-hz1.127.net
+https://tsis.jpush.cn
+https://wannos.127.net/lbs
+httpsExpUrl
+httpsUrl
+https_enabled
+https_report
+httpstatus
+httpstatusmessage

+ 0 - 0
_apk_work/extracted/utf16_cn.txt


+ 91 - 0
_apk_work/img_meta_preview.txt

@@ -0,0 +1,91 @@
+p1 xref=8 1269x61 n=3
+p2 xref=8 1269x61 n=3
+p3 xref=8 1269x61 n=3
+p4 xref=8 1269x61 n=3
+p5 xref=8 1269x61 n=3
+p6 xref=8 1269x61 n=3
+p6 xref=95 1192x601 n=3
+p7 xref=8 1269x61 n=3
+p8 xref=101 1264x636 n=3
+p8 xref=102 101x28 n=3
+p8 xref=8 1269x61 n=3
+p9 xref=8 1269x61 n=3
+p10 xref=109 1268x645 n=3
+p10 xref=8 1269x61 n=3
+p11 xref=8 1269x61 n=3
+--- 1、系统管理操作手册 36 ---
+  p6 1267x644 [3. 功能操作] head=3. 功能操作
+  p7 1178x594 [更多操作] head=3.1.2.员工信息管理
+  p7 1266x644 [更多操作] head=3.1.2.员工信息管理
+  p8 1278x647 [3.1.3.机构管理] head=3.1.3.机构管理
+  p9 1267x646 [岗位名称/代码/分类 岗位信息] head=3.2. 权限管理
+  p10 1267x642 [角色管理] head=
+  p10 1264x635 [作。] head=
+  p11 1267x645 [更多操作-授权菜单] head=
+--- 2、设备管理操作手册 13 ---
+  p4 1265x640 [3. 功能操作] head=3. 功能操作
+  p5 1266x636 [设备清单] head=3.1.3. 易耗品
+  p5 1264x645 [扫码识别)。] head=3.1.3. 易耗品
+  p6 1266x642 [易耗品] head=3.1.4. 易耗品记录
+  p6 1266x644 [易耗品] head=3.1.4. 易耗品记录
+  p7 1133x575 [3.2. 预防性维护] head=3.2.
+  p8 1108x565 [任务清单 必选,关联保养模板] head=
+  p8 1267x646 [维护计划] head=
+--- 3、物料管理操作手册 3 ---
+  p6 1192x601 [物料总库存] head=3.2. 物料列表
+  p8 1264x636 [物料列表] head=3.2.1.检查项
+  p10 1268x645 [ERP 生产订单 关联ERP 生产订单号(如有)] head=4. 数据关系说明
+--- 4、质量管理操作手册 10 ---
+  p5 1110x546 [3. 功能操作] head=3. 功能操作
+  p6 1267x637 [抽检记录查询字段表] head=3.3.
+  p7 1266x615 [返修记录] head=3.4.
+  p7 1265x639 [返修记录] head=3.4.
+  p8 1264x638 [3.5. 恢复记录] head=3.5.
+  p9 1266x637 [类型/状态/检查结果 检验结果] head=3.7.
+  p10 1266x644 [工具寿命更换记录] head=3.8.
+  p10 1267x637 [工具寿命更换记录] head=3.8.
+--- 5、生产管理操作手册 33 ---
+  p6 1264x646 [3. 功能操作] head=3. 功能操作
+  p7 1266x645 [产品生产记录-明细] head=3.1.1.查询
+  p7 1264x637 [据需求输入查询条件,点击查询按钮完成筛选查询。] head=3.1.1.查询
+  p8 1268x687 [筛选后的所有数据。] head=3.1.2.导出
+  p9 1266x646 [产品生成记录-保存] head=3.1.4.修改
+  p9 1214x615 [的加工结果、绑定内容、备注等进行修改,修改完数据后,点击下方保存按钮完] head=3.1.4.修改
+  p10 1267x647 [页面查看该工件的详细信息。] head=3.1.5.查看产品记录详情
+  p11 1265x641 [产品生成记录-重置] head=3.1.7.提交(OK)
+--- 6、ERP对接操作手册 13 ---
+  p5 1268x643 [ERP 生产领料单查询] head=3. 功能操作
+  p6 1269x642 [ERP 生产领料单查询-详情] head=3.2. ERP 生产订单查询
+  p6 1059x536 [ERP 生产订单查询] head=3.2. ERP 生产订单查询
+  p7 1265x638 [3.3. ERP 排产计划] head=3.3. ERP 排产计划
+  p8 1196x611 [ERP 排产计划-看板] head=3.4. ERP 直接调拨单查询
+  p9 1266x639 [ERP 直接调拨单查询] head=3.5. ERP 生产入库单查询
+  p9 1266x643 [存。] head=3.5. ERP 生产入库单查询
+  p10 1265x638 [本模块主要用于展示ERP 生产入库单信息,支持对订单进行新增、查询、] head=
+--- 7、生产线管理操作手册 20 ---
+  p5 1265x641 [3. 功能操作] head=3. 功能操作
+  p6 1264x627 [生产工位管理] head=3.2.1.点检项
+  p6 1265x678 [删改查及停用/启用操作。] head=3.2.1.点检项
+  p7 1265x676 [料进行增删改查及停用/启用操作。] head=3.2.2.物料
+  p8 1268x679 [生产工位管理-人员] head=3.2.4.子工位
+  p8 1191x604 [增删改查操作。] head=3.2.4.子工位
+  p9 1213x618 [作指导书进行添加。] head=3.2.6.JAR 管理
+  p9 1125x569 [信息进行增删改查操作。] head=3.2.6.JAR 管理
+--- 8、PDA操作说明操作手册 68 ---
+  p4 386x823 [1. PDA 端功能与业务概述] head=1. PDA 端功能与业务概述
+  p4 390x823 [安装后图标 登录页] head=1. PDA 端功能与业务概述
+  p5 336x652 [3. 界面介绍] head=3. 界面介绍
+  p5 352x655 [主功能界面 我的界面] head=3. 界面介绍
+  p6 338x618 [HEVOP010A 镭雕扫码界面] head=4.2. HEVOP070 电池壳分总成1 点焊
+  p6 349x736 [HEVOP010A 镭雕扫码界面] head=4.2. HEVOP070 电池壳分总成1 点焊
+  p7 357x680 [4.3. HEVOP080 电池壳分总成1 点焊补焊] head=4.3. HEVOP080 电池壳分总成1 点焊补焊
+  p8 360x675 [HEVOP090A 电池壳分总成2 点焊扫码界面] head=4.5. HEVOP100 电池壳分总成2 点焊补焊
+--- 9、MES系统客户端员工扫码操作手册 22 ---
+  p3 900x677 [用户登录界面] head=1. 功能概述
+  p4 1002x757 [客户端主页] head=3. 工件码扫码操作(核心流程)
+  p5 561x1055 [PDA 主功能界面 扫码界面] head=
+  p5 437x854 [PDA 主功能界面 扫码界面] head=
+  p5 483x895 [PDA 主功能界面 扫码界面] head=
+  p5 460x889 [PDA 扫码页面 PDA 扫码成功页面] head=
+  p6 1187x655 [服务端工位当前工件列表截图] head=3.2. OK 结果提交
+  p6 1002x757 [服务端工位当前工件列表截图] head=3.2. OK 结果提交

+ 169 - 0
_apk_work/insert_manual_images.py

@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+"""Insert 8.28 screenshots back into 9.19 markdown manuals."""
+import json, re
+from pathlib import Path
+
+ROOT = Path(r"D:\产线\大洋\大洋操作手册汇总9.19")
+IMG = ROOT / "images"
+IMG_RE = re.compile(r"^\s*!\[.*?\]\(images/.*?\)\s*$")
+CAP_RE = re.compile(r"^\s*<p class=\"imgcap\">.*$</s>$")
+
+FASCICLES = [
+    "1、系统管理操作手册.md",
+    "2、设备管理操作手册.md",
+    "3、物料管理操作手册.md",
+    "4、质量管理操作手册.md",
+    "5、生产管理操作手册.md",
+    "6、ERP对接操作手册.md",
+    "7、生产线管理操作手册.md",
+    "8、PDA操作说明操作手册.md",
+    "9、MES系统客户端员工扫码操作手册.md",
+]
+
+
+def norm(s):
+    s = (s or "").replace(" ", "").replace(" ", "")
+    s = s.replace("→", "").replace("—", "").replace("-", "")
+    s = re.sub(r"^\d+(\.\d+)*\.?", "", s)
+    return s
+
+
+def parse_sections(lines):
+    """Return list of {level,title,start,end} covering body after heading."""
+    secs = []
+    for i, line in enumerate(lines):
+        m = re.match(r"^(#{2,6})\s+(.*)$", line)
+        if m:
+            secs.append({"level": len(m.group(1)), "title": m.group(2).strip(), "start": i})
+    for i, sec in enumerate(secs):
+        sec["end"] = secs[i + 1]["start"] if i + 1 < len(secs) else len(lines)
+    return secs
+
+
+def strip_old_images(text):
+    lines = text.splitlines()
+    out = []
+    i = 0
+    while i < len(lines):
+        line = lines[i]
+        if IMG_RE.match(line) or line.startswith('<p class="imgcap">') or line.strip() == "*(界面截图取自 8.28 手册,现场如有改动以实际为准。)*":
+            i += 1
+            # skip following blank
+            if i < len(lines) and not lines[i].strip():
+                i += 1
+            continue
+        if line.strip() == "## 原手册界面截图(8.28)":
+            # drop this section until next heading
+            i += 1
+            while i < len(lines) and not re.match(r"^## ", lines[i]):
+                i += 1
+            continue
+        out.append(line)
+        i += 1
+    return "\n".join(out).rstrip() + "\n"
+
+
+def score(sec, cap, heading, body=""):
+    title = sec["title"]
+    tn, cn, hn = norm(title), norm(cap), norm(heading)
+    blob = tn + norm(body)
+    s = 0
+    if cn and (cn in tn or tn in cn):
+        s += 60
+    if hn and (hn in tn or tn in hn):
+        s += 45
+    hay = (title + " " + body).upper()
+    for code in set(re.findall(r"OP\d+", (cap + heading).upper())):
+        if code and code in hay:
+            s += 80
+    keys = re.findall(r"[\u4e00-\u9fff]{2,}", cap + " " + heading)
+    for k in keys:
+        if k in title or k in body[:800]:
+            s += 12
+    return s
+
+
+def image_md(item):
+    cap = item.get("caption") or "界面截图"
+    rel = item["file"]
+    if not rel.startswith("images/"):
+        rel = "images/" + rel
+    return "\n![%s](%s)\n\n*(界面截图取自 8.28 手册,现场如有改动以实际为准。)*\n" % (cap, rel)
+
+
+def insert_into(md_name, items):
+    path = ROOT / md_name
+    text = strip_old_images(path.read_text(encoding="utf-8"))
+    lines = text.splitlines()
+    secs = parse_sections(lines)
+    if not secs:
+        path.write_text(text + "\n## 原手册界面截图(8.28)\n" + "".join(image_md(x) for x in items), encoding="utf-8")
+        return len(items), 0
+    buckets = {id(sec): [] for sec in secs}
+    unmatched = []
+    for item in items:
+        best, best_s = None, 0
+        for sec in secs:
+            body = "\n".join(lines[sec["start"]:sec["end"]])
+            sc = score(sec, item.get("caption", ""), item.get("heading", ""), body)
+            if sc > best_s or (best is not None and sc == best_s and sec["level"] > best["level"]):
+                best, best_s = sec, sc
+        # special: login / home screens
+        cap = item.get("caption") or ""
+        if "登录" in cap:
+            for sec in secs:
+                if "登录" in sec["title"] or "安装" in sec["title"]:
+                    best, best_s = sec, max(best_s, 80)
+        if "主功能" in cap or "我的界面" in cap:
+            for sec in secs:
+                if "界面" in sec["title"]:
+                    best, best_s = sec, max(best_s, 80)
+        if best is None or best_s < 12:
+            unmatched.append(item)
+        else:
+            buckets[id(best)].append(item)
+    # insert from bottom so indexes stay valid
+    for sec in reversed(secs):
+        imgs = buckets[id(sec)]
+        if not imgs:
+            continue
+        # insert before sec['end'] (start of next heading), after trailing blanks of this section
+        pos = sec["end"]
+        while pos > sec["start"] + 1 and pos <= len(lines) and (pos == len(lines) or not lines[pos - 1].strip()):
+            pos -= 1
+        block = "".join(image_md(x) for x in imgs).splitlines()
+        lines[pos:pos] = [""] + block + [""]
+    text = "\n".join(lines).rstrip() + "\n"
+    if unmatched:
+        extra = ["", "## 原手册界面截图(8.28)", "", "以下截图未能自动对上新目录,仍予保留。", ""]
+        for x in unmatched:
+            extra.extend(image_md(x).splitlines())
+        text = text.rstrip() + "\n" + "\n".join(extra) + "\n"
+    path.write_text(text, encoding="utf-8")
+    return len(items) - len(unmatched), len(unmatched)
+
+
+def main():
+    total_m, total_u = 0, 0
+    for md in FASCICLES:
+        stem = md[:-3]
+        man = IMG / stem / "manifest.json"
+        if not man.exists():
+            print("no manifest", stem)
+            continue
+        items = json.loads(man.read_text(encoding="utf-8"))
+        # keep only files that exist
+        ok = []
+        for it in items:
+            p = ROOT / it["file"]
+            if p.exists():
+                ok.append(it)
+        m, u = insert_into(md, ok)
+        total_m += m
+        total_u += u
+        print(stem, "matched", m, "appendix", u, "total", len(ok))
+    print("ALL matched", total_m, "appendix", total_u)
+
+
+if __name__ == "__main__":
+    main()

+ 429 - 0
_apk_work/manuals_text/1、系统管理操作手册.txt

@@ -0,0 +1,429 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——系统管理操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. 系统管理模块概述.................................................................................................. 1
+3. 功能操作.................................................................................................................. 3
+3.1. 组织管理........................................................................................................ 3
+3.1.1. 用户管理.............................................................................................. 3
+3.1.2. 员工信息管理...................................................................................... 4
+3.1.3. 机构管理.............................................................................................. 5
+3.1.4. 岗位管理.............................................................................................. 5
+3.2. 权限管理........................................................................................................ 6
+3.2.1. 角色管理.............................................................................................. 6
+3.2.2. 二级管理员.......................................................................................... 9
+3.2.3. 租户管理员........................................................................................ 10
+3.3. 系统设置...................................................................................................... 10
+3.3.1. 菜单管理............................................................................................ 10
+3.3.2. 参数设置.............................................................................................11
+3.3.3. 字典管理.............................................................................................11
+3.3.4. 功能模块分类.................................................................................... 12
+3.3.5. 功能模块............................................................................................ 13
+3.3.6. 安卓版本............................................................................................ 13
+3.3.7. 客户端版本管理................................................................................ 14
+3.3.8. jar 包管理............................................................................................ 14
+3.4. 系统监控...................................................................................................... 15
+3.4.1. 访问日志............................................................................................ 15
+3.4.2. 在线用户............................................................................................ 16
+3.5. 研发工具...................................................................................................... 16
+3.5.1. 代码生成工具.................................................................................... 16
+3.5.2. 代码生成实例.................................................................................... 17
+3.5.3. 数据表格实例.................................................................................... 18
+
+
+===== PAGE 3 =====
+3.5.4. 表单组件实例.................................................................................... 20
+3.5.5. 前端界面实例.................................................................................... 22
+3.6. 文档管理...................................................................................................... 23
+3.6.1. 文档类型管理.................................................................................... 23
+3.6.2. 文档管理............................................................................................ 23
+4. 常见问题................................................................................................................ 24
+
+
+===== PAGE 4 =====
+第1 页
+1. 文档说明
+本文档说明MES 后台「系统管理」模块各功能的入口、操作步骤及权限要
+求。
+适用对象:系统管理员、IT 运维人员、部门二级管理员。
+使用前提:已登录MES 后台,且账号具备相应菜单权限。
+2. 系统管理模块概述
+MES 后台端系统管理模块,是系统的基础支撑管理模块,覆盖组织管理、
+权限管理、系统设置、系统监控、研发工具、文档管理六大子模块。
+组织管理:实现用户、员工信息、机构、岗位基础业务对象维护,支持数据
+增删改查、导入导出,可完成用户角色分配、密码重置、工位授权等用户相关操
+作,为系统业务提供组织人员基础数据支撑。
+权限管理:包含角色、二级管理员、租户管理员管理,可完成角色菜单权限、
+数据权限配置以及用户角色绑定,分级设置不同管理员,实现系统分级权限管控。
+系统设置:用于系统基础配置维护,包含菜单、系统参数、字典、PDA 相
+关功能模块与版本、jar 包管理,支持功能启停、版本维护,兼顾业务运维配置
+与开发人员后台配置需求。
+系统监控:提供访问日志记录追溯、在线用户查看管理能力,实现系统操作
+留痕与在线会话监控。
+研发工具:面向开发人员,提供代码生成能力,同时提供表格、表单、前端
+图标等各类界面组件的实例参考,辅助开发工作。
+文档管理:实现文档类型与业务文档的统一维护,支持文档上传存储,便于
+文档线上查阅管理。
+系统管理模块概述表
+功能
+主要功能
+组织管理
+用户管理、员工信息、机构管理、岗位管理
+权限管理
+角色管理、二级管理员、租户管理员
+
+
+===== PAGE 5 =====
+第2 页
+系统设置
+菜单、参数、字典、功能模块、客户端版本、JAR
+包等
+系统监控
+访问日志、在线用户、缓存/服务器监控、生产日志
+等
+文档管理
+文档类型、文档上传与在线预览
+
+
+===== PAGE 6 =====
+第3 页
+3. 功能操作
+3.1. 组织管理
+3.1.1.用户管理
+路径:系统管理→组织管理→用户管理。左树右表布局,左侧为机构树,右
+侧为用户列表。
+此模块主要用于管理系统用户信息,支持用户信息的增删改查,以及导入和
+导出操作。
+用户管理查询字段表
+查询字段
+说明
+账号/昵称/姓名/手机
+基本信息筛选
+机构/角色
+在「更多」条件中
+状态
+正常/停用
+用户管理
+点击
+更多操作按钮,可对用户进行分配角色、分配技能、工位授权、重置
+密码、邮箱验证、查看员工二维码操作。
+
+
+===== PAGE 7 =====
+第4 页
+更多操作
+3.1.2.员工信息管理
+路径:系统管理→组织管理→员工信息管理。
+此模块主要用于维护MES 员工档案,与用户账号可关联。可进行员工信息
+进行增删改查以及导入/导出操作。
+员工信息管理查询字段表
+查询字段
+说明
+员工姓名/工号
+基本信息
+所属机构/岗位
+组织信息
+状态
+正常/停用
+员工信息管理
+
+
+===== PAGE 8 =====
+第5 页
+3.1.3.机构管理
+路径:系统管理→组织管理→机构管理。
+此模块主要用于管理维护公司/部门/车间等机构树,可进行组织机构信息增
+删改查、展开/折叠、刷新及导入/导出操作。
+注:新增用户时,可选所属机构。
+机构管理查询字段表
+查询字段
+说明
+机构代码/名称/全称
+机构信息
+状态
+正常/停用
+机构管理
+3.1.4.岗位管理
+路径:系统管理→组织管理→岗位管理。
+此模块主要用于管理人员岗位信息,可进行岗位信息的增删改查以及导入/
+导出操作。
+注:新增用户时,可选所属岗位。
+岗位管理查询字段表
+查询字段
+说明
+
+
+===== PAGE 9 =====
+第6 页
+岗位名称/代码/分类
+岗位信息
+状态
+正常/停用
+岗位管理
+3.2. 权限管理
+3.2.1.角色管理
+路径:系统管理→权限管理→角色管理。
+此模块用于为角色分配菜单权限和数据权限,可进行角色信息的增删改查操
+作。
+关键操作:新增/编辑角色→「授权菜单」勾选功能权限→「分配用户」绑
+定人员。
+角色管理查询字段表
+查询字段
+说明
+角色名称/编码
+角色标识
+用户类型/系统角色
+角色属性
+状态
+正常/停用
+
+
+===== PAGE 10 =====
+第7 页
+角色管理
+点击
+更多操作按钮,可对当前角色进行授权菜单、数据权限、分配用户操
+作。
+更多操作
+点击授权菜单,为当前角色分配功能权限。
+
+
+===== PAGE 11 =====
+第8 页
+更多操作-授权菜单
+点击数据权限,为当前角色分配数据权限。
+更多操作-数据权限
+点击分配用户,当前角色分配系统用户,支持批量添加用户和批量取消用户。
+
+
+===== PAGE 12 =====
+第9 页
+更多操作-分配用户
+3.2.2.二级管理员
+路径:系统管理→权限管理→二级管理员。
+此模块主要用于管理系统二级管理员信息,从已有用户中选择并授权其可管
+理的菜单范围。可进行增删改查操作,直接点击登录账号或
+图标按钮,可以设
+置二级管理员的数据权限,包括机构权限、公司权限和角色权限。
+适用场景:部门级管理员管理本部门用户,无需全局超管权限。
+二级管理员
+
+
+===== PAGE 13 =====
+第10 页
+3.2.3.租户管理员
+路径:系统管理→权限管理→租户管理员。多租户模式下管理各租户管理员
+账号。
+此模块主要用于管理系统一级管理员(超级管理员)信息,可对租户信息进
+行增删改查操作。
+租户管理员
+3.3. 系统设置
+3.3.1.菜单管理
+路径:系统管理→系统设置→菜单管理。
+此模块主要用于管理维护系统菜单树、链接地址及权限标识,支持对系统各
+功能模块菜单进行增删改查、停用/启用菜单等操作。
+关键操作:左侧切换系统编码→查询/新增/编辑/停用/删除菜单→可保存排
+序、数据修复。
+注:修改菜单后需重新登录或刷新缓存生效。
+
+
+===== PAGE 14 =====
+第11 页
+菜单管理
+3.3.2.参数设置
+路径:系统管理→系统设置→参数设置。
+此模块主要用于维护系统运行参数键值,支持对参数信息进行增删改查操作;
+支持按参数名称/键名查询;修改后可「清理全部缓存」使参数立即生效。
+参数设置
+3.3.3.字典管理
+路径:系统管理→系统设置→字典管理。
+
+
+===== PAGE 15 =====
+第12 页
+此模块面向开发人员。主要用于管理系统内部配置,支持增删改查操作。
+关键操作:维护字典类型→进入「字典数据」维护具体选项值。
+字典管理
+3.3.4.功能模块分类
+路径:系统管理→系统设置→功能模块分类。
+此模块面向开发人员。主要用于管理PDA 上的功能分类,支持增删改查、
+停用/启用操作。
+功能模块分类
+
+
+===== PAGE 16 =====
+第13 页
+3.3.5.功能模块
+路径:系统管理→系统设置→功能模块。
+此模块面向开发人员。主要用于管理PDA 上的功能,支持增删改查、停用/
+启用操作。
+注:先维护「功能模块分类」,再维护各「功能模块」的名称、标识、所属
+分类及对应权限。
+功能模块
+3.3.6.安卓版本
+路径:系统管理→系统设置→安卓版本。
+此模块面向开发人员。主要用于展示安卓版本更新记录,支持对版本信息进
+行增删改查操作。
+
+
+===== PAGE 17 =====
+第14 页
+安卓版本
+3.3.7.客户端版本管理
+路径:系统管理→系统设置→客户端版本管理。
+此模块面向开发人员。主要用于展示客户端版本更新记录,支持对版本信息
+进行增删改查操作。
+客户端版本
+3.3.8.jar 包管理
+路径:系统管理→系统设置→jar 包管理。
+
+
+===== PAGE 18 =====
+第15 页
+此模块面向开发人员。主要用于展示客户端版本上传记录,支持对版本信息
+进行增删改查操作。
+注:工位级JAR 版本在「生产线管理→生产工位管理→JAR 管理」中维护;
+也可在工位详情页上传/下载/删除JAR 文件。
+jar 包管理
+3.4. 系统监控
+3.4.1.访问日志
+路径:系统管理→系统监控→访问日志。
+此模块主要用于展示用户行为日志,完整记录并追踪用户在系统中的操作轨
+迹,具体涵盖访问日志、接入日志、修改日志、查询日志及登录登出记录,支持
+对操作留痕进行详细查看与分析。
+
+
+===== PAGE 19 =====
+第16 页
+访问日志
+3.4.2.在线用户
+路径:系统管理→系统监控→在线用户。
+此模块主要展示在线用户信息,包括名称、创建时间、最后访问、超市时间、
+客户主机、用户类型及设备类型,支持对在线用户信息进行删改查操作。
+在线用户
+3.5. 研发工具
+3.5.1.代码生成工具
+路径:系统管理→研发工具→代码生成工具。
+
+
+===== PAGE 20 =====
+第17 页
+此模块主要用于系统代码生成相关配置管理,可对对应配置信息进行查询、
+新增、编辑、删除等操作。
+代码生成工具
+3.5.2.代码生成实例
+3.5.2.1.单表/主子表
+路径:系统管理→研发工具→代码生成实例→单表/主子表。
+此模块主要用于展示单表、主子表功能应用,可借助多种筛选条件查询数据,
+并完成数据新增、编辑、删除等操作。
+单表/主子表
+
+
+===== PAGE 21 =====
+第18 页
+3.5.2.2.树表/树结构表
+路径:系统管理→研发工具→代码生成实例→树表/树结构表。
+此模块主要用于树结构数据管理,支持对树节点进行查询、刷新、展开、折
+叠、新增、编辑等操作。
+树表/树结构表
+3.5.3.数据表格实例
+3.5.3.1.多表头分组小计合计
+路径:系统管理→研发工具→数据表格实例→多表头分组小计合计。
+此模块主要用于展示多表头与数据分组小计功能,支持数据查询、新增,可
+呈现复杂表头的数据统计效果。
+
+
+===== PAGE 22 =====
+第19 页
+多表头分组小计合计
+3.5.3.2.编辑表格多行编辑
+路径:系统管理→研发工具→数据表格实例→编辑表格多行编辑。
+此模块主要用于表格多行编辑功能演示,支持表格内直接编辑、新增行、获
+取表格数据等相关操作。
+编辑表格多行编辑
+3.5.3.3.多表联动示例
+路径:系统管理→研发工具→数据表格实例→多表联动示例。
+
+
+===== PAGE 23 =====
+第20 页
+此模块主要用于展示多表数据联动效果,可通过操作主表格数据,联动加载
+对应关联表格信息。
+多表联动示例
+3.5.4.表单组件实例
+3.5.4.1.组件应用实例
+路径:系统管理→研发工具→表单组件实例→组件应用实例。
+此模块主要用于展示各类表单组件的使用效果,集成多种常用表单控件,直
+观呈现组件应用方式。
+组件应用实例
+
+
+===== PAGE 24 =====
+第21 页
+3.5.4.2.栅格布局实例
+路径:系统管理→研发工具→表单组件实例→栅格布局实例。
+此模块主要用于展示表单栅格布局效果,提供多种列数布局样式,支持数据
+新增与保存操作。
+栅格布局实例
+3.5.4.3.表格表单实例
+路径:系统管理→研发工具→表单组件实例→表格表单实例。
+此模块主要用于展示表格与表单结合的应用样式,支持表单数据填写、保存、
+打印等操作。
+表格表单实例
+
+
+===== PAGE 25 =====
+第22 页
+3.5.4.4.多页签应用示例
+路径:系统管理→研发工具→表单组件实例→多页签应用示例。
+此模块主要用于展示多页签布局的应用效果,支持多页签切换、新增页签、
+关闭窗口等操作。
+多页签应用示例
+3.5.5.前端界面实例
+3.5.5.1.图标样式查找
+路径:系统管理→研发工具→前端界面实例→图标样式查找。
+此模块主要用于系统内置图标的样式预览与查找,支持切换不同图标库查看
+图标样式。
+
+
+===== PAGE 26 =====
+第23 页
+图标样式查找
+3.6. 文档管理
+3.6.1.文档类型管理
+路径:系统管理→文档管理→文档类型管理。
+此模块主要用于维护文档类型。支持增删改查、停用/启用操作。
+文档类型管理
+3.6.2.文档管理
+路径:系统管理→文档管理→文档管理。
+此模块主要用于管理文档信息。上传Word/Excel/PDF 文档线上保存,支持
+
+
+===== PAGE 27 =====
+第24 页
+在线预览,方便查找和查看。可进行增删改查、停用/启用操作。
+关键操作:新增→选择类型、上传文件→保存;列表可预览、编辑、停用/
+删除。
+文档管理
+新增文档
+4. 常见问题
+Q1:修改菜单后用户看不到新菜单?
+确认角色已授权新菜单;清理缓存;用户重新登录。
+Q2:字典修改后下拉框未更新?
+
+
+===== PAGE 28 =====
+第25 页
+在参数设置中清理缓存,或等待缓存自动刷新。
+Q3:用户无法登录?
+检查用户状态是否停用、密码是否正确、角色是否分配。
+Q4:PDA 功能入口缺失?
+检查「功能模块」配置及用户角色是否包含对应权限。

+ 221 - 0
_apk_work/manuals_text/2、设备管理操作手册.txt

@@ -0,0 +1,221 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——设备管理操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. 设备管理模块概述.................................................................................................. 1
+3. 功能操作.................................................................................................................. 2
+3.1. 基础信息........................................................................................................ 2
+3.1.1. 设备分类.............................................................................................. 2
+3.1.2. 设备清单.............................................................................................. 2
+3.1.3. 易耗品.................................................................................................. 3
+3.1.4. 易耗品记录.......................................................................................... 4
+3.2. 预防性维护.................................................................................................... 5
+3.2.1. 任务清单.............................................................................................. 5
+3.2.2. 维护计划.............................................................................................. 5
+3.2.3. 我的维护计划...................................................................................... 7
+3.3. 紧急性维修.................................................................................................... 8
+3.3.1. 维修记录管理...................................................................................... 8
+3.3.2. 我的维修记录...................................................................................... 8
+3.4. 设备运行状态................................................................................................ 9
+4. 业务流程.................................................................................................................. 9
+5. 常见问题................................................................................................................ 10
+
+
+===== PAGE 3 =====
+第1 页
+1. 文档说明
+本文档面向设备管理员、维修人员,说明设备档案、预防性维护、紧急维修
+及运行状态管理操作。
+2. 设备管理模块概述
+MES 后台端设备管理模块,主要用于工厂设备基础档案、保养维修以及设
+备运行状态的业务管控,包含基础信息、预防性维护、紧急性维修、设备运行状
+态四大子模块。
+基础信息:负责维护设备分类、设备清单、易耗品及易耗品记录基础数据,
+支持各类档案的增删改查、停用启用、导入导出,可查看并打印设备二维码,建
+立完整的设备与易耗品基础台账。
+预防性维护:实现设备计划性保养业务管理,可维护保养任务清单、创建预
+防性维护计划,新增维护计划时需要指定任务清单与具备对应技能的执行人员;
+维护人员可在后台或PDA 端查看分派给自己的维护计划,提交维护结果,同时
+登记维护过程中的易耗品使用记录。
+紧急性维修:用于处理设备突发故障维修业务,支持全部维修记录统一管理
+与个人维修记录查看维护,既可以在后台登记维修信息,也支持通过PDA 扫描
+设备二维码提交维修记录,完成故障维修信息归档。
+设备运行状态:接收展示设备上报的运行状态数据,支持数据查询与导出,
+实现设备运行过程数据留存追溯。
+设备管理模块概述表
+功能
+说明
+基础信息
+设备分类、设备清单、易耗品及易耗品记录
+预防性维护
+任务清单(模板)、维护计划、我的维护计划
+紧急性维修
+维修记录管理、我的维修记录
+设备运行状态
+设备上报运行/故障状态查询与导出
+
+
+===== PAGE 4 =====
+第2 页
+3. 功能操作
+3.1. 基础信息
+3.1.1. 设备分类
+路径:设备管理→基础信息→设备分类。
+此模块用于管理项目上设备分类信息,可进行设备分类信息的增删改查、停
+用/启用及导入/导出操作。
+注:新增设备时,可选所属设备分类。
+设备分类
+3.1.2. 设备清单
+路径:设备管理→基础信息→设备清单。
+此模块用于展示项目上设备清单,可进行设备信息的增删改查、停用/启用
+及导入/导出操作。
+
+
+===== PAGE 5 =====
+第3 页
+设备清单
+点击右侧
+二维码标识即可查看和打印设备二维码(内容为设备sn,供PDA
+扫码识别)。
+设备二维码
+3.1.3. 易耗品
+路径:设备管理→基础信息→易耗品。
+此模块用于管理项目上易耗品信息,可进行易耗品信息的增删改查及导入/
+导出操作。
+
+
+===== PAGE 6 =====
+第4 页
+易耗品
+3.1.4. 易耗品记录
+路径:设备管理→基础信息→易耗品记录。
+此模块用于展示项目上易耗品记录信息,查询维修/保养过程中消耗的易耗
+品,数据由业务表单自动生成,可进行易耗品记录的改查及导出操作。
+易耗品记录查询字段表
+查询字段
+说明
+易耗品
+下拉选择
+使用时间
+起止范围
+易耗品记录
+
+
+===== PAGE 7 =====
+第5 页
+3.2.
+预防性维护
+3.2.1.
+任务清单
+路径:设备管理→预防性维护→任务清单。
+此模块用于管理预防性维护任务清单,维护保养模板,含检查项子表(标题、
+工时)。可进行任务清单增删改查、停用/启用及导入/导出操作。
+注:新增维修计划时,可选所属任务清单。
+任务清单查询字段表
+查询字段
+说明
+名称/技术类型/周期/工时/状态
+模板信息
+任务清单
+3.2.2.
+维护计划
+路径:设备管理→预防性维护→维护计划。
+此模块用于管理所有预防性维修计划,可进行维修计划的增删改查及导出操
+作。
+维护计划表单字段
+表单字段
+说明
+
+
+===== PAGE 8 =====
+第6 页
+任务清单
+必选,关联保养模板
+执行人员
+可多选
+设备
+树形选择
+任务开始/结束时间
+计划时间窗口
+维护计划
+点击新增按钮,进入新增预防性维护计划界面。新增维护计划时需选择任务
+清单。
+注:选择执行人员时,需选择具备对应的技能的人员,否则系统将给出提示,
+无法保存成功。
+维护计划新增
+
+
+===== PAGE 9 =====
+第7 页
+3.2.3.
+我的维护计划
+路径:设备管理→预防性维护→我的维护计划。
+此模块用于展示所有分派给我的维修计划,支持查看任务详情和处理(提交
+维修结果)操作。
+注:系统支持用户使用系统后台或PDA 完成维护计划。
+我的维修记录
+点击处理按钮,进入提交维修结果界面,待处理计划可点击「处理」:填写
+结束时间、提交内容、上传图片、登记易耗品用量。支持在此界面填写提交内容、
+上传完成图片和易耗品记录。
+我的维护记录-处理
+
+
+===== PAGE 10 =====
+第8 页
+3.3.
+紧急性维修
+3.3.1.
+维修记录管理
+路径:设备管理→紧急性维修→维修记录管理。
+此模块用于展示所有设备的维修记录,支持对维修记录进行增删改查操作。
+关键操作:新增维修→选择设备→关联故障现象(来自设备运行状态)→填
+写维修内容、时间、图片、易耗品。
+注:用户也可使用PDA 中紧急性维修模块扫描设备二维码,提交维修记录。
+维修记录管理查询字段表
+查询字段
+说明
+设备/维修人员
+树形选择
+维修内容/状态/备注
+维修信息
+维修记录
+3.3.2.
+我的维修记录
+路径:设备管理→紧急性维修→我的维修记录。
+此模块用于展示我的维修记录列表,可对维修记录进行增删改查操作。
+
+
+===== PAGE 11 =====
+第9 页
+我的维修记录
+3.4.
+设备运行状态
+路径:设备管理→设备运行状态。
+此模块用于展示设备运行状态的上传数据,包括设备编号、状态、起止时间、
+时长、处理人、工件码等,可对设备运行状态列表进行查询和导出操作。
+设备运行状态
+4. 业务流程
+建议业务流程:
+
+
+===== PAGE 12 =====
+第10 页
+1. 维护设备分类→设备清单(生成二维码);
+2. 配置任务清单→创建维护计划→执行人处理(我的维护计划);
+3. 设备故障上报(运行状态)→创建维修记录→登记易耗品(自动写入易耗品
+记录)。
+5. 常见问题
+Q1:PDA 扫码找不到设备?
+确认设备清单中sn 与二维码一致,设备状态为正常。
+Q2:维护计划无法处理?
+确认计划状态为待处理,且当前用户为执行人员,具备deal 权限。
+Q3:易耗品记录为空?
+记录在维修/保养提交时自动产生,需在处理表单中填写易耗品用量。

+ 301 - 0
_apk_work/manuals_text/3、物料管理操作手册.txt

@@ -0,0 +1,301 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——物料管理操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. 物料管理模块概述.................................................................................................. 1
+3. 功能操作.................................................................................................................. 3
+3.1. 物料总库存.................................................................................................... 3
+3.2. 物料列表........................................................................................................ 4
+3.2.1. 检查项.................................................................................................. 6
+3.3. 来料库存记录................................................................................................ 7
+4. 数据关系说明.......................................................................................................... 8
+5. 常见问题.................................................................................................................. 9
+
+
+===== PAGE 3 =====
+第1 页
+1. 文档说明
+本文档面向MES 后台管理端用户,说明「物料管理」模块的功能入口、操
+作步骤及注意事项。
+适用对象:仓库管理员、物料计划员、质量检验员、系统管理员。
+使用前提:
+已登录MES 后台管理系统;
+当前账号已分配对应菜单及操作权限;
+
+物料基础数据、库位等主数据已由管理员维护完成。
+2. 物料管理模块概述
+MES 后台端物料管理模块主要用于物料基础档案与库存信息的管理,包含
+物料总库存、物料列表、来料库存记录三项功能。
+物料总库存:展示物料整体库存数据,支持库存查询与按明细重算刷新,掌
+握物料库存总体情况。
+物料列表:用于维护物料基础档案,支持物料信息的增删改查、停用/启用、
+导入导出以及检查项管理,建立完整的物料基础数据。
+来料库存记录:用来查看来料相关库存记录,支持查询记录,同时可查看、
+打印批次二维码,实现来料批次的标识管理。
+模块关系简述:
+先在「物料列表」中建立物料档案;
+来料入库、ERP 生产领料等业务产生「来料库存记录」(按批次存储);
+「物料总库存」由明细记录自动汇总;数量异常时可手动重算。
+物料管理模块概述表
+功能
+说明
+物料总库存
+按物料种类汇总当前总库存数量,支持查询
+与按明细重算。
+物料列表
+维护物料基础档案,支持增删改查、停用/启
+
+
+===== PAGE 4 =====
+第2 页
+用、导入/导出及检查项配置。
+来料库存记录
+查看每一批次的来料/领料库存明细,支持多
+条件查询及批次二维码查看、打印。
+
+
+===== PAGE 5 =====
+第3 页
+3. 功能操作
+3.1. 物料总库存
+路径:物料管理→物料总库存。
+此模块用于展示展示每种物料的当前总库存数量。数据按「来料库存记录」
+明细自动汇总;明细发生入库、出库、领料等变动时会同步更新。可对库存列表
+进行查询和按明细重算(刷新)操作。
+查询操作:
+1.
+进入「物料管理→物料总库存」。
+2.
+点击右上角「查询」按钮,展开查询条件。
+3.
+可按「物料名称」「ERP 料号」筛选,点击「查询」执行;点击「重置」
+清空条件。
+按明细重算操作:(重算为全量操作,请在业务低峰期执行,正常情况下无
+需频繁重算)
+当总库存与明细不一致时,具有编辑权限的用户可执行重算:
+1.
+点击右上角「按明细重算」按钮。
+2.
+在确认对话框中点击确定。
+3.
+系统将按全部来料库存明细重新汇总,并提示更新物料种类数。
+注:按物料列表种类汇总当前总库存;明细变动时自动同步。数量异常时可点
+「按明细重算」。
+物料总库存查询字段表
+字段
+说明
+物料名称
+物料档案中的部件名称
+ERP 料号
+与ERP 系统对应的物料编码
+规格
+物料规格型号
+总库存
+当前汇总库存数量
+更新时间
+最近一次库存汇总更新时间
+
+
+===== PAGE 6 =====
+第4 页
+物料总库存
+3.2. 物料列表
+路径:物料管理→物料列表。
+此模块用于护物料基础档案,是库存、来料检验、生产领料等业务的数据基
+础。可对物料列表进行增删改查、停用/启用、导入/导出及检查项管理操作。
+新增/编辑物料操作:
+1.
+点击「新增」进入编辑页,或点击列表行「编辑」图标。
+2.
+填写基本信息:部件名称、规格、ERP 编码、内部图号、数量/套、加工
+属性、供应商、有效期、追溯类型、备注等。
+3.
+可按需上传物料图片。
+4.
+点击「保存」提交。
+字段说明:
+
+有效期:单位为「月」,填写0 表示该物料不设有效期。
+
+追溯类型:决定物料在生产过程中的追溯方式,请按实际业务选择。
+
+ERP 编码:建议与ERP 保持一致,便于领料、入库对接。
+停用/启用/删除操作:
+
+停用:点击列表「停用」图标,停用后该物料不可用于新业务(历史数
+据保留)。
+
+启用:对已停用物料点击「启用」图标恢复使用。
+
+
+===== PAGE 7 =====
+第5 页
+
+删除:点击「删除」图标,确认后永久删除(请谨慎操作,建议优先使
+用停用)。
+导入/导出操作:
+导出:
+1.
+设置查询条件(可选)后,点击「导出」。
+2.
+系统按当前查询结果导出Excel 文件。
+导入:
+1.
+点击「导入」,在弹窗中选择xls 或xlsx 文件。
+2.
+可先点击「下载模板」获取标准导入模板,按模板填写后上传。
+3. 导入成功后列表自动刷新。
+物料列表查询条件表
+条件
+说明
+部件名称
+支持模糊查询
+部件规格
+物料规格
+ERP 编码
+ERP 物料编码
+内部图号
+企业内部图纸编号
+加工属性
+加工相关属性
+供应商
+默认或主要供应商
+有效期
+有效期(月),0 表示无有效期
+追溯类型
+字典:mes_material_type
+状态
+正常/停用
+
+
+===== PAGE 8 =====
+第6 页
+物料列表
+3.2.1.检查项
+路径:物料管理→物料列表→列表右侧操作
+。
+此操作主要用来为每种物料配置来料检验项目,供来料检验环节使用。检查
+项与具体物料绑定,不同物料可配置不同检验内容。
+详细步骤:
+1.
+在「物料列表」中,点击目标物料行的「检查项」链接。
+2.
+进入该物料的检查项列表,可查询、新增、编辑、删除检查内容。
+3. 新增/编辑时需填写:项目(检验分类)、检查内容、判定类型、最小值/
+最大值(数值型判定时使用),并可上传参考图片。
+检查项列表字段表
+字段
+说明
+项目
+检验项目分类(字典:mes_material_org)
+检查内容
+具体检验要求描述
+判定类型
+如:合格/不合格、数值范围等(字典:
+mes_material_check_type)
+最小值/最大值
+数值型判定的上下限
+状态
+正常/停用
+
+
+===== PAGE 9 =====
+第7 页
+3.3. 来料库存记录
+路径:物料管理→来料库存记录。
+此模块用于展示来料库存记录,记录每一批次的来料/领料库存明细,是库
+存追溯的核心数据。每条记录对应一个批次码,包含物料、库位、数量、来源、
+失效时间等信息。可对来料库存记录列表进行查询及查看、打印批次二维码操作。
+列表「操作」列点击二维码图标,展示该批次码对应的二维码(内容为批次
+码),点击「打印」可打印二维码标签,用于现场贴标、扫码领料/检验。
+说明:本页面以查询、查看为主,新增入口默认关闭,库存明细通常由来料
+入库、ERP 生产领料等业务自动生成。
+来料库存记录查询条件表
+条件
+说明
+物料
+按物料名称筛选
+批次码
+批次唯一标识,支持精确/模糊查询
+库位
+存放库位名称
+来源
+全部/ERP 生产领料/来料入库
+入库类型
+来料入库时的业务类型(字典:
+mes_material_rk_type)
+ERP 领料单号
+ERP 领料单编号
+入库时间
+起止时间范围
+来料库存记录列表字段表
+字段
+说明
+物料
+物料名称
+批次码
+批次唯一标识,用于扫码追溯
+库位
+当前存放库位
+数量
+该批次当前库存数量
+来源/类型
+ERP 生产领料或来料入库类型
+ERP 领料单号
+关联ERP 领料单(如有)
+
+
+===== PAGE 10 =====
+第8 页
+ERP 生产订单
+关联ERP 生产订单号(如有)
+失效时间
+物料有效期截止时间
+入库时间
+批次入库/入账时间
+入库人
+操作人
+原批次码
+拆分或变更前的原批次码(如有)
+来料库存记录
+4. 数据关系说明
+1.
+物料管理各功能之间的数据流向如下:
+2.
+物料列表:建立物料主数据(名称、ERP 编码、追溯类型等)。
+3.
+检查项:为物料配置检验标准。
+4.
+来料库存记录:业务入库/领料后产生批次明细(含批次码、库位、数量)。
+5.
+物料总库存:由明细记录按物料汇总;明细变动自动同步,必要时可手
+动重算。
+建议操作顺序:维护物料档案→配置检查项→业务产生库存明细→通过总库
+存掌握整体情况。
+
+
+===== PAGE 11 =====
+第9 页
+5. 常见问题
+Q1:总库存数量与明细对不上怎么办?
+先核对来料库存记录明细是否正确;确认无误后,在「物料总库存」执行「按
+明细重算」。
+Q2:找不到某个物料的库存记录?
+检查该物料是否已入库或ERP 领料成功;在来料库存记录中放宽查询条件
+(如仅按物料名称查询)。
+Q3:导入物料失败?
+确认文件为xls/xlsx 格式;使用系统提供的导入模板;检查ERP 编码、追溯
+类型等字典值是否合法。
+Q4:无法新增/编辑/删除?
+联系管理员确认是否已分配mes:mesMaterial:edit 等编辑权限。
+Q5:批次二维码扫出来是什么?
+二维码内容为批次码字符串,现场扫码设备需配置为识别该批次码并关联
+MES 业务。

+ 263 - 0
_apk_work/manuals_text/4、质量管理操作手册.txt

@@ -0,0 +1,263 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——质量管理操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. 质量管理模块概述.................................................................................................. 1
+3. 功能操作.................................................................................................................. 3
+3.1. 返修问题清单................................................................................................ 3
+3.2. 抽检记录........................................................................................................ 3
+3.3. 返修记录........................................................................................................ 4
+3.4. 报废记录........................................................................................................ 5
+3.5. 恢复记录........................................................................................................ 6
+3.6. 首件检查记录................................................................................................ 6
+3.7. 工具寿命更换记录........................................................................................ 7
+3.8. 开班点检记录................................................................................................ 8
+3.9. 检测样件设置................................................................................................ 9
+3.10. 发货检记录.................................................................................................. 9
+4. 常见问题................................................................................................................ 10
+
+
+===== PAGE 3 =====
+第1 页
+1. 文档说明
+本文档介绍大洋MES 质量管理模块操作方法,覆盖质量问题配置、多类检
+验记录查询、不良工件返修报废恢复处置及发货检验业务。说明各功能菜单路径、
+字段、操作要点,留存质量台账,为生产全流程质量管控提供操作指引。
+2. 质量管理模块概述
+质量管理为MES 后台系统质量业务管理模块,统筹生产全流程质量业务管
+控与质量台账数据留存,主要功能如下:
+返修问题清单:维护质量问题基础清单,支持数据增删改查、启用停用、导
+入导出,为不良处置业务提供标准化问题选项。
+抽检记录:保存生产过程中的抽检检测数据,可查询导出检验详情,实现生
+产过程质量管控留痕。
+返修记录:记录工件返修全流程信息,留存返修处置业务台账,支持查询导
+出,跟踪不良工件返修处理情况。
+报废记录:管理工件报废业务数据,归档报废判定相关记录,实现报废工件
+信息可查可追溯。
+恢复记录:保存报废工件恢复业务记录,记录工件恢复处置过程,支持台账
+查询导出。
+首件检查记录:留存首件检验业务台账,支持记录查询、导出、详情查看,
+对开工首件检验结果进行归档。
+工具寿命更换记录:记录工装工具寿命更换作业信息,实现工具更换历史台
+账归档管理。
+开班点检记录:留存开班点检作业记录,支持记录查询及详情查看,保障生
+产开工前设备状态合规。
+检测样件设置:维护检验业务所需样件基础配置,完成样件相关信息管理,
+为检验工作提供基础数据支撑。
+发货检验记录:归档成品发货环节检验数据,记录发货检测结果,把控产品
+出厂质量关口。
+
+
+===== PAGE 4 =====
+第2 页
+质量管理模块概述表
+功能
+说明
+主要操作
+返修问题清单
+质量问题标准选项库
+增删改查、导入/导出
+抽检记录
+生产过程抽检台账
+查询、导出、详情
+返修/报废/恢复记录
+不良工件处置台账
+查询、导出、详情、审核
+首件检查记录
+开工首件检验归档
+查询、导出、详情
+工具寿命更换记录
+工装更换历史
+查询、导出、更换登记
+开班点检记录
+工位开班点检台账
+查询、详情
+检测样件设置
+样件标准配置
+增删改查、导入/导出
+发货检记录
+成品发货检验
+查询、详情(PDA 录入)
+
+
+===== PAGE 5 =====
+第3 页
+3. 功能操作
+3.1.
+返修问题清单
+路径:质量管理→返修问题清单。
+本模块用于返修问题清单的管理与维护,支持对返修清单进行增删改查、停
+用/启用及导入/导出等操作,并可维护返修原因、返工动作、检查要点等标准选
+项。
+返修问题清单查询字段表
+查询字段
+说明
+工位号/产线编号
+适用范围
+返修原因/返工类型
+问题分类
+状态
+正常/停用
+返修问题清单
+3.2.
+抽检记录
+路径:质量管理→抽检记录。
+本模块用于展示所有抽检记录,支持查询、导出数据列表和查看抽检记录详
+情操作。
+
+
+===== PAGE 6 =====
+第4 页
+抽检记录查询字段表
+查询字段
+说明
+工件码/工位/产线编号
+被检工件
+类型/检查结果
+检验信息
+检查日期
+起止范围
+抽检记录
+3.3.
+返修记录
+路径:质量管理→返修记录。
+本模块用于展示所有返修记录,支持查询、导出数据列表和查看返修记录详
+情操作。
+返修记录查询字段表
+查询字段
+说明
+工件码/产品型号
+工件信息
+状态/维修结果
+处置状态
+上报人/维修人/维修时间
+人员与时间
+
+
+===== PAGE 7 =====
+第5 页
+返修记录
+3.4.
+报废记录
+路径:质量管理→报废记录。
+本模块用于展示所有报废记录,支持查询/删除、导出数据列表及查看报废
+记录详情,并管理工件报废的申请与审核;待审核状态的记录可执行「审核」,
+评审中的记录可执行「线下评审」,且均支持查看记录详情。
+报废记录
+
+
+===== PAGE 8 =====
+第6 页
+3.5.
+恢复记录
+路径:质量管理→恢复记录。
+本模块用于展示工件返修恢复正常记录,支持查询、导出、数据和查看恢复
+记录详情操作。
+恢复记录查询字段表
+查询字段
+说明
+工件码
+工件标识
+恢复原因/恢复时间
+恢复信息
+恢复记录
+3.6.
+首件检查记录
+路径:质量管理→首件检查记录。
+本模块用于展示首件检查记录,支持查询、导出数据列表和查看首件检查记
+录详情操作。
+首件检查记录查询字段表
+查询字段
+说明
+工件码/工位号/产线编号
+首件信息
+
+
+===== PAGE 9 =====
+第7 页
+类型/状态/检查结果
+检验结果
+检查人/检查时间
+执行信息
+首件检查记录
+3.7.
+工具寿命更换记录
+路径:质量管理→工具寿命更换记录。
+本模块用于展示全部工具寿命更换记录,支持记录查询、数据导出及工具更
+换操作,工装工具更换历史数据取自工具寿命模块,可点击「更换工具」完成新
+工具更换的登记。
+工具寿命更换记录查询字段表
+查询字段
+说明
+名称/唯一标识
+工具信息
+更换人/更换时间
+更换记录
+
+
+===== PAGE 10 =====
+第8 页
+工具寿命更换记录
+3.8.
+开班点检记录
+路径:质量管理→开班点检记录。
+本模块用于展示所有开班点检记录,支持查询和查看开班点检记录详情操作。
+开班点检记录查询字段表
+查询字段
+说明
+产线编号/工位号
+工位信息
+创建日期
+点检时间范围
+开班点检记录
+
+
+===== PAGE 11 =====
+第9 页
+3.9.
+检测样件设置
+路径:质量管理→检测样件设置。
+本模块用于管理检测样件信息,可配置各工位检测样件的上下限标准,支持
+对检测样件执行增删改查、启用/禁用以及导入导出操作。
+检测样件设置查询字段表
+查询字段
+说明
+工件码/工位号/产线编号
+样件标识
+类型/备注/状态
+样件属性
+检测样件管理
+3.10. 发货检记录
+路径:质量管理→发货检记录。
+本模块用于展示全部发货检记录,支持数据列表的查询、导出及发货检记录
+详情查看,存储成品发货前的批次检验记录,可通过PDA 端扫描批次码提交
+OK/NG 检验结果。
+发货检记录查询字段表
+查询字段
+说明
+批次码/产线编号
+发货批次
+
+
+===== PAGE 12 =====
+第10 页
+结果(OK/NG)
+检验结论
+检查时间
+起止范围
+发货检记录
+4. 常见问题
+Q1:返修问题清单导入失败?
+使用系统模板,检查返工类型等字典值是否合法。
+Q2:报废记录无法审核?
+确认具备apply 权限,且记录状态为待审核。
+Q3:发货检数据从哪里来?
+主要由PDA 端扫描批次码提交,后台以查询为主。

+ 386 - 0
_apk_work/manuals_text/5、生产管理操作手册.txt

@@ -0,0 +1,386 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——生产管理操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. 生产管理模块概述.................................................................................................. 1
+3. 功能操作.................................................................................................................. 3
+3.1. 产品生产记录................................................................................................ 3
+3.1.1. 查询...................................................................................................... 4
+3.1.2. 导出...................................................................................................... 5
+3.1.3. 新增...................................................................................................... 5
+3.1.4. 修改...................................................................................................... 6
+3.1.5. 查看产品记录详情.............................................................................. 7
+3.1.6. 重置...................................................................................................... 7
+3.1.7. 提交(OK)..............................................................................................8
+3.2. 产品修改记录................................................................................................ 8
+3.3. 加工消耗扣料日志........................................................................................ 9
+3.4. PDA 扫码记录.............................................................................................. 10
+3.5. 大屏通知...................................................................................................... 10
+3.6. 荣誉榜单.......................................................................................................11
+3.7. 产品管理...................................................................................................... 12
+3.8. 工艺过程参数.............................................................................................. 12
+3.8.1. CCD 视觉检测记录............................................................................ 12
+3.8.2. 白件气密............................................................................................ 13
+3.8.3. 涂胶加工时长.................................................................................... 13
+3.8.4. 总成气密............................................................................................ 14
+3.8.5. 拉铆过程参数.................................................................................... 14
+3.8.6. 115 弧焊参数.......................................................................................15
+3.8.7. HEV 点焊参数.................................................................................... 16
+3.8.8. 凸焊数据............................................................................................ 17
+3.8.9. HEV 弧焊参数.................................................................................... 17
+3.9. 工位生产时间.............................................................................................. 18
+
+
+===== PAGE 3 =====
+3.10. 工位当前产品............................................................................................ 19
+3.11. 批次码记录表.............................................................................................19
+3.12. 开班点检记录............................................................................................ 20
+3.13. 打印记录.................................................................................................... 21
+3.14. 工资核算.................................................................................................... 21
+4. 常见问题................................................................................................................ 22
+
+
+===== PAGE 4 =====
+第1 页
+1. 文档说明
+本文档讲解大洋MES 生产管理模块操作,涵盖工件生产记录维护、各类工
+艺参数采集查询、大屏内容维护、计件工资核算等业务,说明菜单路径、查询导
+出编辑等操作,支撑生产追溯、工艺分析与薪资统计工作。
+2. 生产管理模块概述
+生产管理是MES 后台系统的核心业务模块,覆盖车间工件生产执行、设备
+工艺采集、现场作业留痕、产线监控、信息公示及计件薪资统计等业务,为生产
+追溯、工艺分析、薪资核算提供完整的数据支撑,主要功能如下:
+产品生产记录:管理工件生产台账,记录各工位加工结果与工艺信息,实现
+生产记录的查询、导出、新增、修改、查看详情、重置、提交OK 操作。
+产品修改记录:留存产品数据全部变更历史,支持查询导出,实现业务变更
+过程可追溯。
+加工消耗扣料日志:记录加工过程物料扣料信息,提供日志查询能力。
+PDA 扫码记录:归档移动端扫码作业数据,支持记录查询及详情查看。
+大屏通知:维护大屏公告内容,完成内容增删改查,配置是否上屏展示。
+荣誉榜单:管理车间荣誉榜单信息,支持内容维护,控制是否投放大屏公示。
+产品管理:维护工件全生命周期档案,跟踪生产中、合格、返修中、已报废、
+待处理等产品状态。
+工艺过程参数:统一归集CCD 视觉检测、各类气密、涂胶、拉铆、弧焊、
+点焊、凸焊等设备的工艺检测数据,支持查询、导出、详情查看、部分数据新增。
+工位生产时间:统计工件各工位加工时长,支持数据查询与导出。
+工位当前产品:展示各工位正在加工的工件信息,掌握产线在制生产情况。
+批次码记录表:维护批次码数据,实现工件绑定、二维码打印、查询及详情
+查看。
+开班点检记录:保存开工点检作业台账,支持记录查询与详情查看。
+打印记录:留存标签打印历史,提供打印日志查询功能。
+工资核算:完成员工计件工资统计,支持查询、导出、查看详情以及计件单
+
+
+===== PAGE 5 =====
+第2 页
+价维护。
+生产管理模块概述表
+功能
+说明
+产品生产记录
+按工件码聚合的生产过程主记录
+产品修改记录
+生产结果变更追溯
+加工消耗扣料日志
+OK 后自动扣料记录
+PDA 扫码记录
+现场扫码作业记录
+大屏通知/荣誉榜单
+大屏轮播内容维护
+产品管理
+在制/完工产品台账
+工艺过程参数
+CCD、气密、涂胶等工序数据
+打印记录/工资核算
+标签打印日志与计件工资
+
+
+===== PAGE 6 =====
+第3 页
+3. 功能操作
+3.1. 产品生产记录
+路径:生产管理→产品生产记录。
+本模块主要展示所有工件的生产记录,记录每个工位的工位结果及相关过程
+参数,支持增删改查、导出、重置、修改工位结果为ok 操作。
+产品生产记录查询字段表
+查询字段
+说明
+工件码/工位号/工艺号
+生产定位
+工件类型/绑定内容/结果/加工状态
+生产状态
+更新日期
+起止范围
+产品生产记录
+点击
+按钮和
+按钮即可查看明细详细记录。
+
+
+===== PAGE 7 =====
+第4 页
+产品生产记录-明细
+3.1.1.查询
+路径:生产管理→产品生产记录→查询。
+点击页面右上方
+查询按钮,会显示查询条件输入框,根
+据需求输入查询条件,点击查询按钮完成筛选查询。
+产品生成记录-查询
+
+
+===== PAGE 8 =====
+第5 页
+3.1.2.导出
+路径:点击「查询」展开条件→设置筛选→查询/重置→点击「导出」导出
+Excel。
+点击页面右上方
+导出按钮,会自动导出下载根据查询
+筛选后的所有数据。
+产品生成记录-导出
+3.1.3.新增
+路径:生产管理→产品生产记录→新增。
+点击页面右上方
+新增按钮,进入新增页面,选择产线,
+输入需要新增的工件码,点击保存按钮,完成保存。
+
+
+===== PAGE 9 =====
+第6 页
+产品生成记录-保存
+3.1.4.修改
+路径:生产管理→产品生产记录→修改图标。
+点击操作栏中
+编辑按钮,进入编辑页面,该页面可以对该工件
+的加工结果、绑定内容、备注等进行修改,修改完数据后,点击下方保存按钮完
+成修改操作。
+产品生成记录-修改
+
+
+===== PAGE 10 =====
+第7 页
+3.1.5.查看产品记录详情
+路径:生产管理→产品生产记录→查看图标。
+点击操作栏中
+查看按钮,进入到生产记录详情页面,可以在该
+页面查看该工件的详细信息。
+产品生成记录-查看详情
+3.1.6.重置
+路径:生产管理→产品生产记录→重置图标。
+点击操作栏中
+重置按钮,可以重置该条数据的结果列为UDF,
+绑定内容列为空。
+
+
+===== PAGE 11 =====
+第8 页
+产品生成记录-重置
+3.1.7.提交(OK)
+路径:生产管理→产品生产记录→提交图标。
+点击操作栏中
+提交(OK)按钮,可以改变该条数据的结果列为
+OK。
+产品生成记录-提交(OK)
+3.2. 产品修改记录
+路径:生产管理→产品修改记录。
+本模块主要展示所有产品数据的修改历史,记录字段包括工件码、工位号、
+
+
+===== PAGE 12 =====
+第9 页
+工艺号、原结果、结果、来源、更新人及更新时间,并提供按条件查询与数据导
+出功能。
+产品修改记录查询字段表
+查询字段
+说明
+工件码/工位号/工艺号
+定位信息
+原结果/结果/来源
+变更内容
+产品修改记录
+3.3. 加工消耗扣料日志
+路径:生产管理→加工消耗扣料日志。
+本模块用于展示全部加工消耗扣料日志,仅支持只读查询;加工完成OK 后,
+系统将按工位绑定物料实现自动扣减。
+加工消耗扣料日志查询字段表
+查询字段
+说明
+扣料时间/工件码/工位号/产线
+扣料定位
+物料名称/ERP 料号/批次码
+扣料明细
+
+
+===== PAGE 13 =====
+第10 页
+加工消耗扣料日志
+3.4. PDA 扫码记录
+路径:生产管理→PDA 扫码记录。
+本模块用于展示所有PDA 扫码记录,支持查询和查看PDA 扫码记录详情操
+作,记录现场PDA 扫码作业。
+PDA 扫码记录
+3.5. 大屏通知
+路径:生产管理→大屏通知。
+
+
+===== PAGE 14 =====
+第11 页
+本模块用于展示大屏通知信息,编辑或新增大屏通知时可选择是否上屏,支
+持对大屏通知进行增删改查操作。
+大屏通知
+3.6. 荣誉榜单
+路径:生产管理→荣誉榜单。
+本模块用于展示荣誉榜单信息,编辑或新增荣誉榜单时可选择是否上屏,支
+持对荣誉榜单进行增删改查操作。
+荣誉榜单
+
+
+===== PAGE 15 =====
+第12 页
+3.7. 产品管理
+路径:生产管理→产品管理。
+本模块主要展示全部工件产品记录,可查询在制、完工产品台账,核心字段
+包含工件码、产品类型、当前状态、创建日期、更新日期;产品状态包含生产中、
+合格、返修中、已报废、待处理五种关键节点。
+产品管理查询字段表
+查询字段
+说明
+工件码/状态/类型
+产品信息
+创建/更新日期
+时间范围
+产品管理
+3.8. 工艺过程参数
+3.8.1.CCD 视觉检测记录
+路径:生产管理→工艺过程参数→CCD 视觉检测记录。
+本模块主要展示CCD 检测设备对工件的检测记录及相关参数,支持查询与
+导出操作,可依据工件码、工位号、产线编号、检测结果、创建时间进行条件查
+询。
+
+
+===== PAGE 16 =====
+第13 页
+CCD 视觉检测记录
+3.8.2.白件气密
+路径:生产管理→工艺过程参数→白件气密
+本模块主要展示白件气密检测记录及相关参数,支持查询、导出操作。
+白件气密
+3.8.3.涂胶加工时长
+路径:生产管理→工艺过程参数→涂胶加工时长
+本模块主要展示对工件涂胶加工的时长记录及相关参数,支持查询、新增操
+
+
+===== PAGE 17 =====
+第14 页
+作。
+涂胶加工时长
+3.8.4.总成气密
+路径:生产管理→工艺过程参数→总成气密
+本模块主要展示总成气密检测记录及相关参数,支持查询、导出操作。
+总成气密
+3.8.5.拉铆过程参数
+路径:生产管理→工艺过程参数→拉铆过程参数
+
+
+===== PAGE 18 =====
+第15 页
+本模块主要展示拉铆设备对工件加工记录及相关参数,支持查询、导出操作。
+拉铆过程参数
+3.8.6.115 弧焊参数
+路径:生产管理→工艺过程参数→115 弧焊参数
+本模块主要展示115 弧焊设备对工件加工记录及相关参数,支持查询、导出
+和查看详情操作。
+115 弧焊参数
+
+
+===== PAGE 19 =====
+第16 页
+115 弧焊参数-详情
+3.8.7.HEV 点焊参数
+路径:生产管理→工艺过程参数→HEV 点焊参数
+本模块主要展示点焊设备对工件加工记录及相关参数,支持查询、导出和查
+看详情操作。
+HEV 点焊参数
+
+
+===== PAGE 20 =====
+第17 页
+HEV 点焊参数-详情
+3.8.8.凸焊数据
+路径:生产管理→工艺过程参数→凸焊数据
+本模块主要展示凸焊设备对工件加工记录及相关参数,支持查询和查看详情
+操作。
+凸焊参数
+3.8.9.HEV 弧焊参数
+路径:生产管理→工艺过程参数→HEV 弧焊参数
+
+
+===== PAGE 21 =====
+第18 页
+本模块主要展示弧焊设备对工件加工记录及相关参数,支持查询、导出和查
+看详情操作。
+HEV 弧焊参数
+HEV 弧焊参数-详情
+3.9. 工位生产时间
+路径:生产管理→工位生产时间
+本模块主要展示各个工件在不同工位的加工时间,包括工位号、工件码、开
+始时间、结束时间、生产时长等。支持查询、导出记录操作。
+
+
+===== PAGE 22 =====
+第19 页
+工位生产时间
+3.10. 工位当前产品
+路径:生产管理→工位当前产品
+本模块主要展示产线上各工位当前生产工件信息,支持查询操作。
+工位当前产品
+3.11. 批次码记录表
+路径:生产管理→批次码记录表
+本模块主要展示所有批次码记录,包括批次码、产线编号、已绑定数量、是
+
+
+===== PAGE 23 =====
+第20 页
+否用完、状态和创建人等信息。支持查询、批量打印和查看记录详情,绑定工件
+码、查看、新增及打印批次二维码操作。
+批次码记录表
+3.12. 开班点检记录
+路径:生产管理→开班点检记录
+本模块用于展示所有开班点检记录,支持查询和查看开班点检记录详情操作。
+开班点检记录
+
+
+===== PAGE 24 =====
+第21 页
+3.13. 打印记录
+路径:生产管理→打印记录
+本模块用于展示所有打印记录,支持查询操作。
+打印记录
+3.14. 工资核算
+路径:生产管理→工资核算
+本模块主要展示计件工资进行核算,包括人员编码、人员姓名、总件数和工
+资总金额,支持查询、查看详情、导出和单价维护操作。
+工资核算查询字段表
+查询字段
+说明
+生产时间/产线编号/工位号/人员编码
+核算范围
+
+
+===== PAGE 25 =====
+第22 页
+工资核算
+4. 常见问题
+Q1:生产记录明细为空?
+确认该工件已在产线客户端完成过站。
+Q2:扣料日志没有记录?
+检查工位是否绑定物料、加工结果是否为OK。
+Q3:工资核算金额不对?
+先核对单价维护配置,再确认生产记录时间范围。

+ 212 - 0
_apk_work/manuals_text/6、ERP对接操作手册.txt

@@ -0,0 +1,212 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——ERP 对接操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. ERP 对接模块概述.................................................................................................. 1
+3. 功能操作.................................................................................................................. 3
+3.1. ERP 生产领料单查询.....................................................................................3
+3.2. ERP 生产订单查询.........................................................................................4
+3.3. ERP 排产计划.................................................................................................5
+3.4. ERP 直接调拨单查询.....................................................................................6
+3.5. ERP 生产入库单查询.....................................................................................7
+3.6. ERP 下推日志.................................................................................................9
+3.7. ERP 排产看板...............................................................................................10
+4. 常见问题.................................................................................................................11
+
+
+===== PAGE 3 =====
+第1 页
+1. 文档说明
+本文档说明大洋MES 与ERP 系统对接功能操作,包含领料、生产订单、排
+产计划、调拨、入库等单据查询维护,介绍单据下推操作与接口日志查看方法,
+保障跨系统业务交互可查询、可追溯。
+2. ERP 对接模块概述
+ERP 对接是MES 后台系统的跨系统交互模块,主要实现MES 与ERP 系统
+之间各类业务单据的数据同步、接收与下发,打通两个系统业务流程,留存接口
+交互记录,保障跨系统业务可查询、可追溯,主要功能如下:
+ERP 生产领料单查询:查看从ERP 同步过来的生产领料单据信息,支持单
+据查询、新增及单据详情查阅。
+ERP 生产订单查询:展示指定存货类别的ERP 生产订单,支持查询、下查、
+下推操作,实现生产订单向MES 系统下发。
+ERP 排产计划:维护排产计划数据,支持增删改查、查看详情,可切换甘
+特看板视图直观展示排产信息。
+ERP 直接调拨单查询:管理ERP 调拨业务单据,支持新增、查询、查看详
+情,外发调拨可关联托盘批次码完成业务提交。
+ERP 生产入库单查询:展示ERP 生产入库单据,支持新增、查询、绑定
+MES 业务、查看单据详情。
+ERP 下推日志:记录各类单据向ERP 推送交互的完整执行信息,支持查询、
+导出、查看交互详情,用于对接异常问题排查追溯。
+ERP 排产看板:以可视化看板形式展示排产计划,同时可切换列表模式完
+成排产数据维护操作。
+ERP 对接模块概述表
+功能
+说明
+ERP 生产领料单
+查询/新增领料单,同步至ERP
+ERP 生产订单
+查询订单,下查关联单据,下推领料/入库/
+
+
+===== PAGE 4 =====
+第2 页
+排产
+ERP 排产计划
+维护排产,支持甘特看板
+ERP 直接调拨单
+调拨业务,PDA 可扫码累加
+ERP 生产入库单
+生产完工入库,可绑定MES 批次
+ERP 下推日志
+接口交互记录,用于异常排查
+
+
+===== PAGE 5 =====
+第3 页
+3. 功能操作
+3.1. ERP 生产领料单查询
+路径:ERP 对接→ERP 生产领料单查询。
+本模块主要用于展示ERP 生产领料单信息,支持对列表信息进行查询、新
+增和查看详情。
+关键操作:点击「增加领料单」→选择ERP 生产订单分录→填写领料明细
+→保存并下推ERP;
+注:本页统计的是领料单张数,与生产订单条数不是一一对应:一张生产订
+单可有多张领料单,也可能尚未领料。留空生产订单号时展示全部已关联生产订
+单的领料单。
+ERP 生产领料单查询字段表
+查询字段
+说明
+生产订单号/领料单号/物料编码
+单据筛选
+ERP 生产领料单查询
+
+
+===== PAGE 6 =====
+第4 页
+ERP 生产领料单查询-详情
+3.2. ERP 生产订单查询
+路径:ERP 对接→ERP 生产订单查询。
+本模块主要用于展示ERP 生产订单信息,支持查询、下查和下推操作。
+关键操作:查看明细→「下查」查看关联领料/入库/排产→「下推」跳转创
+建领料单/入库单/排产。
+注:仅展示存货类别为HEV、欣旺达115 或115 的生产订单分录;明细行
+数/总数量仅统计上述类别(不再按固定物料编码过滤)。
+ERP 生产订单查询字段表
+查询字段
+说明
+生产订单号
+订单编号
+ERP 生产订单查询
+
+
+===== PAGE 7 =====
+第5 页
+3.3. ERP 排产计划
+路径:ERP 对接→ERP 排产计划。
+本模块主要用于展示ERP 排产计划,支持对计划列表进行增删改查和查看
+详情,也可以切换到甘特看板界面查看数据。
+关键操作:新增排产(选ERP 订单分录)→填写产线、排产起止、数量→
+保存;可编辑/删除/查看详情。
+ERP 排产计划字段表
+查询字段
+说明
+生产订单号/产线/存货类别
+排产筛选
+ERP 排产计划
+点击
+看板按钮可切换到看板界面。
+
+
+===== PAGE 8 =====
+第6 页
+ERP 排产计划-看板
+3.4. ERP 直接调拨单查询
+路径:ERP 对接→ERP 直接调拨单查询。
+本模块主要用于展示ERP 直接调拨单信息,支持对订单进行新增、查询和
+查看详情操作。
+关键操作:新增调拨单→填写调出/调入仓库及明细→保存下推;PDA 可扫
+码累加调拨数量。
+ERP 直接调拨单查询字段表
+查询字段
+说明
+调拨单号/物料编码/单据状态
+调拨筛选
+
+
+===== PAGE 9 =====
+第7 页
+ERP 直接调拨单查询
+点击右上角
+按钮即可新增调拨单,填写相关信息后提交调拨可以保
+存。
+注:外发调拨选择HEV/115 物料和调出仓库后,进入新页面勾选已发货检
+合格的托盘码(批次码记录),调拨数量按绑定数量累加;提交成功后托盘改为
+已发货。
+ERP 直接调拨单查询-新增
+3.5. ERP 生产入库单查询
+路径:ERP 对接→ERP 生产入库单查询。
+
+
+===== PAGE 10 =====
+第8 页
+本模块主要用于展示ERP 生产入库单信息,支持对订单进行新增、查询、
+绑定MES 和查看详情操作。
+关键操作:新增入库单(选生产订单)→保存下推→查看MES 批次绑定明
+细。
+ERP 生产入库单查询字段表
+查询字段
+说明
+入库单号/生产订单号/物料编码/单据状态
+入库筛选
+ERP 生产入库单查询
+ERP 生产入库单查询-详情
+
+
+===== PAGE 11 =====
+第9 页
+3.6. ERP 下推日志
+路径:ERP 对接→ERP 下推日志。
+本模块主要用于展示ERP 下推日志信息,系统自动记录每一次ERP 接口调
+用结果,支持对日志信息进行查询、导出及详情查看操作。
+业务类型:采购入库、生产入库、生产领料、直接调拨。
+ERP 下推日志字段表
+查询字段
+说明
+操作时间/业务类型/结果
+日志筛选
+源单号/ERP 单号/操作人
+关联信息
+ERP 下推日志
+
+
+===== PAGE 12 =====
+第10 页
+ERP 下推日志-详情
+3.7. ERP 排产看板
+路径:ERP 对接→ERP 排产看板。
+本模块主要用于以看板展示ERP 排产计划,支持对排产列表进行查询和新
+增,也可以切换到列表界面进行增删改查操作。
+关键操作:切换月份→点击计划条查看工位生产详情→可切换列表模式维
+护数据。
+ERP 排产看板
+点击
+列表按钮可切换到列表界面。
+
+
+===== PAGE 13 =====
+第11 页
+ERP 排产看板-列表
+4. 常见问题
+Q1:下推ERP 失败怎么办?
+查看ERP 下推日志详情中的失败原因;核对ERP 单据状态与物料编码。
+Q2:生产订单列表为空?
+确认ERP 中存在HEV/115 类别订单,且MES 与ERP 连接正常。
+Q3:领料后MES 库存未更新?
+领料成功后会在来料库存记录中产生批次,可在物料管理模块核对。

+ 251 - 0
_apk_work/manuals_text/7、生产线管理操作手册.txt

@@ -0,0 +1,251 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——生产线管理操作手册
+2026 年8 月28 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 文档说明.................................................................................................................. 1
+2. 生产线管理模块概述.............................................................................................. 1
+3. 功能操作.................................................................................................................. 3
+3.1. 生产线管理.................................................................................................... 3
+3.2. 生产工位管理................................................................................................ 3
+3.2.1. 点检项.................................................................................................. 4
+3.2.2. 物料...................................................................................................... 5
+3.2.3. 人员...................................................................................................... 5
+3.2.4. 子工位.................................................................................................. 6
+3.2.5. 操作指导书.......................................................................................... 6
+3.2.6. JAR 管理............................................................................................... 7
+3.3. 生产模版........................................................................................................ 8
+3.4. 工件类型........................................................................................................ 8
+3.5. 工具寿命管理................................................................................................ 9
+3.6. 班次表.......................................................................................................... 10
+3.7. 工位绑定物料批次...................................................................................... 10
+3.8. 大屏管理.......................................................................................................11
+3.9. 大屏播放器.................................................................................................. 12
+4. 常见问题................................................................................................................ 14
+
+
+===== PAGE 3 =====
+第1 页
+1. 文档说明
+本文档阐述大洋MES 生产线管理模块操作,包含产线工位、工艺模板、工
+具寿命、班次等基础档案配置,讲解工位点检、物料绑定、大屏配置等操作,为
+车间生产作业与可视化展示提供底层数据配置指引。
+2. 生产线管理模块概述
+生产线管理是MES 后台系统的基础配置模块,主要完成产线、工位、工艺
+模板、生产资源及可视化大屏的配置维护,为车间现场生产作业、工位管控、生
+产数据可视化展示提供底层基础数据支撑,主要功能如下:
+生产线管理:维护生产线基础档案,管理产线名称、编号、生产工件及运行
+状态信息。
+生产工位管理:统一管理产线下各工位基础信息,同时维护工位点检项、绑
+定物料、工位人员、子工位、操作指导书、JAR 版本等配套配置,支持数据启用
+与停用。
+生产模版:维护生产工艺模板及模板清单,对工序清单数据进行增删改查、
+启用停用管理。
+工件类型:管理工件基础档案,记录工件类型、编号、关联工艺模板、规格
+等基础信息。
+工具寿命管理:管控生产工具寿命台账,支持记录增删改查、启用禁用以及
+工具寿命更换业务操作。
+班次表:维护车间生产班次资料,实现班次信息增删改查、启用停用配置。
+工位绑定物料批次:查询工位绑定的物料批次信息,记录产线、工位、物料、
+批次码、剩余使用次数等追溯相关数据。
+大屏管理:实现可视化大屏基础配置,设置轮播时长、启用状态,支持大屏
+资料维护与预览播放。
+大屏播放器:依据预设配置参数,轮播展示中控、生产、设备、物料等各类
+业务可视化大屏页面。
+
+
+===== PAGE 4 =====
+第2 页
+生产线模块概述表
+功能
+说明
+生产线管理
+维护产线档案(名称、编号、生产工件)
+生产工位管理
+工位及点检项、物料、人员、子工位、指导
+书、JAR
+生产模板/工件类型
+工艺模板与条码规则配置
+工具寿命/班次表
+工装寿命与生产班次
+工位绑定物料批次
+托盘批次码与工件绑定
+大屏管理/播放器
+可视化大屏配置与轮播
+
+
+===== PAGE 5 =====
+第3 页
+3. 功能操作
+3.1. 生产线管理
+路径:生产线管理→生产线管理。
+本模块主要用于展示所有生产线信息,包括产线名称、产线编号、生产工件。
+生产线管理字段表
+查询字段
+说明
+名称/状态
+产线信息
+生产线管理
+3.2. 生产工位管理
+路径:生产线管理→生产工位管理。
+本模块主要用于管理生产线上所有的工位信息,支持为每个工位配置点检项、
+物料绑定、人员、子工位、操作指导书、JAR 管理以及增改查操作。
+生产工位管理字段表
+查询字段
+说明
+生产线/工位名称/备注/状态
+工位筛选
+
+
+===== PAGE 6 =====
+第4 页
+生产工位管理
+3.2.1.点检项
+路径:生产线管理→生产工位管理→点检项。
+点击
+按钮可管理该工位点检项,支持对点检项进行增
+删改查及停用/启用操作。
+生产工位管理-点检项
+
+
+===== PAGE 7 =====
+第5 页
+3.2.2.物料
+路径:生产线管理→生产工位管理→物料。
+点击
+按钮可管理该工位加工物料绑定,支持对加工物
+料进行增删改查及停用/启用操作。
+生产工位管理-物料
+3.2.3.人员
+路径:生产线管理→生产工位管理→人员。
+点击
+按钮可管理该工位人员信息,支持对人员信息进行
+增删改查操作。
+
+
+===== PAGE 8 =====
+第6 页
+生产工位管理-人员
+3.2.4.子工位
+路径:生产线管理→生产工位管理→子工位。
+点击
+按钮可管理该工位子工位,支持对子工位进行
+增删改查操作。
+生产工位管理-子工位
+3.2.5.操作指导书
+路径:生产线管理→生产工位管理→操作指导书。
+
+
+===== PAGE 9 =====
+第7 页
+点击
+按钮可管理该工位操作指导书,支持对操
+作指导书进行添加。
+生产工位管理-操作指导书
+3.2.6.JAR 管理
+路径:生产线管理→生产工位管理→点检项JAR 管理。
+点击
+按钮可管理该工位JAR 版本信息,支持对JAR 版本
+信息进行增删改查操作。
+生产工位管理-JAR 管理
+
+
+===== PAGE 10 =====
+第8 页
+3.3. 生产模版
+路径:生产线管理→生产模板。
+本模块主要用于展示所有生产模版列表,点击类型名称即可进入模版清单管
+理界面。
+生产模版
+点击列表中类型名称,进入模版清单管理页面,支持对清单信息进行增删改
+查、停用/启用操作。
+生产模版-清单管理界面
+3.4. 工件类型
+路径:生产线管理→工件类型。
+
+
+===== PAGE 11 =====
+第9 页
+本模块主要用于展示所有工件类型信息,包括类型名称、类型编号和模版名
+称、模版名称和规格等信息。
+工件类型字段表
+字段
+说明
+类型名称/编号
+类型标识
+模板/规格/条码长度
+条码解析规则
+入库数量
+默认入库数
+工件类型
+3.5. 工具寿命管理
+路径:生产线管理→工具寿命管理。
+本模块用于展示全部工具寿命更换记录,支持对记录执行增删改查、启用/
+禁用及工具寿命更换操作,可维护工装的最大寿命、剩余寿命以及单次消耗量。
+
+
+===== PAGE 12 =====
+第10 页
+工具寿命更换记录
+3.6. 班次表
+路径:生产线管理→班次表。
+本模块主要用于管理班次信息,支持对班次信息进行增删改查、停用/启用
+操作。
+班次表
+3.7. 工位绑定物料批次
+路径:生产线管理→工位绑定物料批次。
+本模块主要用于管理工位绑定物料批次信息,包括产线编号、工位号、物料
+
+
+===== PAGE 13 =====
+第11 页
+名称、批次码、工艺号、剩余次数和追溯类型,支持对班次信息进行查询操作。
+关键操作:新增批次码→绑定工件码→打印/批量打印二维码。
+工位绑定物料批次字段表
+查询字段
+说明
+批次码/调拨单号
+批次标识
+已绑定数量/是否用完/状态
+绑定状态
+工位绑定物料批次
+3.8. 大屏管理
+路径:生产线管理→大屏管理。
+本模块主要用于管理大屏,可以设置大屏轮播时长,支持对大屏进行增改查、
+是否启用和大屏播放操作。
+关键操作:新增/编辑→预览→打开「大屏播放器」。
+
+
+===== PAGE 14 =====
+第12 页
+大屏管理
+大屏管理-编辑
+3.9. 大屏播放器
+路径:大屏管理→大屏播放。
+本模块主要用于轮播展示各个大屏,包括中控大屏、生产数据模块大屏和设
+备运用中心等,顺序和时长等可在大屏管理模块进行配置。
+
+
+===== PAGE 15 =====
+第13 页
+大屏播放器-中控
+大屏播放器-物料管理
+
+
+===== PAGE 16 =====
+第14 页
+大屏播放器-生产管理模块
+大屏播放器-设备运用中心
+4. 常见问题
+Q1:工位扣料不生效?
+确认工位「物料」中已绑定物料且状态正常;加工结果为OK。
+Q2:客户端版本未更新?
+检查JAR 管理中版本状态;工位客户端需重启或自动拉取。
+Q3:大屏播放器空白?
+确认大屏管理中对应大屏已启用且URL 可访问。

+ 509 - 0
_apk_work/manuals_text/8、PDA操作说明操作手册.txt

@@ -0,0 +1,509 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——PDA 软件操作手册
+2026 年8 月25 日
+
+
+===== PAGE 2 =====
+目
+录
+1. PDA 端功能与业务概述..........................................................................................1
+2. 系统安装及登录...................................................................................................... 1
+3. 界面介绍.................................................................................................................. 2
+4. HEV 产线扫码..........................................................................................................2
+4.1. HEVOP010 镭雕.............................................................................................2
+4.2. HEVOP070 电池壳分总成1 点焊.................................................................3
+4.3. HEVOP080 电池壳分总成1 点焊补焊.........................................................4
+4.4. HEVOP090 电池壳分总成2 点焊.................................................................4
+4.5. HEVOP100 电池壳分总成2 点焊补焊.........................................................5
+4.6. HEVOP110 电池壳分总成3 点焊................................................................. 6
+4.7. HEVOP120 电池壳分总成4 点焊.................................................................6
+4.8. HEVOP130 电池壳分总成5 点焊补焊.........................................................7
+4.9. HEVOP140 电池壳分总成6 弧焊.................................................................8
+4.10. HEVOP150 电池壳分总成7 弧焊...............................................................8
+4.11. HEVOP160 电池壳分总成8 弧焊............................................................... 9
+4.12. HEVOP190A 白件气密检测...................................................................... 10
+4.13. HEVOP190B 白件气密检测...................................................................... 10
+4.14. HEVOP210 拉铆......................................................................................... 11
+4.15. HEVOP220 总成气密检测.........................................................................12
+5. ERP 对接................................................................................................................ 12
+5.1. 打包.............................................................................................................. 12
+5.2. 生产领料...................................................................................................... 13
+5.3. 生产入库...................................................................................................... 14
+5.4. 直接调拨单.................................................................................................. 14
+6. 生产管理................................................................................................................ 15
+6.1. 报工.............................................................................................................. 15
+6.2. 产品追溯...................................................................................................... 16
+6.3. 打印.............................................................................................................. 17
+
+
+===== PAGE 3 =====
+7. 设备管理................................................................................................................ 17
+7.1. 紧急性维修.................................................................................................. 17
+7.2. 预防性维护.................................................................................................. 17
+8. 质量管理................................................................................................................ 18
+8.1. MES 辅助...................................................................................................... 18
+8.2. MES 辅助修改记录...................................................................................... 19
+8.3. 报废.............................................................................................................. 20
+8.4. 不良处理...................................................................................................... 20
+8.5. 抽检.............................................................................................................. 21
+8.6. 发货检.......................................................................................................... 23
+8.7. 返修.............................................................................................................. 24
+8.8. 返修检查...................................................................................................... 24
+8.9. 工具寿命更换.............................................................................................. 25
+8.10. 来料检查.................................................................................................... 26
+8.11. 首件检查.....................................................................................................26
+9. 115 产线扫码...........................................................................................................27
+9.1. 115OP010 镭雕............................................................................................. 27
+9.2. 115OP040 左右边框总成............................................................................. 27
+9.3. 115OP060 前后边框总成............................................................................. 28
+9.4. 115OP070 总成框架拼焊-A......................................................................... 29
+9.5. 115OP080 总成框架弧焊-B......................................................................... 29
+9.6. 115OP110 白件气密检测..............................................................................30
+9.7. 115OP130 拉铆框架正面............................................................................. 31
+9.8. 115OP150 液冷板装配拉铆......................................................................... 31
+9.9. 115OP180 总成气密检测............................................................................. 32
+
+
+===== PAGE 4 =====
+第1 页
+1. PDA 端功能与业务概述
+本系统为安徽大洋MES 制造执行系统PDA 客户端,面向车间现场操作人员
+使用,主要实现产线工位工件扫码过站、质量检验、不良返修报废、生产报工、
+产品追溯、物料打包、出入库领料、设备维保、工具寿命管理等业务。操作人员
+通过PDA 扫码完成各工位业务操作,业务数据实时同步至MES 服务端,支撑车
+间生产过程数据采集、过程追溯与质量管控。
+2. 系统安装及登录
+“安徽大洋MES 系统”PDA 端软件可通过安装包一键安装,有安装需要的
+用户需联系开发人员。
+安装成功后,点击图标进入登录页,通过已分配的账号、密码进行登录。
+安装后图标
+登录页
+
+
+===== PAGE 5 =====
+第2 页
+3. 界面介绍
+登录账号后,进入软件主界面,主界面分为主功能界面和我的界面两部分。
+主功能界面:展示当前用户可使用的所有功能模块。
+我的界面:展示个人信息,可修改登录密码、进行字号设置、查看软件当前
+版本。
+主功能界面
+我的界面
+4. HEV 产线扫码
+4.1. HEVOP010 镭雕
+该模块用于HEV 产线HEVOP010A 镭雕工序的工位过站操作。
+进入PDA 主功能界面,点击HEVOP010 镭雕模块,进入该工序扫码界面;
+点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工件在该工
+位过站完成。
+
+
+===== PAGE 6 =====
+第3 页
+HEVOP010A 镭雕扫码界面
+4.2. HEVOP070 电池壳分总成1 点焊
+该模块用于HEV 产线HEVOP070A 电池壳分总成1 点焊工序的工位过站操
+作。
+进入PDA 主功能界面,点击HEVOP070 电池壳分总成1 点焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+HEVOP070A 电池壳分总成1 点焊扫码界面
+
+
+===== PAGE 7 =====
+第4 页
+4.3. HEVOP080 电池壳分总成1 点焊补焊
+该模块用于HEV 产线HEVOP080A 电池壳分总成1 点焊补焊工序的工位过
+站操作。
+进入PDA 主功能界面,点击HEVOP080 电池壳分总成1 点焊补焊模块,进
+入该工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成
+功即代表工件在该工位过站完成。
+HEVOP080A 电池壳分总成1 点焊补焊扫码界面
+4.4. HEVOP090 电池壳分总成2 点焊
+该模块用于HEV 产线HEVOP090A 电池壳分总成2 点焊工序的工位过站操
+作。
+进入PDA 主功能界面,点击HEVOP090 电池壳分总成2 点焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+
+
+===== PAGE 8 =====
+第5 页
+HEVOP090A 电池壳分总成2 点焊扫码界面
+4.5. HEVOP100 电池壳分总成2 点焊补焊
+该模块用于HEV 产线HEVOP100A 电池壳分总成2 点焊补焊工序的工位过
+站操作。
+进入PDA 主功能界面,点击HEVOP100 电池壳分总成2 点焊补焊模块,进
+入该工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成
+功即代表工件在该工位过站完成。
+HEVOP100A 电池壳分总成2 点焊补焊扫码界面
+
+
+===== PAGE 9 =====
+第6 页
+4.6. HEVOP110 电池壳分总成3 点焊
+该模块用于HEV 产线HEVOP110A 电池壳分总成3 点焊工序的工位过站操
+作。
+进入PDA 主功能界面,点击HEVOP110 电池壳分总成3 点焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+HEVOP110A 电池壳分总成3 点焊扫码界面
+4.7. HEVOP120 电池壳分总成4 点焊
+该模块用于HEV 产线HEVOP120A 电池壳分总成4 点焊工序的工位过站操
+作。进入PDA 主功能界面,点击HEVOP120 电池壳分总成4 点焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+
+
+===== PAGE 10 =====
+第7 页
+HEVOP120A 电池壳分总成4 点焊扫码界面
+4.8. HEVOP130 电池壳分总成5 点焊补焊
+该模块用于HEV 产线HEVOP130A 电池壳分总成5 点焊补焊工序的工位过
+站操作。
+进入PDA 主功能界面,点击HEVOP130 电池壳分总成5 点焊补焊模块,进
+入该工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成
+功即代表工件在该工位过站完成。
+HEVOP130A 电池壳分总成5 点焊补焊扫码界面
+
+
+===== PAGE 11 =====
+第8 页
+4.9. HEVOP140 电池壳分总成6 弧焊
+该模块用于HEV 产线HEVOP140A 电池壳分总成6 弧焊工序的工位过站操
+作。
+进入PDA 主功能界面,点击HEVOP140 电池壳分总成6 弧焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+HEVOP140A 电池壳分总成6 弧焊扫码界面
+4.10. HEVOP150 电池壳分总成7 弧焊
+该模块用于HEV 产线HEVOP150A 电池壳分总成7 弧焊工序的工位过站操
+作。
+进入PDA 主功能界面,点击HEVOP150 电池壳分总成7 弧焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+
+
+===== PAGE 12 =====
+第9 页
+HEVOP150A 电池壳分总成7 弧焊扫码界面
+4.11. HEVOP160 电池壳分总成8 弧焊
+该模块用于HEV 产线HEVOP160A 电池壳分总成8 弧焊工序的工位过站操
+作。
+进入PDA 主功能界面,点击HEVOP160 电池壳分总成8 弧焊模块,进入该
+工序扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即
+代表工件在该工位过站完成。
+HEVOP160A 电池壳分总成8 弧焊扫码界面
+
+
+===== PAGE 13 =====
+第10 页
+4.12. HEVOP190A 白件气密检测
+该模块用于HEV 产线HEVOP190A 白件气密检测工序的工位过站操作。
+进入PDA 主功能界面,点击HEVOP190A 白件气密检测模块,进入该工序
+扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表
+工件在该工位过站完成。
+HEVOP190A 白件气密检测扫码界面
+4.13. HEVOP190B 白件气密检测
+该模块用于HEV 产线HEVOP190B 白件气密检测工序的工位过站操作。
+进入PDA 主功能界面,点击HEVOP190B 白件气密检测模块,进入该工序
+扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表
+工件在该工位过站完成。
+
+
+===== PAGE 14 =====
+第11 页
+HEVOP190B 气密检测扫码界面
+4.14. HEVOP210 拉铆
+该模块用于HEV 产线HEVOP210A 拉铆工序的工位过站操作。
+进入PDA 主功能界面,点击HEVOP210 拉铆模块,进入该工序扫码界面;
+点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工件在该工
+位过站完成。
+HEVOP210A 拉铆扫码界面
+
+
+===== PAGE 15 =====
+第12 页
+4.15. HEVOP220 总成气密检测
+该模块用于HEV 产线HEVOP220A 总成气密检测工序的工位过站操作。
+进入PDA 主功能界面,点击HEVOP220 总成气密检测模块,进入该工序扫
+码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工
+件在该工位过站完成。
+HEVOP220A 总成气密检测扫码界面
+5. ERP 对接
+5.1. 打包
+该模块用于对完工产品进行打包操作。
+进入PDA 主功能界面,点击产品打包模块,进入批次码列表界面,点击底
+部新增批次码,点击底部扫码绑定,扫描产品工件码,出现该条记录即为打包成
+功,可扫描多个工件码。
+
+
+===== PAGE 16 =====
+第13 页
+批次码列表界面
+生产订单列表界面
+5.2. 生产领料
+该模块用于按生产订单领取物料。
+进入PDA 主功能界面,点击生产领料模块,进入领料单列表界面,点击新
+增创建领料单,点击对应领料单跳转至生产订单列表界面,点击扫码即可查看对
+应领料单详情及物料领取数量及领取状态。
+领料单列表
+生产订单列表
+订单分录列表界面
+
+
+===== PAGE 17 =====
+第14 页
+5.3. 生产入库
+该模块用于将生产订单进行入库操作。
+进入PDA 主功能界面,点击生产入库模块,进入生产订单列表界面,点击
+扫码,扫描包装码,即可对生产订单进行入库操作,可在列表页点击记录查看订
+单入库详情。
+生产订单列表界面
+订单分录列表界面
+5.4. 直接调拨单
+该模块用于库存之间的直接调拨。
+点击直接调拨单模块,进入直接调拨单界面,录入调拨信息,提交调拨单。
+
+
+===== PAGE 18 =====
+第15 页
+直接调拨单界面
+6. 生产管理
+6.1. 报工
+该模块用于工序完工报工。
+进入PDA 主功能界面,点击报工模块,进入报工查询界面,可筛选产线编
+号、工位号、姓名及时间条件后执行查询,选择对应的生产订单与工序,完成报
+工。
+
+
+===== PAGE 19 =====
+第16 页
+报工查询界面
+6.2. 产品追溯
+该模块主要用于产品追溯查询。
+点击产品追溯模块,点击产品追溯扫码按钮或使用PDA 侧边键,扫描产品
+工件码,即可查询出该产品状态及在各工位的生产记录。
+产品追溯界面
+追溯详情界面
+
+
+===== PAGE 20 =====
+第17 页
+6.3. 打印
+进入PDA 主功能界面,点击打印模块,进入打印功能界面。打印功能用于
+在车间现场通过PDA 连接便携式打印机,打印产品标签、物料标签或工序流转
+卡,便于后续扫码追溯与交接。
+7. 设备管理
+7.1. 紧急性维修
+该模块用于紧急性维修工作提交操作。
+点击紧急性维修模块,进入紧急性维修记录界面,点击下方设备扫码按钮,
+扫描设备二维码,进入设备台账界面,提交维修内容。
+紧急性维修记录界面
+设备台账界面
+7.2. 预防性维护
+该模块用于预防性维护计划提交操作。
+点击预防性维护模块,进入预防性维护记录界面,此界面将展示当前账号下
+
+
+===== PAGE 21 =====
+第18 页
+所有维护计划,点击状态为处理中的记录,即可进行维护计划的任务提交。
+预防性维护记录界面
+预防性维护提交界面
+8. 质量管理
+8.1. MES 辅助
+该模块主要用于查询工件在各工位的结果。
+点击MES 辅助模块,进入MES 辅助界面,输入或扫描工件码,点击查询
+按钮即可进入该工件的工位结果界面,可根据实际情况,点击OK/NG/重置按钮,
+将工位结果修改为OK/NG 状态。
+
+
+===== PAGE 22 =====
+第19 页
+MES 辅助界面
+工位结果界面
+8.2. MES 辅助修改记录
+该模块用于查看MES 辅助修改记录。
+进入MES 辅助修改记录界面,页面展示工位名称、产线、原结果、现结果、
+来源、修改时间、修改人等信息,可查阅工位检测结果的变更历史,完整留存结
+果修改前后的数据,便于追溯结果修改情况。
+MES 辅助修改记录界面
+
+
+===== PAGE 23 =====
+第20 页
+8.3. 报废
+当NG 工件返修失败后可通过该模块进行报废工件操作。
+点击报废记录模块,进入报废记录列表界面,点击下方报废按钮,进入报废
+提交界面,输入或扫描工件码,填写报废原因,上传汇报图片,点击提交按钮即
+可完成报废工件操作。可在列表界面查看对应记录详情。
+报废记录列表界面
+报废提交界面
+报废详情界面
+8.4. 不良处理
+该模块用于不良处理操作。
+点击不良处理模块,进入不良处理列表界面,点击底部扫码按钮,扫描工件
+码进行不良处理,可在不良处理页面查看不良处理详情。
+
+
+===== PAGE 24 =====
+第21 页
+不良处理列表界面
+不良处理详情界面
+8.5. 抽检
+该模块用于工件及工位抽检操作。
+第一种对工件抽检:点击抽检模块,进入抽检列表界面,点击界面下方抽检
+按钮,扫描工件码,进入抽检提交界面。在抽检提交界面,可点击右上角选择工
+位,选择抽检结果和抽检类型后,可选择添加汇报内容及汇报图片后进行提交。
+提交成功后即可在抽检列表中查看详情信息。
+注:当前账号用户可抽检的工位需要在系统后台系统管理-生产线管理-生产
+工位管理-编辑(工位人员关系表)模块中设置。
+
+
+===== PAGE 25 =====
+第22 页
+抽检列表界面
+抽检提交界面
+抽检提交(选择工位界面)
+抽检详情界面
+第二种,对工位进行抽检:点击抽检列表右上角的抽检按钮,进入抽检命令
+记录页面,在此界面,点击底部抽检按钮,选择工位,(注意,选择工位时仅可
+选择一个工位),选择完毕后点击底部确定按钮即代表对该工位执行抽检操作,
+抽检完毕后可在抽检命令记录列表页面中查看对应抽检结果。
+
+
+===== PAGE 26 =====
+第23 页
+抽检列表界面
+抽检命令记录
+抽检(选择工位)界面
+8.6. 发货检
+该模块用于产品出库发货检验。
+进入PDA 主功能界面,点击发货检模块,进入发货检扫码界面;点击扫码
+按钮或使用PDA 侧边键扫描产品工件码,扫码成功后记录产品发货检验信息,
+完成本工序发货检验。
+发货检扫码界面
+
+
+===== PAGE 27 =====
+第24 页
+8.7. 返修
+该模块用于产品返修。
+点击返修模块,进入开始返修界面,点击开始返修扫码按钮,扫描工件码,
+进入返修提交界面,可查看该工件信息,可填写汇报内容汇报图片后提交返修。
+开始返修扫码界面
+8.8. 返修检查
+该模块用于返修完成后的检查确认。
+点击返修检查模块,进入返修检查记录界面,展示所有返修检查记录列表,
+在此界面可查看各工件返修检查时间、检查结果,点击可查看具体详情信息。
+
+
+===== PAGE 28 =====
+第25 页
+返修检查记录界面
+返修检查详情界面
+8.9. 工具寿命更换
+该模块用于工具寿命更换操作。
+点击工具寿命更换模块,进入工具寿命更换列表界面,在此界面可查看所有
+的工具信息及对应寿命信息,点击任意一工具,即可进入工具寿命更换提交界面,
+选择工具选择唯一标识,可选添加备注,点击提交即代表工具寿命更换成功。可
+在列表中查看更换结果。
+工具寿命更换列表界面
+工具寿命更换提交界面
+
+
+===== PAGE 29 =====
+第26 页
+8.10. 来料检查
+该模块用于采购来料检验。
+点击来料检模块,进入采购入库历史列表,选择来料批次可查看来料详情,
+点击新增可录入采购入库信息。
+采购入库历史列表
+8.11. 首件检查
+该模块用于首件检查操作。
+点击首件检查模块,进入首件检查列表界面,可查看未检查和已检查列表,
+选择检查任务后可查看首件检查信息详情。
+首件检查列表界面
+首件检查信息界面
+
+
+===== PAGE 30 =====
+第27 页
+9. 115 产线扫码
+9.1. 115OP010 镭雕
+该模块用于115 产线115OP010A 镭雕工序的工位过站操作。
+进入PDA 主功能界面,点击115OP010 镭雕模块,进入该工序扫码界面;
+点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工件在该工
+位过站完成。
+115OP010A 镭雕扫码界面
+9.2. 115OP040 左右边框总成
+该模块用于115 产线115OP040A 左右边框总成工序的工位过站操作。
+进入PDA 主功能界面,点击115OP040 左右边框总成模块,进入该工序扫
+码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工
+件在该工位过站完成。
+
+
+===== PAGE 31 =====
+第28 页
+115OP040A 左边框总成扫码界面
+9.3. 115OP060 前后边框总成
+该模块用于115 产线115OP060A 前后边框总成工序的工位过站操作。
+进入PDA 主功能界面,点击115OP060 前后边框总成模块,进入该工序扫
+码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工
+件在该工位过站完成。
+115OP060A 前后边框总成扫码界面
+
+
+===== PAGE 32 =====
+第29 页
+9.4. 115OP070 总成框架拼焊-A
+该模块用于115 产线115OP070A 总成框架拼焊-A 工序的工位过站操作。
+进入PDA 主功能界面,点击115OP070 总成框架拼焊-A 模块,进入该工序
+扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表
+工件在该工位过站完成。
+115OP070A 总成框架拼焊-A 扫码界面
+9.5. 115OP080 总成框架弧焊-B
+该模块用于115 产线115OP080A 总成框架弧焊-B 工序的工位过站操作。
+进入PDA 主功能界面,点击115OP080 总成框架弧焊-B 模块,进入该工序
+扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表
+工件在该工位过站完成。
+
+
+===== PAGE 33 =====
+第30 页
+115OP080A 总成框架弧焊-B 扫码界面
+9.6. 115OP110 白件气密检测
+该模块用于115 产线115OP110A 白件气密检测工序的工位过站操作。
+进入PDA 主功能界面,点击115OP110 白件气密检测模块,进入该工序扫码界
+面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工件在
+该工位过站完成。
+115OP110A 白件气密检测扫码界面
+
+
+===== PAGE 34 =====
+第31 页
+9.7. 115OP130 拉铆框架正面
+该模块用于115 产线115OP130A 拉铆框架正面工序的工位过站操作。
+进入PDA 主功能界面,点击115OP130 拉铆框架正面模块,进入该工序扫
+码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工
+件在该工位过站完成。
+115OP130A 拉铆框架正面
+9.8. 115OP150 液冷板装配拉铆
+该模块用于115 产线115OP150A 液冷板装配拉铆工序的工位过站操作。
+进入PDA 主功能界面,点击115OP150 液冷板装配拉铆模块,进入该工序
+扫码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表
+工件在该工位过站完成。
+
+
+===== PAGE 35 =====
+第32 页
+115OP150A 液冷板装配拉铆扫码界面
+9.9. 115OP180 总成气密检测
+该模块用于115 产线OP180A 总成气密检测工序的工位过站操作。
+进入PDA 主功能界面,点击115OP180 总成气密检测模块,进入该工序扫
+码界面;点击扫码按钮或使用PDA 侧边键扫描产品工件码,扫码成功即代表工
+件在该工位过站完成。
+115OP180A 总成气密检测扫码界面

+ 120 - 0
_apk_work/manuals_text/9、MES系统客户端员工扫码操作手册.txt

@@ -0,0 +1,120 @@
+
+
+===== PAGE 1 =====
+大洋MES 生产管理系统
+——客户端员工扫码操作手册
+2026 年8 月25 日
+
+
+===== PAGE 2 =====
+目
+录
+1. 功能概述.................................................................................................................. 1
+2. 客户端登录(以HEVXTOP050A 工位作演示)................................................1
+2.1. 界面介绍......................................................................................................1
+3. 工件码扫码操作(核心流程).............................................................................. 2
+3.1. 扫码流程......................................................................................................2
+3.2. OK 结果提交................................................................................................ 4
+3.3. NG 结果提交................................................................................................ 5
+4. 返修处理.................................................................................................................. 7
+4.1. 工位重复加工模式返修..............................................................................7
+4.2. PDA 不良处理返修......................................................................................8
+
+
+===== PAGE 3 =====
+第1 页
+1. 功能概述
+本系统为MES(制造执行系统)客户端,用于各工位的工件质量判定与物
+料绑定。系统通过扫码方式获取工位当前工件码,实现质检,提交生产记录等功
+能。
+2. 客户端登录(以HEVXTOP050A 工位作演示)
+2.1. 界面介绍
+该界面用于客户端账号登录操作。在登录界面输入用户名和密码,点击用户
+密码登录按钮后进入客户端主页。
+用户登录界面
+该界面为客户端操作主页,登录成功后在此页面完成工件扫码、OK/NG 结
+果提交、开班组点检、工作记录查看操作。
+
+
+===== PAGE 4 =====
+第2 页
+客户端主页
+3. 工件码扫码操作(核心流程)
+3.1. 扫码流程
+该模块用于PDA 端工位工件扫码过站操作。
+进入主功能界面点击PDA 对应工位的功能模块进入扫码页面,点击扫码按
+钮或使用PDA 侧边键扫描工件码,扫码完成后PDA 显示扫码成功,工位当前工
+件新增数据,客户端页面出现工件码,OK 和NG 按钮状态置为true。
+
+
+===== PAGE 5 =====
+第3 页
+PDA 主功能界面
+扫码界面
+PDA 扫码页面
+PDA 扫码成功页面
+
+
+===== PAGE 6 =====
+第4 页
+服务端工位当前工件列表截图
+客户端截图
+3.2. OK 结果提交
+该模块用于工件加工合格结果提交。
+工件扫码完成后,在客户端页面点击OK 按钮,系统提交OK 结果,生产记
+录结果更新为OK,OK 和NG 按钮重新置为false。
+
+
+===== PAGE 7 =====
+第5 页
+系统生产记录截图
+提交成功后客户端截图
+3.3. NG 结果提交
+该模块用于工件加工不合格结果提交。
+工件扫码完成后,在客户端页面点击NG 按钮,系统提交NG 结果,生产记
+
+
+===== PAGE 8 =====
+第6 页
+录结果显示为NG,该工件标记为不合格不再继续流转加工,后续工序客户端无
+法提交该工件的扫码结果。
+系统生产记录截图
+PDA 扫码结果
+
+
+===== PAGE 9 =====
+第7 页
+后续客户端截图
+4. 返修处理
+4.1. 工位重复加工模式返修
+该模块用于管理员后台开启工位重复加工模式,实现NG 不合格工件再次加
+工。管理员登录MES 后台,打开编辑生产工位页面,将重复加工选项设置为是
+并保存,该工位就可以对NG 工件重新扫码加工。
+工位编辑截图
+
+
+===== PAGE 10 =====
+第8 页
+4.2. PDA 不良处理返修
+该模块用于PDA 端对NG 工件提交返修申请。
+进入PDA 主功能界面,点击不良处理模块,进入不良处理列表界面,点击
+底部扫码按钮扫描NG 工件码,进入不良处理提交页面,依次选择返工白名单、
+工位列表,勾选返工类型,填写不良信息,可按需添加汇报图片,点击提交完成
+返修申请,提交后在不良处理列表查看返修记录,后台返修记录管理页面同步生
+成对应数据。
+点击不良处理
+不良处理列表界面
+
+
+===== PAGE 11 =====
+第9 页
+不良处理提交界面
+返工白名单列表界面
+工位列表选择工位界面
+不良处理提交界面
+
+
+===== PAGE 12 =====
+第10 页
+不良处理列表界面
+系统返修记录截图

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2127 - 0
_apk_work/manuals_text/大洋交付-操作手册合订版.txt


+ 144 - 0
_apk_work/md_to_docx.py

@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+"""Convert 9.19 markdown manuals to Word."""
+import os, re
+from docx import Document
+from docx.shared import Pt, Cm, RGBColor
+from docx.oxml.ns import qn
+from docx.enum.text import WD_ALIGN_PARAGRAPH
+from docx.enum.table import WD_TABLE_ALIGNMENT
+
+SRC = r"D:\产线\大洋\大洋操作手册汇总9.19"
+FONT = "微软雅黑"
+
+def set_run_font(run, size=11, bold=False, color=None):
+    run.bold = bold
+    run.font.size = Pt(size)
+    run.font.name = FONT
+    r = run._element
+    rPr = r.get_or_add_rPr()
+    rFonts = rPr.find(qn("w:rFonts"))
+    if rFonts is None:
+        from lxml import etree
+        rFonts = rPr.makeelement(qn("w:rFonts"), {})
+        rPr.append(rFonts)
+    rFonts.set(qn("w:eastAsia"), FONT)
+    rFonts.set(qn("w:ascii"), FONT)
+    rFonts.set(qn("w:hAnsi"), FONT)
+    if color:
+        run.font.color.rgb = RGBColor(*color)
+
+def add_runs(p, text, size=11, bold=False):
+    # split **bold**
+    parts = re.split(r"(\*\*[^*]+\*\*)", text)
+    for part in parts:
+        if part.startswith("**") and part.endswith("**"):
+            run = p.add_run(part[2:-2])
+            set_run_font(run, size=size, bold=True)
+        else:
+            run = p.add_run(part)
+            set_run_font(run, size=size, bold=bold)
+
+def parse_table(lines, i):
+    rows = []
+    while i < len(lines) and lines[i].startswith("|"):
+        raw = [c.strip() for c in lines[i].strip().strip("|").split("|")]
+        if not re.match(r"^:?-+:?$", raw[0].replace(" ", "")):
+            rows.append(raw)
+        i += 1
+    return rows, i
+
+def convert(md_path, docx_path):
+    text = open(md_path, encoding="utf-8").read()
+    lines = text.splitlines()
+    doc = Document()
+    section = doc.sections[0]
+    section.top_margin = Cm(2)
+    section.bottom_margin = Cm(2)
+    section.left_margin = Cm(2.2)
+    section.right_margin = Cm(2.2)
+    style = doc.styles["Normal"]
+    style.font.name = FONT
+    style.font.size = Pt(11)
+    style.element.rPr.rFonts.set(qn("w:eastAsia"), FONT)
+
+    i = 0
+    while i < len(lines):
+        line = lines[i].rstrip()
+        if not line:
+            i += 1
+            continue
+        if line.startswith("# "):
+            p = doc.add_heading("", level=0)
+            p.clear()
+            run = p.add_run(line[2:].strip())
+            set_run_font(run, size=18, bold=True, color=(0x1F, 0x4E, 0x79))
+            i += 1
+            continue
+        if line.startswith("## "):
+            p = doc.add_heading("", level=1)
+            p.clear()
+            run = p.add_run(line[3:].strip())
+            set_run_font(run, size=16, bold=True, color=(0x2E, 0x75, 0xB6))
+            i += 1
+            continue
+        if line.startswith("### "):
+            p = doc.add_heading("", level=2)
+            p.clear()
+            run = p.add_run(line[4:].strip())
+            set_run_font(run, size=14, bold=True, color=(0x2E, 0x75, 0xB6))
+            i += 1
+            continue
+        if line.startswith("#### "):
+            p = doc.add_heading("", level=3)
+            p.clear()
+            run = p.add_run(line[5:].strip())
+            set_run_font(run, size=12, bold=True)
+            i += 1
+            continue
+        if line.startswith("---"):
+            i += 1
+            continue
+        if line.startswith("|"):
+            rows, i = parse_table(lines, i)
+            if rows:
+                cols = max(len(r) for r in rows)
+                table = doc.add_table(rows=len(rows), cols=cols)
+                table.style = "Table Grid"
+                table.alignment = WD_TABLE_ALIGNMENT.CENTER
+                for r_idx, row in enumerate(rows):
+                    for c_idx in range(cols):
+                        cell = table.cell(r_idx, c_idx)
+                        cell.text = ""
+                        p = cell.paragraphs[0]
+                        val = row[c_idx] if c_idx < len(row) else ""
+                        add_runs(p, val, size=10, bold=(r_idx == 0))
+            continue
+        if line.startswith("- "):
+            p = doc.add_paragraph(style="List Bullet")
+            p.clear()
+            add_runs(p, line[2:].strip())
+            i += 1
+            continue
+        if re.match(r"^\d+\.\s", line):
+            p = doc.add_paragraph(style="List Number")
+            p.clear()
+            add_runs(p, re.sub(r"^\d+\.\s", "", line))
+            i += 1
+            continue
+        p = doc.add_paragraph()
+        add_runs(p, line)
+        i += 1
+
+    doc.save(docx_path)
+    print("saved", os.path.basename(docx_path))
+
+def main():
+    files = [f for f in os.listdir(SRC) if f.endswith(".md")]
+    files.sort()
+    for f in files:
+        md = os.path.join(SRC, f)
+        docx = os.path.join(SRC, os.path.splitext(f)[0] + ".docx")
+        convert(md, docx)
+
+if __name__ == "__main__":
+    main()

+ 10 - 0
_apk_work/pdf_img_count.txt

@@ -0,0 +1,10 @@
+1、系统管理操作手册.pdf pages=28 images=67 size=2570017
+2、设备管理操作手册.pdf pages=12 images=26 size=961706
+3、物料管理操作手册.pdf pages=11 images=15 size=504335
+4、质量管理操作手册.pdf pages=12 images=22 size=754391
+5、生产管理操作手册.pdf pages=25 images=67 size=2390328
+6、ERP对接操作手册.pdf pages=13 images=29 size=1159571
+7、生产线管理操作手册.pdf pages=16 images=42 size=1439613
+8、PDA操作说明操作手册.pdf pages=35 images=103 size=1875596
+9、MES系统客户端员工扫码操作手册.pdf pages=12 images=34 size=1381469
+大洋交付-操作手册合订版.pdf pages=138 images=392 size=12087323

+ 25 - 0
_apk_work/query_menus.sql

@@ -0,0 +1,25 @@
+SELECT '==== PDA CATEGORIES ====' AS t;
+SELECT id, title, sort_order, status FROM mes_icons_category ORDER BY sort_order, title;
+
+SELECT '==== PDA ICONS ====' AS t;
+SELECT IFNULL(c.title,'未分类') AS category, i.title AS icon, i.mode, i.auth, i.status
+FROM mes_icons i
+LEFT JOIN mes_icons_category c ON c.id = i.category_id
+WHERE i.status = '0'
+ORDER BY IFNULL(c.sort_order,9999), IFNULL(c.title,''), i.title;
+
+SELECT '==== GROUPED CONFIG ====' AS t;
+SELECT config_key, config_value FROM js_sys_config WHERE config_key LIKE 'mes.icons%';
+
+SELECT '==== SYS MENU ====' AS t;
+SELECT tree_level, menu_name, menu_href, is_show, permission, parent_code, menu_code, tree_sorts
+FROM js_sys_menu
+WHERE status='0' AND menu_type IN ('1','0') AND is_show='1'
+ORDER BY tree_sorts, tree_sort;
+
+SELECT '==== LINE PROCESS ====' AS t;
+SELECT l.sn AS line_sn, l.title AS line_title, p.oprno, p.title AS process_title, p.status
+FROM mes_line_process p
+LEFT JOIN mes_line l ON l.id = p.line_id OR l.sn = p.line_sn
+WHERE p.status='0'
+ORDER BY l.sn, p.oprno;

+ 247 - 0
_apk_work/regen_mes_icons_current_sql.py

@@ -0,0 +1,247 @@
+# -*- coding: utf-8 -*-
+"""Regenerate restore SQL: only current (status=0) image per mes_icons id."""
+from __future__ import print_function
+
+from collections import Counter, defaultdict
+import os
+import sys
+
+sys.path.insert(0, r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work")
+from extract_mes_icons_files import (  # noqa: E402
+    DUMP,
+    OUT_DIR,
+    find_offsets,
+    iter_value_rows,
+    parse_create_columns,
+    read_until_stmt_end,
+    row_to_dict,
+    sql_quote,
+    unquote,
+)
+
+
+def pick_latest(lst):
+    return sorted(
+        lst,
+        key=lambda x: (
+            x.get("update_date") or "",
+            x.get("create_date") or "",
+            x.get("id") or "",
+        ),
+        reverse=True,
+    )[0]
+
+
+def main():
+    hits = find_offsets(DUMP, ["mes_icons", "js_sys_file_upload", "js_sys_file_entity"])
+    create_cols = {}
+    inserts = {}
+    for off, name in hits:
+        if name.startswith("CREATE:"):
+            t = name.split(":", 1)[1]
+            stmt = read_until_stmt_end(DUMP, off, max_bytes=200 * 1024)
+            create_cols[t] = parse_create_columns(stmt)
+        else:
+            inserts[name] = off
+
+    icons_cols = create_cols["mes_icons"]
+    upload_cols = create_cols["js_sys_file_upload"]
+    entity_cols = create_cols["js_sys_file_entity"]
+
+    icons = [row_to_dict(f, icons_cols) for f in iter_value_rows(DUMP, inserts["mes_icons"])]
+    icon_by_id = {i["id"]: i for i in icons}
+
+    biz_type_idx = upload_cols.index("biz_type")
+    icon_uploads = []
+    for fields in iter_value_rows(DUMP, inserts["js_sys_file_upload"]):
+        if unquote(fields[biz_type_idx]) == "mesIcons_image":
+            icon_uploads.append(row_to_dict(fields, upload_cols))
+
+    print("upload status:", Counter(u.get("status") for u in icon_uploads))
+
+    by_biz = defaultdict(list)
+    for u in icon_uploads:
+        if (u.get("status") or "0") == "0":
+            by_biz[u.get("biz_key")].append(u)
+
+    current = {}
+    for k, lst in by_biz.items():
+        if k:
+            current[k] = pick_latest(lst)
+
+    print(
+        "modules with active image=%d, multi-active=%d"
+        % (len(current), sum(1 for v in by_biz.values() if len(v) > 1))
+    )
+
+    needed = set(u["file_id"] for u in current.values() if u.get("file_id"))
+    file_id_idx = entity_cols.index("file_id")
+    entities = {}
+    for fields in iter_value_rows(DUMP, inserts["js_sys_file_entity"]):
+        fid = unquote(fields[file_id_idx])
+        if fid in needed:
+            entities[fid] = row_to_dict(fields, entity_cols)
+            if len(entities) == len(needed):
+                break
+    print("entities=%d" % len(entities))
+
+    def disk_rel(e):
+        if not e:
+            return ""
+        path = (e.get("file_path") or "").replace("\\", "/")
+        md5 = e.get("file_md5") or ""
+        ext = e.get("file_extension") or ""
+        return ("%s%s.%s" % (path, md5, ext)) if ext else ("%s%s" % (path, md5))
+
+    map2 = os.path.join(OUT_DIR, "mes_icons_image_map_current_only.txt")
+    with open(map2, "w", encoding="utf-8") as wf:
+        wf.write(
+            "icon_id\ttitle\tmode\ticon_status\tupload_id\tfile_id\tfile_name\t"
+            "file_path\tfile_md5\text\tdisk_rel\tupdate_date\n"
+        )
+        for biz_key in sorted(current.keys()):
+            u = current[biz_key]
+            e = entities.get(u.get("file_id") or {}, {})
+            ic = icon_by_id.get(biz_key, {})
+            wf.write(
+                "\t".join(
+                    [
+                        biz_key,
+                        ic.get("title") or "",
+                        ic.get("mode") or "",
+                        ic.get("status") or "",
+                        u.get("id") or "",
+                        u.get("file_id") or "",
+                        u.get("file_name") or "",
+                        (e.get("file_path") or "").replace("\\", "/"),
+                        e.get("file_md5") or "",
+                        e.get("file_extension") or "",
+                        disk_rel(e),
+                        u.get("update_date") or "",
+                    ]
+                )
+                + "\n"
+            )
+    print("Wrote", map2)
+
+    sql_path = os.path.join(OUT_DIR, "restore_mes_icons_image_mapping.sql")
+    with open(sql_path, "w", encoding="utf-8") as wf:
+        wf.write("-- ============================================================\n")
+        wf.write("-- Restore PDA功能模块图片映射(仅当前有效图 status=0,每模块取最新一条)\n")
+        wf.write("-- 来源: mes_cloud_20260919.sql\n")
+        wf.write("-- 关联: biz_key=mes_icons.id, biz_type=mesIcons_image\n")
+        wf.write("-- 务必同步拷贝磁盘文件到新服务器 {baseDir}/userfiles/\n")
+        wf.write("-- ============================================================\n")
+        wf.write("SET NAMES utf8mb4;\nSTART TRANSACTION;\n\n")
+        wf.write("-- 1) 文件实体\n")
+        for fid in sorted(needed):
+            e = entities[fid]
+            size = e.get("file_size")
+            size_sql = size if size is not None else "NULL"
+            wf.write(
+                "INSERT INTO `js_sys_file_entity` "
+                "(`file_id`,`file_md5`,`file_path`,`file_content_type`,`file_extension`,"
+                "`file_size`,`file_meta`,`file_preview`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s) "
+                "ON DUPLICATE KEY UPDATE "
+                "`file_md5`=VALUES(`file_md5`),`file_path`=VALUES(`file_path`),"
+                "`file_content_type`=VALUES(`file_content_type`),"
+                "`file_extension`=VALUES(`file_extension`),`file_size`=VALUES(`file_size`),"
+                "`file_meta`=VALUES(`file_meta`),`file_preview`=VALUES(`file_preview`);\n"
+                % (
+                    sql_quote(e.get("file_id")),
+                    sql_quote(e.get("file_md5")),
+                    sql_quote(e.get("file_path")),
+                    sql_quote(e.get("file_content_type")),
+                    sql_quote(e.get("file_extension")),
+                    size_sql,
+                    sql_quote(e.get("file_meta")),
+                    sql_quote(e.get("file_preview")),
+                )
+            )
+
+        wf.write("\n-- 2) 按模块 id 替换绑定\n")
+        for biz_key in sorted(current.keys()):
+            u = current[biz_key]
+            ic = icon_by_id.get(biz_key, {})
+            e = entities.get(u.get("file_id") or {}, {})
+            wf.write(
+                "\n-- id=%s title=%s mode=%s disk=%s\n"
+                % (biz_key, ic.get("title") or "", ic.get("mode") or "", disk_rel(e))
+            )
+            wf.write(
+                "DELETE FROM `js_sys_file_upload` "
+                "WHERE `biz_type`='mesIcons_image' AND `biz_key`=%s;\n"
+                % sql_quote(biz_key)
+            )
+            sortv = u.get("file_sort")
+            sort_sql = sortv if sortv is not None else "NULL"
+            wf.write(
+                "INSERT INTO `js_sys_file_upload` "
+                "(`id`,`file_id`,`file_name`,`file_type`,`file_sort`,`biz_key`,`biz_type`,"
+                "`status`,`create_by`,`create_date`,`update_by`,`update_date`,`remarks`) "
+                "VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);\n"
+                % (
+                    sql_quote(u.get("id")),
+                    sql_quote(u.get("file_id")),
+                    sql_quote(u.get("file_name")),
+                    sql_quote(u.get("file_type")),
+                    sort_sql,
+                    sql_quote(u.get("biz_key")),
+                    sql_quote(u.get("biz_type")),
+                    sql_quote(u.get("status") or "0"),
+                    sql_quote(u.get("create_by") or "system"),
+                    sql_quote(u.get("create_date")),
+                    sql_quote(u.get("update_by") or "system"),
+                    sql_quote(u.get("update_date")),
+                    sql_quote(u.get("remarks")),
+                )
+            )
+
+        missing = [
+            i
+            for i in icons
+            if i.get("id") not in current and (i.get("status") or "0") == "0"
+        ]
+        if missing:
+            wf.write("\n-- 老库正常模块但无有效图片:\n")
+            for i in missing:
+                wf.write(
+                    "--   id=%s title=%s mode=%s\n"
+                    % (i.get("id"), i.get("title"), i.get("mode"))
+                )
+        wf.write("\nCOMMIT;\n")
+        wf.write(
+            "\n-- 校验:\n"
+            "-- SELECT u.biz_key, i.title, i.mode, u.file_name, e.file_path, e.file_md5, e.file_extension\n"
+            "-- FROM js_sys_file_upload u\n"
+            "-- LEFT JOIN js_sys_file_entity e ON e.file_id=u.file_id\n"
+            "-- LEFT JOIN mes_icons i ON i.id=u.biz_key\n"
+            "-- WHERE u.biz_type='mesIcons_image' AND u.status='0'\n"
+            "-- ORDER BY i.title;\n"
+        )
+    print("Wrote", sql_path)
+
+    files_list = os.path.join(OUT_DIR, "mes_icons_image_files_to_copy.txt")
+    seen = set()
+    with open(files_list, "w", encoding="utf-8") as wf:
+        wf.write("# 拷到新服务器 {file.baseDir}/userfiles/ 下,保持相对路径\n")
+        for u in current.values():
+            rel = disk_rel(entities.get(u.get("file_id") or {}))
+            if not rel or rel in seen:
+                continue
+            seen.add(rel)
+            wf.write(rel + "\n")
+    print("files=%d Wrote %s" % (len(seen), files_list))
+
+    print("--- preview (first 15) ---")
+    with open(map2, encoding="utf-8") as rf:
+        for i, line in enumerate(rf):
+            if i <= 15:
+                print(line.rstrip())
+            else:
+                break
+    print("DONE")
+
+
+if __name__ == "__main__":
+    main()

BIN
_apk_work/tools/apktool.jar


+ 12 - 0
db/mysql/add_mes_gp12_pack_lines_config.sql

@@ -0,0 +1,12 @@
+-- 打包绑定批次码时,哪些产线须先完成 GP12 检查(系统设置 → 参数设置)
+-- mes.gp12.pack.lines:逗号分隔产线编号或关键字,如 HEV,HEVXT,115XT
+-- 默认仅 HEVXT 产线需要 GP12,115XT 产线可直接打包
+
+INSERT INTO `js_sys_config` (
+  `id`, `config_name`, `config_key`, `config_value`, `is_sys`,
+  `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+) VALUES (
+  '2069501212292587522', '打包需GP12检查的产线', 'mes.gp12.pack.lines', 'HEVXT', '0',
+  'system', NOW(), 'system', NOW(),
+  '逗号分隔产线编号,如 HEVXT、115XT;打包绑定批次码时,匹配产线的工件须先完成 GP12 且结果为 OK'
+);

+ 3 - 0
db/mysql/add_mes_process_param_limit_gun_type.sql

@@ -0,0 +1,3 @@
+-- 工艺参数上下限增加拉铆枪类型(A/B)
+ALTER TABLE `mes_process_param_limit`
+  ADD COLUMN `gun_type` varchar(20) NULL DEFAULT NULL COMMENT '类型 A枪/B枪' AFTER `oprno`;

+ 4 - 0
db/mysql/add_mes_process_param_limit_line_oprno.sql

@@ -0,0 +1,4 @@
+-- 工艺参数上下限增加产线编号、工位号
+ALTER TABLE `mes_process_param_limit`
+  ADD COLUMN `line_sn` varchar(20) NULL DEFAULT NULL COMMENT '产线编号' AFTER `process_name`,
+  ADD COLUMN `oprno` varchar(20) NULL DEFAULT NULL COMMENT '工位号' AFTER `line_sn`;

+ 10 - 0
db/mysql/add_mes_product_check_one_permission.sql

@@ -0,0 +1,10 @@
+-- 首件检查记录菜单补充 mes_product_check_one 权限标识
+-- 列表/表单按钮校验 mes:mesProductCheckOne:view|edit,原菜单仅有 mesProductCheckFirst 权限导致操作列为空
+-- 菜单表单 permission 输入框 maxlength=100,写全 4 个会超长,改用通配 *
+
+UPDATE `js_sys_menu`
+SET `permission` = 'mes:mesProductCheckFirst:*,mes:mesProductCheckOne:*',
+    `update_by` = 'system',
+    `update_date` = NOW()
+WHERE `menu_code` = '1796152788824604672'
+  AND (`permission` IS NULL OR `permission` NOT LIKE '%mes:mesProductCheckOne:%');

+ 5 - 0
db/mysql/add_mes_product_check_one_remark.sql

@@ -0,0 +1,5 @@
+-- 首件检记录增加备注字段
+-- 代码已映射 a.remark,未执行本脚本时列表会报 Unknown column 'a.remark'
+
+ALTER TABLE `mes_product_check_one`
+  ADD COLUMN `remark` varchar(255) NULL DEFAULT NULL COMMENT '备注' AFTER `result`;

+ 39 - 0
db/mysql/optimize_process_param_list_indexes.sql

@@ -0,0 +1,39 @@
+-- 工艺过程参数列表加速索引
+-- 建议在业务低峰执行。若提示 Duplicate key name,说明该索引已存在,跳过对应语句即可。
+
+ALTER TABLE `mes_product_arc_welding`
+  ADD INDEX `idx_mpaw_create_date` (`create_date`),
+  ADD INDEX `idx_mpaw_sn` (`sn`),
+  ADD INDEX `idx_mpaw_line_oprno` (`line_sn`, `oprno`);
+
+ALTER TABLE `mes_product_cmt`
+  ADD INDEX `idx_mpc_create_date` (`create_date`),
+  ADD INDEX `idx_mpc_sn` (`sn`),
+  ADD INDEX `idx_mpc_line_oprno` (`line_sn`, `oprno`);
+
+ALTER TABLE `mes_product_prod`
+  ADD INDEX `idx_mpp_date_time` (`date_time`),
+  ADD INDEX `idx_mpp_sn` (`sn`);
+
+ALTER TABLE `mes_product_fsw`
+  ADD INDEX `idx_mpf_create_date` (`create_date`),
+  ADD INDEX `idx_mpf_sn` (`sn`);
+
+ALTER TABLE `mes_product_qm`
+  ADD INDEX `idx_mpq_test_time` (`test_time`),
+  ADD INDEX `idx_mpq_oprno` (`oprno`);
+
+ALTER TABLE `mes_torsional_process`
+  ADD INDEX `idx_mtp_create_date` (`create_date`),
+  ADD INDEX `idx_mtp_sn` (`sn`);
+
+ALTER TABLE `mes_electric_torque`
+  ADD INDEX `idx_met_create_date` (`create_date`),
+  ADD INDEX `idx_met_sn` (`sn`);
+
+ALTER TABLE `mes_product_glue_duration`
+  ADD INDEX `idx_mpgd_create_date` (`create_date`),
+  ADD INDEX `idx_mpgd_sn` (`sn`);
+
+ALTER TABLE `mes_product_record`
+  ADD INDEX `idx_mpr_sn_oprno_line` (`sn`, `oprno`, `line_sn`);

+ 13 - 0
db/mysql/restore_sys_config_menu.sql

@@ -0,0 +1,13 @@
+-- 恢复「参数设置」菜单给已授权角色(菜单可见性与系统参数可见性分开)。
+-- 系统参数(is_sys=1)仍仅超级管理员 system 能在列表中看到,由代码过滤,不靠藏菜单。
+
+UPDATE `js_sys_menu`
+SET `weight` = 60
+WHERE `permission` = 'sys:config'
+   OR `menu_href` = '/sys/config/list';
+
+INSERT IGNORE INTO `js_sys_role_menu` (`role_code`, `menu_code`)
+SELECT r.role_code, m.menu_code
+FROM `js_sys_role` r
+JOIN `js_sys_menu` m ON m.permission = 'sys:config' OR m.menu_href = '/sys/config/list'
+WHERE r.role_code IN ('corpAdmin', 'dy0001', 'dy0002', 'dy00026', 'guanliyuan', 'ITGLY', 'yonghu');

+ 3 - 0
db/mysql/restrict_sys_config_to_super_admin.sql

@@ -0,0 +1,3 @@
+-- 参数设置可见性说明(不要用本脚本藏菜单)。
+-- 列表过滤在代码 ConfigSuperAdminAspect:非 system 只能看到 is_sys=0 的项。
+-- 用 system 编辑某条,把「系统参数」设为「是」= 仅超管可见;「否」= 有菜单权限的人可见。

+ 130 - 0
db/mysql/scale_spot_welding_current.py

@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+"""
+一次性把历史点焊电流放大 10 倍,与当前入库规则对齐。
+已放大过的记录(电流绝对值 >= 3)会跳过,可重复执行。
+"""
+import argparse
+import json
+import sys
+from decimal import Decimal
+
+import pymysql
+from pymysql.cursors import SSCursor
+
+SCALE_THRESHOLD = Decimal("3")
+CURRENT_KEYS = ("robot1Current", "robot2Current")
+
+
+def to_decimal(value):
+    if value is None or value == "":
+        return None
+    try:
+        return Decimal(str(value))
+    except Exception:
+        return None
+
+
+def scale_content(content):
+    if not content:
+        return None
+    try:
+        payload = json.loads(content)
+    except Exception:
+        return None
+    if not isinstance(payload, dict) or payload.get("weldingType") != "spot":
+        return None
+    samples = payload.get("samples") or []
+    if not isinstance(samples, list) or not samples:
+        return None
+
+    max_current = Decimal("0")
+    for sample in samples:
+        if not isinstance(sample, dict):
+            continue
+        for key in CURRENT_KEYS:
+            current = to_decimal(sample.get(key))
+            if current is not None and abs(current) > max_current:
+                max_current = abs(current)
+
+    if max_current <= 0 or max_current >= SCALE_THRESHOLD:
+        return None
+
+    for sample in samples:
+        if not isinstance(sample, dict):
+            continue
+        for key in CURRENT_KEYS:
+            current = to_decimal(sample.get(key))
+            if current is None:
+                continue
+            scaled = current * 10
+            if scaled == scaled.to_integral_value():
+                sample[key] = int(scaled)
+            else:
+                sample[key] = float(scaled)
+    return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
+
+
+def main():
+    parser = argparse.ArgumentParser(description="Scale historical spot welding current by 10")
+    parser.add_argument("--host", default="127.0.0.1")
+    parser.add_argument("--port", type=int, default=3306)
+    parser.add_argument("--user", default="root")
+    parser.add_argument("--password", required=True)
+    parser.add_argument("--database", default="mes_cloud_ahdy")
+    parser.add_argument("--dry-run", action="store_true")
+    args = parser.parse_args()
+
+    read_conn = pymysql.connect(
+        host=args.host, port=args.port, user=args.user, password=args.password,
+        database=args.database, charset="utf8mb4", autocommit=False
+    )
+    write_conn = pymysql.connect(
+        host=args.host, port=args.port, user=args.user, password=args.password,
+        database=args.database, charset="utf8mb4", autocommit=False
+    )
+    scanned = 0
+    updated = 0
+    skipped = 0
+    failed = 0
+    try:
+        read_cur = read_conn.cursor(SSCursor)
+        write_cur = write_conn.cursor()
+        read_cur.execute(
+            "SELECT id, create_date, content FROM mes_product_arc_welding "
+            "WHERE content LIKE %s",
+            ('%"weldingType":"spot"%',)
+        )
+        for row_id, create_date, content in read_cur:
+            scanned += 1
+            try:
+                new_content = scale_content(content)
+            except Exception as ex:
+                failed += 1
+                print("parse fail id=%s date=%s err=%s" % (row_id, create_date, ex))
+                continue
+            if not new_content:
+                skipped += 1
+            elif not args.dry_run:
+                write_cur.execute(
+                    "UPDATE mes_product_arc_welding SET content=%s WHERE id=%s AND create_date=%s",
+                    (new_content, row_id, create_date)
+                )
+                updated += 1
+                if updated % 200 == 0:
+                    write_conn.commit()
+                    print("updated %s / scanned %s" % (updated, scanned))
+            else:
+                updated += 1
+                if updated % 200 == 0:
+                    print("dry-run would update %s / scanned %s" % (updated, scanned))
+        if not args.dry_run:
+            write_conn.commit()
+        print("done scanned=%s updated=%s skipped=%s failed=%s dry_run=%s"
+              % (scanned, updated, skipped, failed, args.dry_run))
+    finally:
+        read_conn.close()
+        write_conn.close()
+
+
+if __name__ == "__main__":
+    sys.exit(main())

+ 128 - 0
db/mysql/scale_spot_welding_current.sql

@@ -0,0 +1,128 @@
+-- 历史点焊电流 * 10,与当前入库规则对齐
+-- 只处理 weldingType=spot;电流绝对值已经 >= 3 的视为已放大,会跳过
+-- 可重复执行。执行前建议先备份 mes_product_arc_welding
+
+-- 1. 先看有多少点焊 / 弧焊(确认只动点焊)
+SELECT
+  SUM(content LIKE '%"weldingType":"spot"%') AS spot_cnt,
+  SUM(content LIKE '%"weldingType":"arc"%') AS arc_cnt
+FROM mes_product_arc_welding;
+
+-- 2. 看几条点焊当前电流(放大前一般是 0.81,放大后是 8.1)
+SELECT
+  id,
+  oprno,
+  create_date,
+  JSON_UNQUOTE(JSON_EXTRACT(content, '$.samples[0].robot1Current')) AS i1,
+  JSON_UNQUOTE(JSON_EXTRACT(content, '$.samples[0].robot2Current')) AS i2
+FROM mes_product_arc_welding
+WHERE content LIKE '%"weldingType":"spot"%'
+ORDER BY create_date DESC
+LIMIT 10;
+
+-- 3. 执行放大(Navicat 里把分隔符改成 $$ 再跑下面这段)
+DROP PROCEDURE IF EXISTS scale_spot_welding_current;
+
+DELIMITER $$
+CREATE PROCEDURE scale_spot_welding_current()
+BEGIN
+  DECLARE done INT DEFAULT 0;
+  DECLARE rid VARCHAR(64);
+  DECLARE rdate DATETIME;
+  DECLARE rcontent LONGTEXT;
+  DECLARE i INT;
+  DECLARE n INT;
+  DECLARE c1 DECIMAL(20,6);
+  DECLARE c2 DECIMAL(20,6);
+  DECLARE maxc DECIMAL(20,6);
+  DECLARE updated_cnt INT DEFAULT 0;
+  DECLARE skipped_cnt INT DEFAULT 0;
+
+  DECLARE cur CURSOR FOR
+    SELECT id, create_date, content
+    FROM mes_product_arc_welding
+    WHERE content LIKE '%"weldingType":"spot"%';
+  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
+
+  OPEN cur;
+  read_loop: LOOP
+    FETCH cur INTO rid, rdate, rcontent;
+    IF done = 1 THEN
+      LEAVE read_loop;
+    END IF;
+
+    IF rcontent IS NULL OR JSON_VALID(rcontent) = 0 THEN
+      SET skipped_cnt = skipped_cnt + 1;
+      ITERATE read_loop;
+    END IF;
+    IF JSON_UNQUOTE(JSON_EXTRACT(rcontent, '$.weldingType')) <> 'spot' THEN
+      SET skipped_cnt = skipped_cnt + 1;
+      ITERATE read_loop;
+    END IF;
+
+    SET n = IFNULL(JSON_LENGTH(rcontent, '$.samples'), 0);
+    IF n <= 0 THEN
+      SET skipped_cnt = skipped_cnt + 1;
+      ITERATE read_loop;
+    END IF;
+
+    SET maxc = 0;
+    SET i = 0;
+    WHILE i < n DO
+      SET c1 = CAST(JSON_UNQUOTE(JSON_EXTRACT(rcontent, CONCAT('$.samples[', i, '].robot1Current'))) AS DECIMAL(20,6));
+      SET c2 = CAST(JSON_UNQUOTE(JSON_EXTRACT(rcontent, CONCAT('$.samples[', i, '].robot2Current'))) AS DECIMAL(20,6));
+      IF c1 IS NOT NULL AND ABS(c1) > maxc THEN
+        SET maxc = ABS(c1);
+      END IF;
+      IF c2 IS NOT NULL AND ABS(c2) > maxc THEN
+        SET maxc = ABS(c2);
+      END IF;
+      SET i = i + 1;
+    END WHILE;
+
+    -- 没有电流,或已经放大过(>=3),跳过
+    IF maxc <= 0 OR maxc >= 3 THEN
+      SET skipped_cnt = skipped_cnt + 1;
+      ITERATE read_loop;
+    END IF;
+
+    SET i = 0;
+    WHILE i < n DO
+      SET c1 = CAST(JSON_UNQUOTE(JSON_EXTRACT(rcontent, CONCAT('$.samples[', i, '].robot1Current'))) AS DECIMAL(20,6));
+      SET c2 = CAST(JSON_UNQUOTE(JSON_EXTRACT(rcontent, CONCAT('$.samples[', i, '].robot2Current'))) AS DECIMAL(20,6));
+      IF c1 IS NOT NULL THEN
+        SET rcontent = JSON_SET(rcontent, CONCAT('$.samples[', i, '].robot1Current'), c1 * 10);
+      END IF;
+      IF c2 IS NOT NULL THEN
+        SET rcontent = JSON_SET(rcontent, CONCAT('$.samples[', i, '].robot2Current'), c2 * 10);
+      END IF;
+      SET i = i + 1;
+    END WHILE;
+
+    UPDATE mes_product_arc_welding
+    SET content = rcontent
+    WHERE id = rid AND create_date = rdate;
+
+    SET updated_cnt = updated_cnt + 1;
+  END LOOP;
+  CLOSE cur;
+
+  SELECT updated_cnt AS updated_cnt, skipped_cnt AS skipped_cnt;
+END$$
+DELIMITER ;
+
+CALL scale_spot_welding_current();
+DROP PROCEDURE IF EXISTS scale_spot_welding_current;
+
+-- 4. 执行后再抽查,点焊应为 8.1 左右,弧焊仍是原来的电流/电压
+SELECT
+  id,
+  oprno,
+  create_date,
+  JSON_UNQUOTE(JSON_EXTRACT(content, '$.weldingType')) AS welding_type,
+  JSON_UNQUOTE(JSON_EXTRACT(content, '$.samples[0].robot1Current')) AS i1,
+  JSON_UNQUOTE(JSON_EXTRACT(content, '$.samples[0].robot2Current')) AS i2
+FROM mes_product_arc_welding
+WHERE content LIKE '%"weldingType":"spot"%'
+ORDER BY create_date DESC
+LIMIT 10;

+ 12 - 4
docs/PDAGP12检查接口说明.md

@@ -3,14 +3,15 @@
 > 模块:`MesProductGp12Controller`  
 > 服务地址示例:`http://127.0.0.1:8980`  
 > 返回格式:`submit` 为 JeeSite `renderResult`;`pdaCheckItems`、`pdaQueryBySn` 为 `CommonResp`(`result` / `message` / `data`)  
-> 说明:后台在「工件类型」中维护 GP12 检查项。员工用 PDA 扫工件码后,按该工件类型展示检查项并提交。
+> 说明:后台在「工件类型」中维护 GP12 检查项。员工用 PDA 扫工件码后,按该工件类型展示检查项并提交。  
+> 未上 MES 的产线:在「工件类型」配好编码规则(规格/起始位/长度)和 GP12 检查项后,扫码时若工件主数据不存在,会按编码规则自动创建工件;系统里已有的正常工件不会重复创建。
 
 ---
 
 ## 后台维护
 
-1. 打开 **工件类型管理**
-2. 对应类型操作列点击 **GP12检查项**
+1. 打开 **工件类型管理**,配置类型编号及编码规则(`spec` / `specStart` / `length`)
+2. 对应类型操作列点击 **GP12检查项**(可选全部启用中的工件类型,不限 HEV)
 3. 新增检查项:名称、输入类型(选择框/输入框)、排序、最小值/最大值(输入框时)
 
 检查项表:`mes_product_gp12_check`,通过 `cate_sn` 关联 `mes_product_cate.sn`。
@@ -31,6 +32,12 @@
 |:----|:---|:-----|-----|
 |sn|是|string|工件码|
 
+##### 说明
+
+- 工件已存在:直接返回
+- 工件不存在:按工件类型编码规则匹配;匹配成功则自动创建 `mes_product`(备注 `GP12扫码自动创建`)后返回
+- 不存在且规则不匹配:返回失败「工件码不存在,且未匹配到编码规则」
+
 ##### 返回字段说明
 
 |字段路径|类型|中文说明|
@@ -45,7 +52,8 @@
 
 ## 2. 查询 GP12 检查项
 
-扫码后调用本接口,展示该工件类型下已启用的检查项。
+扫码后调用本接口,展示该工件类型下已启用的检查项。  
+传 `sn` 时同样走「已有复用 / 无则按编码规则自动创建」。
 
 ##### 请求URL
 - ` /js/a/mes/mesProductGp12/pdaCheckItems `

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 192 - 0
hs_err_pid7152.log


+ 2 - 0
src/main/java/com/jeesite/modules/mes/dao/MesAdw300DataDao.java

@@ -25,6 +25,8 @@ public interface MesAdw300DataDao extends CrudDao<MesAdw300Data> {
 
 	List<Map<String, Object>> findHourlyEnergy(@Param("startTime") Date startTime, @Param("endTime") Date endTime);
 
+	List<Map<String, Object>> findDailyEnergy(@Param("startTime") Date startTime, @Param("endTime") Date endTime);
+
 	List<Map<String, Object>> findTodayEnergyByPower(@Param("startTime") Date startTime, @Param("endTime") Date endTime);
 
 	List<Map<String, Object>> findHourlyEnergyByPower(@Param("startTime") Date startTime, @Param("endTime") Date endTime);

+ 2 - 0
src/main/java/com/jeesite/modules/mes/dao/MesLineProcessDao.java

@@ -31,6 +31,8 @@ public interface MesLineProcessDao extends CrudDao<MesLineProcess> {
 
     List<MesLineProcess> findOprnoListByLineSn(@Param("lineSn") String lineSn);
 
+    List<String> findOprnosByTitleLike(@Param("title") String title);
+
 
     /**
      * 根据ID修改jar路径

+ 9 - 0
src/main/java/com/jeesite/modules/mes/dao/MesProductArcWeldingDao.java

@@ -1,8 +1,13 @@
 package com.jeesite.modules.mes.dao;
 
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
 import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesProductArcWelding;
+import com.jeesite.modules.mes.entity.MesProductRecord;
 
 /**
  * 弧焊参数DAO接口
@@ -16,4 +21,8 @@ public interface MesProductArcWeldingDao extends CrudDao<MesProductArcWelding> {
 
 	String findProductRecordUpdateBy(MesProductArcWelding mesProductArcWelding);
 
+	List<MesProductArcWelding> findContentByKeys(@Param("list") List<MesProductArcWelding> list);
+
+	List<MesProductRecord> findProductRecordUpdateByList(@Param("list") List<MesProductArcWelding> list);
+
 }

+ 6 - 0
src/main/java/com/jeesite/modules/mes/dao/MesProductCmtDao.java

@@ -1,5 +1,9 @@
 package com.jeesite.modules.mes.dao;
 
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
 import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesProductCmt;
@@ -11,5 +15,7 @@ import com.jeesite.modules.mes.entity.MesProductCmt;
  */
 @MyBatisDao
 public interface MesProductCmtDao extends CrudDao<MesProductCmt> {
+
+	List<MesProductCmt> findContentByIds(@Param("ids") List<String> ids);
 	
 }

+ 6 - 1
src/main/java/com/jeesite/modules/mes/dao/MesProductProdDao.java

@@ -1,5 +1,7 @@
 package com.jeesite.modules.mes.dao;
 
+import java.util.List;
+
 import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesProductProd;
@@ -11,5 +13,8 @@ import com.jeesite.modules.mes.entity.MesProductProd;
  */
 @MyBatisDao
 public interface MesProductProdDao extends CrudDao<MesProductProd> {
-	
+
+	List<MesProductProd> findSnGroupList(MesProductProd mesProductProd);
+
+	long findSnGroupCount(MesProductProd mesProductProd);
 }

+ 36 - 3
src/main/java/com/jeesite/modules/mes/entity/MesProcessParamLimit.java

@@ -15,7 +15,10 @@ import com.jeesite.common.mybatis.mapper.query.QueryType;
 @Table(name="mes_process_param_limit", alias="a", label="工艺参数上下限信息", columns={
 		@Column(name="id", attrName="id", label="id", isPK=true),
 		@Column(name="process_key", attrName="processKey", label="工艺编码", queryType=QueryType.LIKE),
-		@Column(name="process_name", attrName="processName", label="工艺名称", queryType=QueryType.LIKE),
+		@Column(name="process_name", attrName="processName", label="工位名称", queryType=QueryType.LIKE),
+		@Column(name="line_sn", attrName="lineSn", label="产线编号", queryType=QueryType.LIKE),
+		@Column(name="oprno", attrName="oprno", label="工位号", queryType=QueryType.LIKE),
+		@Column(name="gun_type", attrName="gunType", label="类型", isUpdateForce=true),
 		@Column(name="param_code", attrName="paramCode", label="参数编码", queryType=QueryType.LIKE),
 		@Column(name="param_name", attrName="paramName", label="参数名称", queryType=QueryType.LIKE),
 		@Column(name="lower_limit", attrName="lowerLimit", label="下限", isUpdateForce=true),
@@ -34,7 +37,10 @@ public class MesProcessParamLimit extends DataEntity<MesProcessParamLimit> {
 	private static final long serialVersionUID = 1L;
 
 	private String processKey;		// 工艺编码
-	private String processName;		// 工艺名称
+	private String processName;		// 工位名称
+	private String lineSn;			// 产线编号
+	private String oprno;			// 工位号
+	private String gunType;			// 类型,A枪 B枪
 	private String paramCode;		// 参数编码
 	private String paramName;		// 参数名称
 	private String lowerLimit;		// 下限
@@ -59,7 +65,7 @@ public class MesProcessParamLimit extends DataEntity<MesProcessParamLimit> {
 		this.processKey = processKey;
 	}
 
-	@Size(min=0, max=100, message="工艺名称长度不能超过 100 个字符")
+	@Size(min=0, max=100, message="工位名称长度不能超过 100 个字符")
 	public String getProcessName() {
 		return processName;
 	}
@@ -68,6 +74,33 @@ public class MesProcessParamLimit extends DataEntity<MesProcessParamLimit> {
 		this.processName = processName;
 	}
 
+	@Size(min=0, max=20, message="产线编号长度不能超过 20 个字符")
+	public String getLineSn() {
+		return lineSn;
+	}
+
+	public void setLineSn(String lineSn) {
+		this.lineSn = lineSn;
+	}
+
+	@Size(min=0, max=20, message="工位号长度不能超过 20 个字符")
+	public String getOprno() {
+		return oprno;
+	}
+
+	public void setOprno(String oprno) {
+		this.oprno = oprno;
+	}
+
+	@Size(min=0, max=20, message="类型长度不能超过 20 个字符")
+	public String getGunType() {
+		return gunType;
+	}
+
+	public void setGunType(String gunType) {
+		this.gunType = gunType;
+	}
+
 	@Size(min=0, max=50, message="参数编码长度不能超过 50 个字符")
 	public String getParamCode() {
 		return paramCode;

+ 2 - 7
src/main/java/com/jeesite/modules/mes/entity/MesProductArcWelding.java

@@ -20,8 +20,8 @@ import com.jeesite.common.utils.excel.annotation.ExcelFields;
  */
 @Table(name="mes_product_arc_welding", alias="a", label="弧焊参数信息", columns={
 		@Column(name="id", attrName="id", label="id", isPK=true),
-		@Column(name="line_sn", attrName="lineSn", label="产线编号", queryType=QueryType.LIKE),
-		@Column(name="oprno", attrName="oprno", label="工位号", queryType=QueryType.LIKE),
+		@Column(name="line_sn", attrName="lineSn", label="产线编号"),
+		@Column(name="oprno", attrName="oprno", label="工位号"),
 		@Column(name="sn", attrName="sn", label="工件码", queryType=QueryType.LIKE),
 		@Column(name="content", attrName="content", label="参数内容", isQuery=false),
 		@Column(name="create_date", attrName="createDate", label="创建时间", isPK=true, isUpdate=false, isQuery=false),
@@ -127,11 +127,6 @@ public class MesProductArcWelding extends DataEntity<MesProductArcWelding> {
 
 	public void setWeldingCategory(String weldingCategory) {
 		this.weldingCategory = weldingCategory;
-		if ("spot".equals(weldingCategory)) {
-			sqlMap.getWhere().and("b.title", QueryType.LIKE, "点焊");
-		} else if ("arc".equals(weldingCategory)) {
-			sqlMap.getWhere().and("b.title", QueryType.LIKE, "弧焊");
-		}
 	}
 
 	public String getLimitFlag() {

+ 4 - 1
src/main/java/com/jeesite/modules/mes/entity/MesProductCheckOne.java

@@ -49,7 +49,7 @@ public class MesProductCheckOne extends DataEntity<MesProductCheckOne> {
 			@ExcelField(title = "工位号", attrName = "oprno", align = Align.CENTER, sort = 30),
 			@ExcelField(title = "产线编号", attrName = "lineSn", align = Align.CENTER, sort = 40),
 			@ExcelField(title = "结果", attrName = "result", align = Align.CENTER, sort = 50),
-			@ExcelField(title = "确认检查", attrName = "confirmCheckLabel", align = Align.CENTER, sort = 60),
+			@ExcelField(title = "NG检查", attrName = "confirmCheckLabel", align = Align.CENTER, sort = 60),
 			@ExcelField(title = "备注", attrName = "remark", align = Align.CENTER, sort = 70),
 			@ExcelField(title = "创建人", attrName = "createBy", align = Align.CENTER, sort = 80),
 			@ExcelField(title = "创建时间", attrName = "createDate", align = Align.CENTER, sort = 90, dataFormat = "yyyy-MM-dd hh:mm:ss"),
@@ -115,6 +115,9 @@ public class MesProductCheckOne extends DataEntity<MesProductCheckOne> {
 	}
 
 	public String getConfirmCheckLabel() {
+		if ("OK".equals(result)) {
+			return "无需确认";
+		}
 		if ("1".equals(confirmCheck)) {
 			return "已确认";
 		}

+ 1 - 1
src/main/java/com/jeesite/modules/mes/entity/MesProductCmt.java

@@ -22,7 +22,7 @@ import com.jeesite.common.utils.excel.annotation.ExcelFields;
 		@Column(name="line_sn", attrName="lineSn", label="产线编号"),
 		@Column(name="content", attrName="content", label="参数内容"),
 		@Column(name="create_date", attrName="createDate", label="创建时间", isUpdate=false, isQuery=false, isUpdateForce=true),
-	}, orderBy="a.id DESC"
+	}, orderBy="a.create_date DESC, a.id DESC"
 )
 public class MesProductCmt extends DataEntity<MesProductCmt> {
 	

+ 20 - 0
src/main/java/com/jeesite/modules/mes/entity/MesProductGlueDuration.java

@@ -119,4 +119,24 @@ public class MesProductGlueDuration extends DataEntity<MesProductGlueDuration> {
 		}
 	}
 
+	public java.util.Date getCreateDate_gte() {
+		return sqlMap.getWhere().getValue("a.create_date", QueryType.GTE);
+	}
+
+	public void setCreateDate_gte(java.util.Date createDate) {
+		if (createDate != null) {
+			sqlMap.getWhere().and("a.create_date", QueryType.GTE, createDate);
+		}
+	}
+
+	public java.util.Date getCreateDate_lte() {
+		return sqlMap.getWhere().getValue("a.create_date", QueryType.LTE);
+	}
+
+	public void setCreateDate_lte(java.util.Date createDate) {
+		if (createDate != null) {
+			sqlMap.getWhere().and("a.create_date", QueryType.LTE, createDate);
+		}
+	}
+
 }

+ 27 - 0
src/main/java/com/jeesite/modules/mes/entity/MesProductProd.java

@@ -57,6 +57,9 @@ public class MesProductProd extends DataEntity<MesProductProd> {
 	private Date dateTime;		// 拉铆时间
 	private String oldSn;
 	private String limitFlag;	// 超限标记:1-超限 0-正常
+	private Integer recordCount;	// 拉铆次数(按工件聚合)
+	private Integer okCount;		// OK次数(按工件聚合)
+	private Integer ngCount;		// NG次数(按工件聚合)
 
 	@ExcelFields({
 			@ExcelField(title="工件码", attrName="sn", align=Align.CENTER, sort=20),
@@ -214,6 +217,30 @@ public class MesProductProd extends DataEntity<MesProductProd> {
 		this.limitFlag = limitFlag;
 	}
 
+	public Integer getRecordCount() {
+		return recordCount;
+	}
+
+	public void setRecordCount(Integer recordCount) {
+		this.recordCount = recordCount;
+	}
+
+	public Integer getOkCount() {
+		return okCount;
+	}
+
+	public void setOkCount(Integer okCount) {
+		this.okCount = okCount;
+	}
+
+	public Integer getNgCount() {
+		return ngCount;
+	}
+
+	public void setNgCount(Integer ngCount) {
+		this.ngCount = ngCount;
+	}
+
 	public Date getDateTime_gte() {
 		return sqlMap.getWhere().getValue("date_time", QueryType.GTE);
 	}

+ 74 - 0
src/main/java/com/jeesite/modules/mes/service/MesAdw300DataService.java

@@ -72,6 +72,8 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 		Date now = new Date();
 		Date todayStart = getTodayStart(now);
 		Date tomorrowStart = new Date(todayStart.getTime() + 24L * 60L * 60L * 1000L);
+		Date monthStart = getMonthStart(now);
+		Date nextMonthStart = getNextMonthStart(monthStart);
 
 		List<String> deviceSnList = dao.findDeviceSnList();
 		List<Map<String, Object>> latestRows = dao.findLatestSnapshot();
@@ -92,9 +94,11 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 		}
 
 		Map<String, Double> todayEnergyMap = mapNumberByDevice(dao.findTodayEnergy(todayStart, tomorrowStart), "energy");
+		Map<String, Double> monthEnergyMap = mapNumberByDevice(dao.findTodayEnergy(monthStart, nextMonthStart), "energy");
 		List<Map<String, Object>> devices = ListUtils.newArrayList();
 		double totalPower = 0D;
 		double totalEnergy = 0D;
+		double totalMonthEnergy = 0D;
 		int onlineCount = 0;
 
 		for (Map.Entry<String, Map<Integer, Map<String, Object>>> entry : latestMap.entrySet()) {
@@ -104,6 +108,8 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 			double power = calculatePower(deviceSn, points);
 			double todayEnergyRaw = todayEnergyMap.getOrDefault(deviceSn, 0D);
 			double todayEnergy = scaleByCtRatio(deviceSn, todayEnergyRaw);
+			double monthEnergyRaw = monthEnergyMap.getOrDefault(deviceSn, 0D);
+			double monthEnergy = scaleByCtRatio(deviceSn, monthEnergyRaw);
 			Date reportTime = getDate(points);
 			boolean online = !points.isEmpty();
 			if (online) {
@@ -111,6 +117,7 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 			}
 			totalPower += power;
 			totalEnergy += todayEnergy;
+			totalMonthEnergy += monthEnergy;
 			double totalEnergyValue = scaleByCtRatio(deviceSn, getPointDouble(points, 28));
 
 			device.put("deviceSn", deviceSn);
@@ -120,6 +127,7 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 			device.put("reportTimeText", getDateText(points));
 			device.put("power", round(power));
 			device.put("todayEnergy", round(todayEnergy));
+			device.put("monthEnergy", round(monthEnergy));
 			device.put("totalEnergy", round(totalEnergyValue));
 			device.put("ua", round(getPointDouble(points, 1)));
 			device.put("ub", round(getPointDouble(points, 2)));
@@ -130,14 +138,18 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 			devices.add(device);
 		}
 
+		List<String> days = buildMonthDays(monthStart, nextMonthStart);
 		Map<String, Object> data = MapUtils.newHashMap();
 		data.put("devices", devices);
 		data.put("deviceCount", devices.size());
 		data.put("onlineCount", onlineCount);
 		data.put("totalPower", round(totalPower));
 		data.put("todayEnergy", round(totalEnergy));
+		data.put("monthEnergy", round(totalMonthEnergy));
 		data.put("hours", buildHours());
 		data.put("hourlySeries", buildHourlySeries(deviceSnList, dao.findHourlyEnergy(todayStart, tomorrowStart)));
+		data.put("days", days);
+		data.put("dailySeries", buildDailySeries(deviceSnList, days, dao.findDailyEnergy(monthStart, nextMonthStart)));
 		data.put("refreshTime", now);
 		return data;
 	}
@@ -195,6 +207,24 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 		return calendar.getTime();
 	}
 
+	private Date getMonthStart(Date now) {
+		java.util.Calendar calendar = java.util.Calendar.getInstance();
+		calendar.setTime(now);
+		calendar.set(java.util.Calendar.DAY_OF_MONTH, 1);
+		calendar.set(java.util.Calendar.HOUR_OF_DAY, 0);
+		calendar.set(java.util.Calendar.MINUTE, 0);
+		calendar.set(java.util.Calendar.SECOND, 0);
+		calendar.set(java.util.Calendar.MILLISECOND, 0);
+		return calendar.getTime();
+	}
+
+	private Date getNextMonthStart(Date monthStart) {
+		java.util.Calendar calendar = java.util.Calendar.getInstance();
+		calendar.setTime(monthStart);
+		calendar.add(java.util.Calendar.MONTH, 1);
+		return calendar.getTime();
+	}
+
 	private Date getHalfHourStart(Date reportTime) {
 		java.util.Calendar calendar = java.util.Calendar.getInstance();
 		calendar.setTime(reportTime);
@@ -213,6 +243,18 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 		return hours;
 	}
 
+	private List<String> buildMonthDays(Date monthStart, Date nextMonthStart) {
+		List<String> days = ListUtils.newArrayList();
+		java.util.Calendar calendar = java.util.Calendar.getInstance();
+		calendar.setTime(monthStart);
+		while (calendar.getTime().before(nextMonthStart)) {
+			days.add(String.format("%02d-%02d", calendar.get(java.util.Calendar.MONTH) + 1,
+					calendar.get(java.util.Calendar.DAY_OF_MONTH)));
+			calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
+		}
+		return days;
+	}
+
 	private List<Map<String, Object>> buildHourlySeries(List<String> deviceSnList, List<Map<String, Object>> rows) {
 		Map<String, Map<String, Double>> dataMap = new LinkedHashMap<>();
 		for (String deviceSn : deviceSnList) {
@@ -256,6 +298,38 @@ public class MesAdw300DataService extends CrudService<MesAdw300DataDao, MesAdw30
 		}
 	}
 
+	private List<Map<String, Object>> buildDailySeries(List<String> deviceSnList, List<String> days,
+			List<Map<String, Object>> rows) {
+		Map<String, Map<String, Double>> dataMap = new LinkedHashMap<>();
+		for (String deviceSn : deviceSnList) {
+			dataMap.put(deviceSn, new LinkedHashMap<>());
+		}
+		for (Map<String, Object> row : rows) {
+			String deviceSn = getString(row.get("deviceSn"));
+			String dayLabel = getString(row.get("dayLabel"));
+			if (deviceSn == null || dayLabel == null) {
+				continue;
+			}
+			if (!dataMap.containsKey(deviceSn)) {
+				dataMap.put(deviceSn, new LinkedHashMap<>());
+			}
+			dataMap.get(deviceSn).put(dayLabel, scaleByCtRatio(deviceSn, getDouble(row.get("energy"))));
+		}
+
+		List<Map<String, Object>> series = ListUtils.newArrayList();
+		for (Map.Entry<String, Map<String, Double>> entry : dataMap.entrySet()) {
+			Map<String, Object> item = MapUtils.newHashMap();
+			List<Double> values = ListUtils.newArrayList();
+			for (String day : days) {
+				values.add(round(entry.getValue().getOrDefault(day, 0D)));
+			}
+			item.put("name", getDeviceName(entry.getKey()));
+			item.put("data", values);
+			series.add(item);
+		}
+		return series;
+	}
+
 	private Map<String, Double> mapNumberByDevice(List<Map<String, Object>> rows, String key) {
 		Map<String, Double> result = new LinkedHashMap<>();
 		for (Map<String, Object> row : rows) {

+ 8 - 0
src/main/java/com/jeesite/modules/mes/service/MesLineProcessService.java

@@ -57,6 +57,14 @@ public class MesLineProcessService extends CrudService<MesLineProcessDao, MesLin
 		return mesLineProcessDao.findInfo(mesLineProcess);
 	}
 
+	public List<String> findOprnosByTitleLike(String title) {
+		if (StringUtils.isBlank(title)) {
+			return Collections.emptyList();
+		}
+		List<String> oprnos = mesLineProcessDao.findOprnosByTitleLike(title.trim());
+		return oprnos == null ? Collections.emptyList() : oprnos;
+	}
+
 	public MesLineProcess findPreviousByOprnoLineSn(String oprno, String lineSn){
 		if (StringUtils.isBlank(oprno) || StringUtils.isBlank(lineSn)) {
 			return null;

+ 231 - 16
src/main/java/com/jeesite/modules/mes/service/MesProcessParamLimitCheckService.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.jeesite.common.lang.StringUtils;
 import com.jeesite.modules.mes.entity.*;
+import com.jeesite.modules.mes.util.CommonUitl;
 import org.springframework.beans.BeanWrapperImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -22,6 +23,7 @@ import java.util.Map;
 @Service
 public class MesProcessParamLimitCheckService {
 
+	private static final int LIST_CHECK_MAX_SAMPLES = 50;
 	private static final Map<String, String[]> ARC_PARAM_ALIASES = new HashMap<>();
 
 	static {
@@ -46,7 +48,7 @@ public class MesProcessParamLimitCheckService {
 		}
 		String processKey = normalizeProcessKey(qmCategory);
 		for (MesProductQm row : list) {
-			row.setLimitFlag(checkBeanRow(row, limitMap.get(processKey)) ? "1" : "0");
+			row.setLimitFlag(checkBeanRow(row, resolveLimits(limitMap, row.getLineSn(), row.getOprno(), processKey)) ? "1" : "0");
 		}
 	}
 
@@ -56,7 +58,10 @@ public class MesProcessParamLimitCheckService {
 			return;
 		}
 		for (MesProductProd row : list) {
-			row.setLimitFlag(checkBeanRow(row, limitMap.get(resolveProdProcessKey(row))) ? "1" : "0");
+			List<NormalizedLimit> limits = filterByGunType(
+					resolveLimits(limitMap, row.getLineSn(), row.getOprno(), resolveProdProcessKey(row)),
+					row.getType());
+			row.setLimitFlag(checkBeanRow(row, limits) ? "1" : "0");
 		}
 	}
 
@@ -66,7 +71,7 @@ public class MesProcessParamLimitCheckService {
 			return;
 		}
 		for (MesWelderParamRecord row : list) {
-			row.setLimitFlag(checkBeanRow(row, limitMap.get("welder")) ? "1" : "0");
+			row.setLimitFlag(checkBeanRow(row, resolveLimits(limitMap, null, row.getOprno(), "welder")) ? "1" : "0");
 		}
 	}
 
@@ -81,7 +86,7 @@ public class MesProcessParamLimitCheckService {
 		}
 		for (MesProductArcWelding row : list) {
 			String processKey = resolveArcProcessKey(row, weldingCategory, processName);
-			row.setLimitFlag(checkArcRow(row, limitMap.get(processKey)) ? "1" : "0");
+			row.setLimitFlag(checkArcRow(row, resolveLimits(limitMap, row.getLineSn(), row.getOprno(), processKey)) ? "1" : "0");
 		}
 	}
 
@@ -90,9 +95,12 @@ public class MesProcessParamLimitCheckService {
 		if (list == null || list.isEmpty()) {
 			return;
 		}
-		List<NormalizedLimit> limits = limitMap.get("arc115");
 		for (MesProductCmt row : list) {
-			row.setLimitFlag(checkArcContent(row == null ? null : row.getContent(), limits, true) ? "1" : "0");
+			List<NormalizedLimit> limits = resolveLimits(limitMap,
+					row == null ? null : row.getLineSn(),
+					row == null ? null : row.getOprno(),
+					"arc115");
+			row.setLimitFlag(checkArcContent(row == null ? null : row.getContent(), limits, true, LIST_CHECK_MAX_SAMPLES) ? "1" : "0");
 		}
 	}
 
@@ -102,13 +110,20 @@ public class MesProcessParamLimitCheckService {
 
 	public List<ArcLimitRule> findArcLimitRules(MesProductArcWelding row, String weldingCategory, String processName) {
 		Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
-		List<NormalizedLimit> limits = limitMap.get(resolveArcProcessKey(row, weldingCategory, processName));
+		List<NormalizedLimit> limits = resolveLimits(limitMap,
+				row == null ? null : row.getLineSn(),
+				row == null ? null : row.getOprno(),
+				resolveArcProcessKey(row, weldingCategory, processName));
 		return toArcLimitRules(limits);
 	}
 
 	public List<ArcLimitRule> findCmtLimitRules() {
+		return findCmtLimitRules(null, null);
+	}
+
+	public List<ArcLimitRule> findCmtLimitRules(String lineSn, String oprno) {
 		Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
-		return toArcLimitRules(limitMap.get("arc115"));
+		return toArcLimitRules(resolveLimits(limitMap, lineSn, oprno, "arc115"));
 	}
 
 	private List<ArcLimitRule> toArcLimitRules(List<NormalizedLimit> limits) {
@@ -128,12 +143,20 @@ public class MesProcessParamLimitCheckService {
 
 	public boolean checkArcRecord(MesProductArcWelding row, String weldingCategory, String processName) {
 		Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
-		return checkArcRow(row, limitMap.get(resolveArcProcessKey(row, weldingCategory, processName)));
+		return checkArcRow(row, resolveLimits(limitMap,
+				row == null ? null : row.getLineSn(),
+				row == null ? null : row.getOprno(),
+				resolveArcProcessKey(row, weldingCategory, processName)));
 	}
 
 	public boolean checkCmtRecord(MesProductCmt row) {
 		Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
-		return checkArcContent(row == null ? null : row.getContent(), limitMap.get("arc115"), true);
+		return checkArcContent(row == null ? null : row.getContent(),
+				resolveLimits(limitMap,
+						row == null ? null : row.getLineSn(),
+						row == null ? null : row.getOprno(),
+						"arc115"),
+				true);
 	}
 
 	private Map<String, List<NormalizedLimit>> loadLimitMap() {
@@ -141,15 +164,186 @@ public class MesProcessParamLimitCheckService {
 		for (MesProcessParamLimit limit : mesProcessParamLimitService.findEnabledList()) {
 			String processKey = resolveLimitProcessKey(limit);
 			String paramCode = normalizeParamCode(StringUtils.defaultString(limit.getParamCode(), limit.getParamName()));
-			if (StringUtils.isBlank(processKey) || StringUtils.isBlank(paramCode)) {
+			if (StringUtils.isBlank(paramCode)) {
+				continue;
+			}
+			String lineSn = StringUtils.trim(limit.getLineSn());
+			String oprno = StringUtils.trim(limit.getOprno());
+			String mapKey;
+			if (StringUtils.isNotBlank(lineSn) && StringUtils.isNotBlank(oprno)) {
+				mapKey = stationMapKey(lineSn, oprno);
+			} else if (StringUtils.isNotBlank(processKey)) {
+				mapKey = processKey;
+			} else {
 				continue;
 			}
-			NormalizedLimit normalized = new NormalizedLimit(processKey, paramCode, limit.getLowerLimit(), limit.getUpperLimit());
-			map.computeIfAbsent(processKey, k -> new ArrayList<>()).add(normalized);
+			NormalizedLimit normalized = new NormalizedLimit(processKey, lineSn, oprno,
+					normalizeGunType(limit.getGunType()), paramCode,
+					limit.getLowerLimit(), limit.getUpperLimit());
+			map.computeIfAbsent(mapKey, k -> new ArrayList<>()).add(normalized);
 		}
 		return map;
 	}
 
+	private List<NormalizedLimit> resolveLimits(Map<String, List<NormalizedLimit>> limitMap, String lineSn, String oprno, String processKey) {
+		List<NormalizedLimit> stationLimits = filterByProcessKey(findStationLimits(limitMap, lineSn, oprno), processKey);
+		if (stationLimits != null && !stationLimits.isEmpty()) {
+			return stationLimits;
+		}
+		if (StringUtils.isBlank(processKey) || limitMap == null) {
+			return null;
+		}
+		return limitMap.get(processKey);
+	}
+
+	private List<NormalizedLimit> findStationLimits(Map<String, List<NormalizedLimit>> limitMap, String lineSn, String oprno) {
+		if (limitMap == null || StringUtils.isBlank(oprno)) {
+			return null;
+		}
+		List<NormalizedLimit> exactLine = new ArrayList<>();
+		List<NormalizedLimit> familyLine = new ArrayList<>();
+		boolean hasLine = StringUtils.isNotBlank(lineSn);
+		for (Map.Entry<String, List<NormalizedLimit>> entry : limitMap.entrySet()) {
+			String key = entry.getKey();
+			if (key == null || !key.startsWith("s:") || entry.getValue() == null) {
+				continue;
+			}
+			for (NormalizedLimit limit : entry.getValue()) {
+				if (limit == null || !oprnoMatches(oprno, limit.oprno)) {
+					continue;
+				}
+				if (!hasLine) {
+					familyLine.add(limit);
+					continue;
+				}
+				if (StringUtils.equalsIgnoreCase(StringUtils.trim(lineSn), StringUtils.trim(limit.lineSn))) {
+					exactLine.add(limit);
+				} else if (sameLineFamily(lineSn, limit.lineSn)) {
+					familyLine.add(limit);
+				}
+			}
+		}
+		if (!exactLine.isEmpty()) {
+			return exactLine;
+		}
+		return familyLine.isEmpty() ? null : familyLine;
+	}
+
+	private List<NormalizedLimit> filterByGunType(List<NormalizedLimit> limits, String recordGunType) {
+		if (limits == null || limits.isEmpty()) {
+			return limits;
+		}
+		String gun = normalizeGunType(recordGunType);
+		List<NormalizedLimit> matched = new ArrayList<>();
+		for (NormalizedLimit limit : limits) {
+			if (limit == null) {
+				continue;
+			}
+			if (StringUtils.isBlank(limit.gunType) || StringUtils.equals(limit.gunType, gun)) {
+				matched.add(limit);
+			}
+		}
+		return matched;
+	}
+
+	private String normalizeGunType(String value) {
+		String text = StringUtils.upperCase(StringUtils.trim(value));
+		if (StringUtils.isBlank(text)) {
+			return "";
+		}
+		if (StringUtils.startsWith(text, "A")) {
+			return "A";
+		}
+		if (StringUtils.startsWith(text, "B")) {
+			return "B";
+		}
+		return "";
+	}
+
+	private List<NormalizedLimit> filterByProcessKey(List<NormalizedLimit> limits, String processKey) {
+		if (limits == null || limits.isEmpty() || StringUtils.isBlank(processKey)) {
+			return limits;
+		}
+		List<NormalizedLimit> matched = new ArrayList<>();
+		for (NormalizedLimit limit : limits) {
+			if (limit != null && processKeyMatches(limit.processKey, processKey)) {
+				matched.add(limit);
+			}
+		}
+		return matched;
+	}
+
+	private boolean processKeyMatches(String limitKey, String requestedKey) {
+		if (StringUtils.isBlank(requestedKey) || StringUtils.isBlank(limitKey)) {
+			return true;
+		}
+		if (requestedKey.equals(limitKey)) {
+			return true;
+		}
+		return processKeyGroup(limitKey).equals(processKeyGroup(requestedKey));
+	}
+
+	private String processKeyGroup(String processKey) {
+		if ("arc".equals(processKey) || "arcHev".equals(processKey)) {
+			return "arcHev";
+		}
+		if ("spot".equals(processKey) || "spotHev".equals(processKey)) {
+			return "spotHev";
+		}
+		return processKey;
+	}
+
+	private boolean sameLineFamily(String left, String right) {
+		String familyLeft = lineFamily(left);
+		String familyRight = lineFamily(right);
+		return StringUtils.isNotBlank(familyLeft) && familyLeft.equals(familyRight);
+	}
+
+	private String lineFamily(String lineSn) {
+		String line = StringUtils.upperCase(StringUtils.trim(lineSn));
+		if (StringUtils.isBlank(line)) {
+			return "";
+		}
+		if (line.contains("115")) {
+			return "115";
+		}
+		if (line.contains("HEV")) {
+			return "HEV";
+		}
+		return line;
+	}
+
+	private boolean oprnoMatches(String recordOprno, String limitOprno) {
+		if (StringUtils.isBlank(recordOprno) || StringUtils.isBlank(limitOprno)) {
+			return false;
+		}
+		String record = recordOprno.trim();
+		String limit = limitOprno.trim();
+		if (record.equalsIgnoreCase(limit)) {
+			return true;
+		}
+		String recordParent = safeFormatOprno(record);
+		String limitParent = safeFormatOprno(limit);
+		if (StringUtils.isNotBlank(recordParent) && recordParent.equalsIgnoreCase(limitParent)) {
+			return true;
+		}
+		if (record.length() == 5 && (record + "A").equalsIgnoreCase(limit)) {
+			return true;
+		}
+		return limit.length() == 5 && (limit + "A").equalsIgnoreCase(record);
+	}
+
+	private String stationMapKey(String lineSn, String oprno) {
+		return "s:" + StringUtils.upperCase(StringUtils.trim(lineSn)) + "|" + StringUtils.upperCase(StringUtils.trim(oprno));
+	}
+
+	private String safeFormatOprno(String oprno) {
+		if (StringUtils.isBlank(oprno)) {
+			return "";
+		}
+		return CommonUitl.formatOprno(oprno.trim());
+	}
+
 	private String resolveLimitProcessKey(MesProcessParamLimit limit) {
 		if (limit == null) {
 			return "";
@@ -191,14 +385,18 @@ public class MesProcessParamLimitCheckService {
 	}
 
 	private boolean checkArcRow(MesProductArcWelding row, List<NormalizedLimit> limits) {
-		return checkArcContent(row == null ? null : row.getContent(), limits, false);
+		return checkArcContent(row == null ? null : row.getContent(), limits, false, LIST_CHECK_MAX_SAMPLES);
 	}
 
 	private boolean checkArcContent(String content, List<NormalizedLimit> limits, boolean swapVoltageCurrent) {
+		return checkArcContent(content, limits, swapVoltageCurrent, 0);
+	}
+
+	private boolean checkArcContent(String content, List<NormalizedLimit> limits, boolean swapVoltageCurrent, int maxSamples) {
 		if (limits == null || limits.isEmpty() || StringUtils.isBlank(content)) {
 			return false;
 		}
-		for (JSONObject sample : parseArcSamples(content, swapVoltageCurrent)) {
+		for (JSONObject sample : parseArcSamples(content, swapVoltageCurrent, maxSamples)) {
 			for (NormalizedLimit limit : limits) {
 				for (String value : readArcValues(sample, limit.paramCode)) {
 					if (isOutOfRange(value, limit)) {
@@ -211,6 +409,10 @@ public class MesProcessParamLimitCheckService {
 	}
 
 	private List<JSONObject> parseArcSamples(String content, boolean swapVoltageCurrent) {
+		return parseArcSamples(content, swapVoltageCurrent, 0);
+	}
+
+	private List<JSONObject> parseArcSamples(String content, boolean swapVoltageCurrent, int maxSamples) {
 		List<JSONObject> result = new ArrayList<>();
 		try {
 			String text = StringUtils.trim(content);
@@ -222,6 +424,9 @@ public class MesProcessParamLimitCheckService {
 				JSONArray samples = root == null ? null : root.getJSONArray("samples");
 				if (samples != null) {
 					for (int i = 0; i < samples.size(); i++) {
+						if (maxSamples > 0 && result.size() >= maxSamples) {
+							break;
+						}
 						JSONObject sample = samples.getJSONObject(i);
 						if (sample != null) {
 							result.add(sample);
@@ -234,6 +439,9 @@ public class MesProcessParamLimitCheckService {
 				JSONArray arr = JSONArray.parseArray(text);
 				if (arr != null) {
 					for (int i = 0; i < arr.size(); i++) {
+						if (maxSamples > 0 && result.size() >= maxSamples) {
+							break;
+						}
 						String record = arr.getString(i);
 						appendOldArcRecord(record, result, swapVoltageCurrent);
 					}
@@ -533,12 +741,19 @@ public class MesProcessParamLimitCheckService {
 
 	private static class NormalizedLimit {
 		private final String processKey;
+		private final String lineSn;
+		private final String oprno;
+		private final String gunType;
 		private final String paramCode;
 		private final String lowerLimit;
 		private final String upperLimit;
 
-		private NormalizedLimit(String processKey, String paramCode, String lowerLimit, String upperLimit) {
+		private NormalizedLimit(String processKey, String lineSn, String oprno, String gunType, String paramCode,
+				String lowerLimit, String upperLimit) {
 			this.processKey = processKey;
+			this.lineSn = lineSn;
+			this.oprno = oprno;
+			this.gunType = gunType;
 			this.paramCode = paramCode;
 			this.lowerLimit = lowerLimit;
 			this.upperLimit = upperLimit;

+ 15 - 0
src/main/java/com/jeesite/modules/mes/service/MesProductArcWeldingService.java

@@ -7,6 +7,7 @@ import org.springframework.transaction.annotation.Transactional;
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.service.CrudService;
 import com.jeesite.modules.mes.entity.MesProductArcWelding;
+import com.jeesite.modules.mes.entity.MesProductRecord;
 import com.jeesite.modules.mes.dao.MesProductArcWeldingDao;
 import com.jeesite.common.service.ServiceException;
 import com.jeesite.common.config.Global;
@@ -33,6 +34,20 @@ public class MesProductArcWeldingService extends CrudService<MesProductArcWeldin
 	public String findProductRecordUpdateBy(MesProductArcWelding mesProductArcWelding) {
 		return dao.findProductRecordUpdateBy(mesProductArcWelding);
 	}
+
+	public List<MesProductArcWelding> findContentByKeys(List<MesProductArcWelding> list) {
+		if (list == null || list.isEmpty()) {
+			return java.util.Collections.emptyList();
+		}
+		return dao.findContentByKeys(list);
+	}
+
+	public List<MesProductRecord> findProductRecordUpdateByList(List<MesProductArcWelding> list) {
+		if (list == null || list.isEmpty()) {
+			return java.util.Collections.emptyList();
+		}
+		return dao.findProductRecordUpdateByList(list);
+	}
 	
 	/**
 	 * 获取单条数据

+ 177 - 0
src/main/java/com/jeesite/modules/mes/service/MesProductCheckOneService.java

@@ -1,15 +1,27 @@
 package com.jeesite.modules.mes.service;
 
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import com.jeesite.common.collect.ListUtils;
 import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.common.service.CrudService;
 import com.jeesite.modules.file.utils.FileUploadUtils;
 import com.jeesite.modules.mes.dao.MesProductCheckOneDao;
 import com.jeesite.modules.mes.entity.MesProductCheckOne;
+import com.jeesite.modules.mes.resp.MesShiftDataResp;
+import com.jeesite.modules.mes.util.CommonUitl;
+import com.jeesite.modules.sys.entity.User;
 
 /**
  * 首件检记录Service
@@ -17,6 +29,9 @@ import com.jeesite.modules.mes.entity.MesProductCheckOne;
 @Service
 public class MesProductCheckOneService extends CrudService<MesProductCheckOneDao, MesProductCheckOne> {
 
+	@Autowired
+	private MesShiftService mesShiftService;
+
 	@Override
 	public MesProductCheckOne get(MesProductCheckOne mesProductCheckOne) {
 		return super.get(mesProductCheckOne);
@@ -35,8 +50,20 @@ public class MesProductCheckOneService extends CrudService<MesProductCheckOneDao
 	@Override
 	@Transactional
 	public void save(MesProductCheckOne mesProductCheckOne) {
+		// 工位接口会话用户多为 system,preInsert/preUpdate 会把 update_by 覆盖成会话用户
+		String operator = StringUtils.defaultIfBlank(mesProductCheckOne.getUpdateBy(), mesProductCheckOne.getCreateBy());
+		if (StringUtils.isNotBlank(operator)) {
+			User user = new User();
+			user.setUserCode(operator);
+			user.setUserName(operator);
+			mesProductCheckOne.setCurrentUser(user);
+		}
 		super.save(mesProductCheckOne);
 		FileUploadUtils.saveFileUpload(mesProductCheckOne, mesProductCheckOne.getId(), "mesProductCheckOne_image");
+		if (StringUtils.isNotBlank(operator) && !operator.equals(mesProductCheckOne.getUpdateBy())) {
+			mesProductCheckOne.setUpdateBy(operator);
+			super.update(mesProductCheckOne);
+		}
 	}
 
 	@Override
@@ -50,4 +77,154 @@ public class MesProductCheckOneService extends CrudService<MesProductCheckOneDao
 	public void delete(MesProductCheckOne mesProductCheckOne) {
 		super.delete(mesProductCheckOne);
 	}
+
+	/**
+	 * 扫码加工拦截:本班次本工位最新首件检为 OK 才放行;
+	 * 尚无记录时放行首件;NG 须确认后才能再做一件并重新首件检。
+	 * @return 拦截原因,null 表示可以加工
+	 */
+	public String getProcessBlockMessage(String oprno, String lineSn) {
+		if (!CommonUitl.needCheckOne(oprno, lineSn)) {
+			return null;
+		}
+		Date[] shiftRange = getCurrentShiftRange();
+		if (shiftRange == null) {
+			return "未查询到班次";
+		}
+		MesProductCheckOne latest = findLatestInShift(oprno, lineSn, shiftRange[0], shiftRange[1]);
+		if (latest == null) {
+			return null;
+		}
+		String result = StringUtils.trim(latest.getResult());
+		if ("OK".equalsIgnoreCase(result)) {
+			return null;
+		}
+		if ("NG".equalsIgnoreCase(result)) {
+			if ("1".equals(latest.getConfirmCheck())) {
+				return null;
+			}
+			return "当前班次首件检NG,请确认后再加工";
+		}
+		return "当前班次首件检未完成";
+	}
+
+	/**
+	 * 工件结果上传后按需生成首件检:
+	 * 本班次本工位已有 OK 不再插入;
+	 * 已有待检记录不再插入;
+	 * NG 未确认不插入;
+	 * 无记录,或 NG 已确认后的下一件,插入一条 UDF。
+	 */
+	@Transactional
+	public void generateIfNeeded(String sn, String oprno, String lineSn, String userCode) {
+		if (!CommonUitl.needCheckOne(oprno, lineSn) || StringUtils.isBlank(sn)) {
+			return;
+		}
+		Date[] shiftRange = getCurrentShiftRange();
+		if (shiftRange == null) {
+			return;
+		}
+		if (hasOkInShift(oprno, lineSn, shiftRange[0], shiftRange[1])) {
+			return;
+		}
+		MesProductCheckOne latest = findLatestInShift(oprno, lineSn, shiftRange[0], shiftRange[1]);
+		if (latest != null) {
+			String result = StringUtils.trim(latest.getResult());
+			if ("NG".equalsIgnoreCase(result)) {
+				if (!"1".equals(latest.getConfirmCheck())) {
+					return;
+				}
+			} else {
+				return;
+			}
+		}
+		MesProductCheckOne record = new MesProductCheckOne();
+		record.setSn(sn.trim());
+		record.setOprno(normalizeCheckOprno(oprno));
+		record.setLineSn(lineSn);
+		record.setResult("UDF");
+		record.setConfirmCheck("0");
+		String operator = StringUtils.defaultIfBlank(userCode, "system");
+		record.setCreateBy(operator);
+		record.setUpdateBy(operator);
+		save(record);
+	}
+
+	public MesProductCheckOne findLatestInShift(String oprno, String lineSn, Date startDate, Date endDate) {
+		List<String> oprnos = buildCheckOneOprnos(oprno);
+		if (ListUtils.isEmpty(oprnos) || startDate == null || endDate == null) {
+			return null;
+		}
+		MesProductCheckOne query = new MesProductCheckOne();
+		if (StringUtils.isNotBlank(lineSn)) {
+			query.setLineSn(lineSn);
+		}
+		query.setCreateDate_gte(startDate);
+		query.setCreateDate_lte(endDate);
+		query.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
+		query.getSqlMap().getOrder().setOrderBy("a.update_date DESC, a.id DESC");
+		List<MesProductCheckOne> list = findList(query);
+		if (ListUtils.isEmpty(list)) {
+			return null;
+		}
+		return list.get(0);
+	}
+
+	private boolean hasOkInShift(String oprno, String lineSn, Date startDate, Date endDate) {
+		List<String> oprnos = buildCheckOneOprnos(oprno);
+		if (ListUtils.isEmpty(oprnos) || startDate == null || endDate == null) {
+			return false;
+		}
+		MesProductCheckOne query = new MesProductCheckOne();
+		query.setResult("OK");
+		if (StringUtils.isNotBlank(lineSn)) {
+			query.setLineSn(lineSn);
+		}
+		query.setCreateDate_gte(startDate);
+		query.setCreateDate_lte(endDate);
+		query.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
+		Long count = findCount(query);
+		return count != null && count > 0;
+	}
+
+	private Date[] getCurrentShiftRange() {
+		MesShiftDataResp shift = mesShiftService.getCurShift();
+		if (shift == null || StringUtils.isBlank(shift.getStart()) || StringUtils.isBlank(shift.getEnd())) {
+			return null;
+		}
+		try {
+			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+			return new Date[]{dateFormat.parse(shift.getStart()), dateFormat.parse(shift.getEnd())};
+		} catch (ParseException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	private List<String> buildCheckOneOprnos(String oprno) {
+		List<String> oprnos = new ArrayList<>();
+		String checkOprno = normalizeCheckOprno(oprno);
+		if (StringUtils.isBlank(checkOprno)) {
+			return oprnos;
+		}
+		String formattedOprno = CommonUitl.formatOprno(checkOprno);
+		oprnos.add(checkOprno);
+		if (!StringUtils.equals(checkOprno, formattedOprno)) {
+			oprnos.add(formattedOprno);
+		}
+		return oprnos;
+	}
+
+	private String normalizeCheckOprno(String oprno) {
+		if (StringUtils.isBlank(oprno)) {
+			return "";
+		}
+		String value = oprno.trim();
+		if (value.length() > 6 && value.startsWith("OP")) {
+			value = value.substring(0, 5);
+		}
+		if (value.length() == 5) {
+			return value + "A";
+		}
+		return value;
+	}
 }

+ 7 - 0
src/main/java/com/jeesite/modules/mes/service/MesProductCmtService.java

@@ -54,6 +54,13 @@ public class MesProductCmtService extends CrudService<MesProductCmtDao, MesProdu
 	public List<MesProductCmt> findList(MesProductCmt mesProductCmt) {
 		return super.findList(mesProductCmt);
 	}
+
+	public List<MesProductCmt> findContentByIds(List<String> ids) {
+		if (ids == null || ids.isEmpty()) {
+			return java.util.Collections.emptyList();
+		}
+		return dao.findContentByIds(ids);
+	}
 	
 	/**
 	 * 保存数据(插入或更新)

+ 14 - 0
src/main/java/com/jeesite/modules/mes/service/MesProductProdService.java

@@ -44,6 +44,20 @@ public class MesProductProdService extends CrudService<MesProductProdDao, MesPro
 	public Page<MesProductProd> findPage(MesProductProd mesProductProd) {
 		return super.findPage(mesProductProd);
 	}
+
+	/**
+	 * 列表聚合:按工件码分组分页。
+	 * 统计总数时需临时去掉 Page,避免分页拦截器给 count SQL 加 LIMIT。
+	 */
+	public Page<MesProductProd> findSnGroupPage(MesProductProd query) {
+		Page<MesProductProd> page = query.getPage();
+		query.setPage(null);
+		long count = dao.findSnGroupCount(query);
+		page.setCount(count);
+		query.setPage(page);
+		page.setList(dao.findSnGroupList(query));
+		return page;
+	}
 	
 	/**
 	 * 查询列表数据

+ 2 - 47
src/main/java/com/jeesite/modules/mes/service/MesProductRecordService.java

@@ -27,9 +27,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
 
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -806,50 +803,6 @@ public class MesProductRecordService extends CrudService<MesProductRecordDao, Me
 					mesProductModifyRecordService.save(mesProductModifyRecord1);
 				}
 
-				//查询首件检记录是否为OK或是确认状态
-				if (CommonUitl.needCheckOne(oldOprno, lineSn)) {
-					MesShiftDataResp mesShiftDataResp = mesShiftService.getCurShift();
-					try {
-						DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-						Date stdate = null;
-						stdate = dateFormat.parse(mesShiftDataResp.getStart());
-						Date etdate = dateFormat.parse(mesShiftDataResp.getEnd());
-						String checkOprno = oprno;
-						if (checkOprno.length() == 5) {
-							checkOprno += "A";
-						}
-						String formattedOprno = CommonUitl.formatOprno(checkOprno);
-						List<String> oprnos = new ArrayList<>();
-						oprnos.add(checkOprno);
-						if (!StringUtils.equals(checkOprno, formattedOprno)) {
-							oprnos.add(formattedOprno);
-						}
-						//查询当前班次的是否有加工记录
-						MesProductRecord mesProductRecord5 = new MesProductRecord();
-						mesProductRecord5.setLineSn(lineSn);
-						mesProductRecord5.setCraft("100000");
-						mesProductRecord5.setUpdateDate_gte(stdate);
-						mesProductRecord5.setUpdateDate_lte(etdate);
-						mesProductRecord5.getSqlMap().getWhere().and("a.content", QueryType.NE,"UDF");
-						mesProductRecord5.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
-						mesProductRecord5.getSqlMap().getOrder().setOrderBy("a.update_date DESC, a.id DESC");
-						List<MesProductRecord> productRecords = this.findList(mesProductRecord);
-						if (ListUtils.isEmpty(productRecords)) {
-							//生成首件检记录
-							MesProductCheckOne mesProductCheckOne1 = new MesProductCheckOne();
-							mesProductCheckOne1.setSn(sn);
-							mesProductCheckOne1.setOprno(checkOprno);
-							mesProductCheckOne1.setLineSn(lineSn);
-							mesProductCheckOne1.setResult("UDF");
-							mesProductCheckOne1.setConfirmCheck("0");
-							mesProductCheckOne1.setCreateBy(userCode);
-							mesProductCheckOne1.setUpdateBy(userCode);
-							mesProductCheckOneService.save(mesProductCheckOne1);
-						}
-					} catch (ParseException e) {
-						throw new RuntimeException(e);
-					}
-				}
 				// 更新主结果
 				if(mesProductRecord.getCraft().equals(craft)){
 					if(oldOprno.length() == 6){
@@ -911,6 +864,8 @@ public class MesProductRecordService extends CrudService<MesProductRecordDao, Me
 			}
 		}
 
+		mesProductCheckOneService.generateIfNeeded(sn, oldOprno, lineSn, userCode);
+
 		// 是否更新工位时间
 		if(optime){
 			String sns = sn;

+ 38 - 1
src/main/java/com/jeesite/modules/mes/service/MesProductService.java

@@ -5,6 +5,8 @@ import com.jeesite.common.lang.StringUtils;
 import com.jeesite.common.service.CrudService;
 import com.jeesite.modules.mes.dao.MesProductDao;
 import com.jeesite.modules.mes.entity.MesProduct;
+import com.jeesite.modules.mes.entity.MesProductCate;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -19,7 +21,8 @@ import java.util.List;
 @Service
 public class MesProductService extends CrudService<MesProductDao, MesProduct> {
 
-
+	@Autowired
+	private MesProductCateService mesProductCateService;
 
 	/**
 	 * 获取单条数据
@@ -98,6 +101,40 @@ public class MesProductService extends CrudService<MesProductDao, MesProduct> {
 		return dao.findInfo(m1);
 	}
 
+	/**
+	 * GP12 扫码:工件已存在则直接返回;不存在则按工件类型编码规则匹配并自动创建。
+	 * 已存在的正常工件不会重复创建。匹配不到编码规则时返回 null。
+	 */
+	@Transactional
+	public MesProduct findOrCreateBySnForGp12(String sn) {
+		if (StringUtils.isBlank(sn)) {
+			return null;
+		}
+		String trimSn = sn.trim();
+		MesProduct existing = findBySn(trimSn);
+		if (existing != null) {
+			return existing;
+		}
+		MesProductCate cate = mesProductCateService.getCateBySn(trimSn);
+		if (cate == null || StringUtils.isBlank(cate.getSn())) {
+			return null;
+		}
+		// 并发下可能已被其他请求创建,再查一次
+		MesProduct again = findBySn(trimSn);
+		if (again != null) {
+			return again;
+		}
+		MesProduct product = new MesProduct();
+		product.setSn(trimSn);
+		product.setCate(cate.getSn());
+		product.setTitle(cate.getTitle());
+		product.setState("0");
+		product.setRemark("GP12扫码自动创建");
+		save(product);
+		MesProduct created = findBySn(trimSn);
+		return created != null ? created : product;
+	}
+
 	public int updateUpdateDateBySn(String sn, Date updateDate,String userCode,String lineSn) {
 		if (StringUtils.isBlank(sn) || updateDate == null||StringUtils.isBlank(userCode)||StringUtils.isBlank(lineSn)) {
 			return 0;

+ 36 - 0
src/main/java/com/jeesite/modules/mes/util/CommonUitl.java

@@ -174,6 +174,42 @@ public class CommonUitl {
     }
 
     /**
+     * 打包绑定批次码时,当前产线是否须先完成 GP12 检查。
+     * 参数 mes.gp12.pack.lines:逗号分隔产线编号,如 HEVXT,115XT
+     */
+    public static boolean requireGp12ForPack(String lineSn) {
+        String config = Global.getConfig("mes.gp12.pack.lines");
+        if (StringUtils.isBlank(config) || StringUtils.isBlank(lineSn)) {
+            return false;
+        }
+        String currentLine = lineSn.trim();
+        for (String item : config.split(",")) {
+            if (StringUtils.isBlank(item)) {
+                continue;
+            }
+            if (matchPackLine(currentLine, item.trim())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean matchPackLine(String currentLine, String configLine) {
+        if (matchLineSn(currentLine, configLine)) {
+            return true;
+        }
+        String upperCurrent = normalizeCheckLineSn(currentLine).toUpperCase();
+        String upperConfig = normalizeCheckLineSn(configLine).toUpperCase();
+        if (upperConfig.contains("HEV") && upperCurrent.contains("HEV")) {
+            return true;
+        }
+        if (upperConfig.contains("115") && upperCurrent.contains("115")) {
+            return true;
+        }
+        return upperCurrent.contains(upperConfig) || upperConfig.contains(upperCurrent);
+    }
+
+    /**
      * 获取几天前的时间
      * @param days
      * @return

+ 18 - 5
src/main/java/com/jeesite/modules/mes/web/MesBatchSnController.java

@@ -14,6 +14,7 @@ import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.modules.mes.entity.MesProduct;
 import com.jeesite.modules.mes.entity.MesProductGp12;
 import com.jeesite.modules.mes.resp.CommonResp;
+import com.jeesite.modules.mes.service.MesProductRecordService;
 import com.jeesite.modules.mes.service.MesProductService;
 import com.jeesite.modules.mes.service.MesProductGp12Service;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -38,6 +39,7 @@ import com.jeesite.common.web.BaseController;
 import com.jeesite.modules.mes.entity.MesBatchSn;
 import com.jeesite.modules.mes.erp.ErpPdaRespHelper;
 import com.jeesite.modules.mes.service.MesBatchSnService;
+import com.jeesite.modules.mes.util.CommonUitl;
 
 /**
  * 批次码记录表Controller
@@ -54,6 +56,8 @@ public class MesBatchSnController extends BaseController {
 	private MesProductService mesProductService;
 	@Autowired
 	private MesProductGp12Service mesProductGp12Service;
+	@Autowired
+	private MesProductRecordService mesProductRecordService;
 	/**
 	 * 获取数据
 	 */
@@ -237,12 +241,21 @@ public class MesBatchSnController extends BaseController {
 		if (StringUtils.isNotBlank(mesProduct1.getBatchSn())) {
 			return renderResult(Global.FALSE, text("该工件已绑定批次码"));
 		}
-		MesProductGp12 latestGp12 = mesProductGp12Service.findLatestBySn(sn);
-		if (ObjectUtils.isEmpty(latestGp12)) {
-			return renderResult(Global.FALSE, text("请先进行GP12检查"));
+		String lineSn = mesProductRecordService.resolveLineSnBySn(sn);
+		if (StringUtils.isBlank(lineSn)) {
+			lineSn = msInfo.getLineSn();
+		}
+		if (StringUtils.isBlank(lineSn) && StringUtils.isNotBlank(mesProduct1.getCate())) {
+			lineSn = mesProduct1.getCate();
 		}
-		if (!"OK".equalsIgnoreCase(StringUtils.trim(latestGp12.getResult()))) {
-			return renderResult(Global.FALSE, text("GP12检查不合格,无法绑定"));
+		if (CommonUitl.requireGp12ForPack(lineSn)) {
+			MesProductGp12 latestGp12 = mesProductGp12Service.findLatestBySn(sn);
+			if (ObjectUtils.isEmpty(latestGp12)) {
+				return renderResult(Global.FALSE, text("请先进行GP12检查"));
+			}
+			if (!"OK".equalsIgnoreCase(StringUtils.trim(latestGp12.getResult()))) {
+				return renderResult(Global.FALSE, text("GP12检查不合格,无法绑定"));
+			}
 		}
 		User curUser = UserUtils.getUser();
 		mesProduct1.setBatchSn(msInfo.getBatchSn());

+ 11 - 1
src/main/java/com/jeesite/modules/mes/web/MesElectricTorqueController.java

@@ -8,8 +8,10 @@ import javax.servlet.http.HttpServletResponse;
 
 import com.jeesite.common.lang.StringUtils;
 import com.jeesite.modules.mes.entity.*;
+import com.jeesite.modules.mes.req.MesSearchDateReq;
 import com.jeesite.modules.mes.resp.BindMaterialResp;
 import com.jeesite.modules.mes.service.*;
+import com.jeesite.modules.mes.util.CommonUitl;
 import com.jeesite.modules.utils.DateLocalUtils;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -68,7 +70,15 @@ public class MesElectricTorqueController extends BaseController {
 	 */
 	@RequestMapping(value = {"list", ""})
 	public String list(MesElectricTorque mesElectricTorque, Model model) {
-
+		if (StringUtils.isBlank(mesElectricTorque.getBatchId())) {
+			MesSearchDateReq dateMap = CommonUitl.getSearchDate();
+			if (mesElectricTorque.getCreateDate_gte() == null) {
+				mesElectricTorque.setCreateDate_gte(dateMap.getStartDate());
+			}
+			if (mesElectricTorque.getCreateDate_lte() == null) {
+				mesElectricTorque.setCreateDate_lte(dateMap.getEndtDate());
+			}
+		}
 		model.addAttribute("mesElectricTorque", mesElectricTorque);
 //		MesElectricTorque mesElectricTorque1 = new MesElectricTorque();
 //		mesElectricTorque.setBatchId(mesElectricTorque.getBatchId());

+ 142 - 0
src/main/java/com/jeesite/modules/mes/web/MesProcessParamLimitController.java

@@ -1,13 +1,22 @@
 package com.jeesite.modules.mes.web;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import com.jeesite.common.config.Global;
+import com.jeesite.common.collect.ListUtils;
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.lang.StringUtils;
 import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesLine;
+import com.jeesite.modules.mes.entity.MesLineProcess;
 import com.jeesite.modules.mes.entity.MesProcessParamLimit;
+import com.jeesite.modules.mes.service.MesLineProcessService;
+import com.jeesite.modules.mes.service.MesLineService;
 import com.jeesite.modules.mes.service.MesProcessParamLimitService;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +40,12 @@ public class MesProcessParamLimitController extends BaseController {
 	@Autowired
 	private MesProcessParamLimitService mesProcessParamLimitService;
 
+	@Autowired
+	private MesLineService mesLineService;
+
+	@Autowired
+	private MesLineProcessService mesLineProcessService;
+
 	@ModelAttribute
 	public MesProcessParamLimit get(String id, boolean isNewRecord) {
 		return mesProcessParamLimitService.get(id, isNewRecord);
@@ -55,15 +70,63 @@ public class MesProcessParamLimitController extends BaseController {
 	@RequiresPermissions("mes:mesProcessParamLimit:view")
 	@RequestMapping(value = "form")
 	public String form(MesProcessParamLimit mesProcessParamLimit, Model model) {
+		MesLine lineQuery = new MesLine();
+		lineQuery.setStatus(MesLine.STATUS_NORMAL);
+		model.addAttribute("lineList", mesLineService.findList(lineQuery));
 		model.addAttribute("mesProcessParamLimit", mesProcessParamLimit);
 		return "modules/mes/mesProcessParamLimitForm";
 	}
 
+	@RequiresPermissions("mes:mesProcessParamLimit:view")
+	@RequestMapping(value = "stationList")
+	@ResponseBody
+	public List<Map<String, String>> stationList(String lineSn) {
+		List<Map<String, String>> result = ListUtils.newArrayList();
+		if (StringUtils.isBlank(lineSn)) {
+			return result;
+		}
+		List<MesLineProcess> processList = mesLineProcessService.findOprnoListByLineSn(lineSn.trim());
+		if (processList == null) {
+			return result;
+		}
+		for (MesLineProcess process : processList) {
+			if (process == null || StringUtils.isBlank(process.getOprno())) {
+				continue;
+			}
+			Map<String, String> item = new HashMap<>();
+			item.put("oprno", process.getOprno());
+			item.put("title", StringUtils.defaultString(process.getTitle()));
+			result.add(item);
+		}
+		return result;
+	}
+
 	@RequiresPermissions("mes:mesProcessParamLimit:edit")
 	@PostMapping(value = "save")
 	@ResponseBody
 	public String save(@Validated MesProcessParamLimit mesProcessParamLimit) {
 		trimFields(mesProcessParamLimit);
+		if (StringUtils.isBlank(mesProcessParamLimit.getLineSn()) || StringUtils.isBlank(mesProcessParamLimit.getOprno())) {
+			return renderResult(Global.FALSE, text("请选择产线编号和工位"));
+		}
+		if (StringUtils.isBlank(mesProcessParamLimit.getProcessName())) {
+			mesProcessParamLimit.setProcessName(findStationTitle(
+					mesProcessParamLimit.getLineSn(), mesProcessParamLimit.getOprno()));
+		}
+		String inferredKey = inferProcessKey(mesProcessParamLimit.getLineSn(),
+				mesProcessParamLimit.getProcessName(), mesProcessParamLimit.getOprno());
+		if (StringUtils.isNotBlank(inferredKey)) {
+			mesProcessParamLimit.setProcessKey(inferredKey);
+		}
+		if (isProdProcessKey(mesProcessParamLimit.getProcessKey())) {
+			String gunType = normalizeGunType(mesProcessParamLimit.getGunType());
+			if (StringUtils.isBlank(gunType)) {
+				return renderResult(Global.FALSE, text("拉铆工位请选择A枪或B枪"));
+			}
+			mesProcessParamLimit.setGunType(gunType);
+		} else {
+			mesProcessParamLimit.setGunType(null);
+		}
 		if (StringUtils.isBlank(mesProcessParamLimit.getStatus())) {
 			mesProcessParamLimit.setStatus(MesProcessParamLimit.STATUS_NORMAL);
 		}
@@ -100,6 +163,9 @@ public class MesProcessParamLimitController extends BaseController {
 	private void trimFields(MesProcessParamLimit mesProcessParamLimit) {
 		mesProcessParamLimit.setProcessKey(StringUtils.trim(mesProcessParamLimit.getProcessKey()));
 		mesProcessParamLimit.setProcessName(StringUtils.trim(mesProcessParamLimit.getProcessName()));
+		mesProcessParamLimit.setLineSn(StringUtils.trim(mesProcessParamLimit.getLineSn()));
+		mesProcessParamLimit.setOprno(StringUtils.trim(mesProcessParamLimit.getOprno()));
+		mesProcessParamLimit.setGunType(StringUtils.trim(mesProcessParamLimit.getGunType()));
 		mesProcessParamLimit.setParamCode(StringUtils.trim(mesProcessParamLimit.getParamCode()));
 		mesProcessParamLimit.setParamName(StringUtils.trim(mesProcessParamLimit.getParamName()));
 		mesProcessParamLimit.setLowerLimit(StringUtils.trim(mesProcessParamLimit.getLowerLimit()));
@@ -107,4 +173,80 @@ public class MesProcessParamLimitController extends BaseController {
 		mesProcessParamLimit.setUnit(StringUtils.trim(mesProcessParamLimit.getUnit()));
 		mesProcessParamLimit.setRemark(StringUtils.trim(mesProcessParamLimit.getRemark()));
 	}
+
+	private String findStationTitle(String lineSn, String oprno) {
+		List<MesLineProcess> processList = mesLineProcessService.findOprnoListByLineSn(lineSn);
+		if (processList == null) {
+			return "";
+		}
+		for (MesLineProcess process : processList) {
+			if (process != null && StringUtils.equals(oprno, process.getOprno())) {
+				return StringUtils.defaultString(process.getTitle());
+			}
+		}
+		return "";
+	}
+
+	private String inferProcessKey(String lineSn, String title, String oprno) {
+		String text = StringUtils.defaultString(title);
+		String line = StringUtils.upperCase(StringUtils.defaultString(lineSn));
+		if (is115ArcStation(line, oprno)) {
+			return "arc115";
+		}
+		if (StringUtils.contains(text, "点焊")) {
+			return StringUtils.contains(line, "115") ? "spot115" : "spotHev";
+		}
+		if (StringUtils.contains(text, "弧焊") || StringUtils.containsIgnoreCase(text, "CMT")) {
+			return StringUtils.contains(line, "115") ? "arc115" : "arcHev";
+		}
+		if (StringUtils.contains(text, "拉铆")) {
+			if (StringUtils.contains(line, "115") && StringUtils.contains(text, "正面")) {
+				return "prod115Front";
+			}
+			if (StringUtils.contains(line, "115")) {
+				return "prod115Back";
+			}
+			return "prodHevBack";
+		}
+		if (StringUtils.contains(text, "气密")) {
+			return StringUtils.contains(text, "白件") ? "whitePart" : "assembly";
+		}
+		if (StringUtils.contains(text, "凸焊")) {
+			return "welder";
+		}
+		return "";
+	}
+
+	private boolean isProdProcessKey(String processKey) {
+		return StringUtils.startsWithIgnoreCase(StringUtils.trim(processKey), "prod");
+	}
+
+	private String normalizeGunType(String value) {
+		String text = StringUtils.upperCase(StringUtils.trim(value));
+		if (StringUtils.isBlank(text)) {
+			return "";
+		}
+		if ("A".equals(text) || "A枪".equals(text) || StringUtils.startsWith(text, "A")) {
+			return "A";
+		}
+		if ("B".equals(text) || "B枪".equals(text) || StringUtils.startsWith(text, "B")) {
+			return "B";
+		}
+		return "";
+	}
+
+	private boolean is115ArcStation(String line, String oprno) {
+		if (!StringUtils.contains(line, "115")) {
+			return false;
+		}
+		String code = StringUtils.upperCase(StringUtils.trim(oprno));
+		if (StringUtils.isBlank(code)) {
+			return false;
+		}
+		int opIndex = code.lastIndexOf("OP");
+		String parent = (opIndex >= 0 && code.length() >= opIndex + 5)
+				? code.substring(opIndex, opIndex + 5)
+				: code;
+		return "OP060".equals(parent) || "OP070".equals(parent) || "OP080".equals(parent);
+	}
 }

+ 208 - 5
src/main/java/com/jeesite/modules/mes/web/MesProductArcWeldingController.java

@@ -1,8 +1,11 @@
 package com.jeesite.modules.mes.web;
 
+import java.math.BigDecimal;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.Date;
@@ -11,7 +14,9 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.modules.mes.entity.MesLineProcess;
+import com.jeesite.modules.mes.entity.MesProductRecord;
 import com.jeesite.modules.mes.req.MesSearchDateReq;
 import com.jeesite.modules.mes.util.CommonUitl;
 
@@ -129,11 +134,14 @@ public class MesProductArcWeldingController extends BaseController {
 	@RequestMapping(value = "listData")
 	@ResponseBody
 	public Page<MesProductArcWelding> listData(MesProductArcWelding mesProductArcWelding, String processName, HttpServletRequest request, HttpServletResponse response) {
+		applyWeldingStationFilter(mesProductArcWelding);
 		mesProductArcWelding.setPage(new Page<>(request, response));
 		Page<MesProductArcWelding> page = mesProductArcWeldingService.findPage(mesProductArcWelding);
 		fillOprnoTitle(page.getList());
 		fillCreateByFromProductRecord(page.getList());
+		fillContentForLimitCheck(page.getList());
 		mesProcessParamLimitCheckService.markArc(page.getList(), mesProductArcWelding.getWeldingCategory(), processName);
+		clearContent(page.getList());
 		return page;
 	}
 
@@ -141,23 +149,174 @@ public class MesProductArcWeldingController extends BaseController {
 		if (ListUtils.isEmpty(list)) {
 			return;
 		}
-		Map<String, String> updateByMap = new HashMap<>();
+		List<MesProductArcWelding> keys = new java.util.ArrayList<>();
+		Set<String> seen = new HashSet<>();
 		for (MesProductArcWelding record : list) {
 			if (StringUtils.isBlank(record.getSn()) || StringUtils.isBlank(record.getOprno())
 					|| StringUtils.isBlank(record.getLineSn())) {
 				continue;
 			}
 			String key = record.getSn() + "|" + record.getOprno() + "|" + record.getLineSn();
-			if (!updateByMap.containsKey(key)) {
-				updateByMap.put(key, mesProductArcWeldingService.findProductRecordUpdateBy(record));
+			if (seen.add(key)) {
+				keys.add(record);
+			}
+		}
+		if (keys.isEmpty()) {
+			return;
+		}
+		Map<String, String> updateByMap = new HashMap<>();
+		List<MesProductRecord> records = mesProductArcWeldingService.findProductRecordUpdateByList(keys);
+		if (records != null) {
+			for (MesProductRecord row : records) {
+				if (row == null || StringUtils.isBlank(row.getSn()) || StringUtils.isBlank(row.getOprno())) {
+					continue;
+				}
+				String updateBy = row.getUpdateBy();
+				int priority = isPreferredUpdateBy(updateBy) ? 0 : 1;
+				putPreferredUpdateBy(updateByMap, row.getSn(), row.getOprno(), row.getLineSn(), updateBy, priority, row.getUpdateDate(), row.getCreateDate());
+				putPreferredUpdateBy(updateByMap, row.getSn(), row.getOprno(), row.getCateSn(), updateBy, priority, row.getUpdateDate(), row.getCreateDate());
+			}
+		}
+		for (MesProductArcWelding record : list) {
+			if (StringUtils.isBlank(record.getSn()) || StringUtils.isBlank(record.getOprno())
+					|| StringUtils.isBlank(record.getLineSn())) {
+				continue;
 			}
-			String updateBy = updateByMap.get(key);
+			String updateBy = updateByMap.get(record.getSn() + "|" + record.getOprno() + "|" + record.getLineSn());
 			if (StringUtils.isNotBlank(updateBy)) {
 				record.setCreateBy(updateBy);
 			}
 		}
 	}
 
+	private void putPreferredUpdateBy(Map<String, String> updateByMap, String sn, String oprno, String lineSn,
+			String updateBy, int priority, java.util.Date updateDate, java.util.Date createDate) {
+		if (StringUtils.isBlank(sn) || StringUtils.isBlank(oprno) || StringUtils.isBlank(lineSn)) {
+			return;
+		}
+		String key = sn + "|" + oprno + "|" + lineSn;
+		String exist = updateByMap.get(key);
+		if (exist == null) {
+			updateByMap.put(key, updateBy);
+			updateByMap.put(key + "|p", String.valueOf(priority));
+			updateByMap.put(key + "|t", String.valueOf(dateSortValue(updateDate, createDate)));
+			return;
+		}
+		int existPriority = parseIntQuietly(updateByMap.get(key + "|p"), 1);
+		if (priority > existPriority) {
+			return;
+		}
+		long existTime = parseLongQuietly(updateByMap.get(key + "|t"), 0L);
+		long currentTime = dateSortValue(updateDate, createDate);
+		if (priority < existPriority || currentTime >= existTime) {
+			updateByMap.put(key, updateBy);
+			updateByMap.put(key + "|p", String.valueOf(priority));
+			updateByMap.put(key + "|t", String.valueOf(currentTime));
+		}
+	}
+
+	private boolean isPreferredUpdateBy(String updateBy) {
+		return StringUtils.isNotBlank(updateBy) && !"system".equals(updateBy);
+	}
+
+	private long dateSortValue(java.util.Date updateDate, java.util.Date createDate) {
+		if (updateDate != null) {
+			return updateDate.getTime();
+		}
+		return createDate == null ? 0L : createDate.getTime();
+	}
+
+	private int parseIntQuietly(String value, int defaultValue) {
+		if (StringUtils.isBlank(value)) {
+			return defaultValue;
+		}
+		try {
+			return Integer.parseInt(value);
+		} catch (Exception ex) {
+			return defaultValue;
+		}
+	}
+
+	private long parseLongQuietly(String value, long defaultValue) {
+		if (StringUtils.isBlank(value)) {
+			return defaultValue;
+		}
+		try {
+			return Long.parseLong(value);
+		} catch (Exception ex) {
+			return defaultValue;
+		}
+	}
+
+	private void fillContentForLimitCheck(List<MesProductArcWelding> list) {
+		if (ListUtils.isEmpty(list)) {
+			return;
+		}
+		List<MesProductArcWelding> contents = mesProductArcWeldingService.findContentByKeys(list);
+		if (ListUtils.isEmpty(contents)) {
+			return;
+		}
+		Map<String, String> contentMap = new HashMap<>();
+		Map<String, String> contentById = new HashMap<>();
+		for (MesProductArcWelding row : contents) {
+			if (row != null) {
+				contentMap.put(rowKey(row), row.getContent());
+				if (StringUtils.isNotBlank(row.getId())) {
+					contentById.put(row.getId(), row.getContent());
+				}
+			}
+		}
+		for (MesProductArcWelding row : list) {
+			String content = contentMap.get(rowKey(row));
+			if (content == null && row != null) {
+				content = contentById.get(row.getId());
+			}
+			if (content != null) {
+				row.setContent(content);
+			}
+		}
+	}
+
+	private void clearContent(List<MesProductArcWelding> list) {
+		if (ListUtils.isEmpty(list)) {
+			return;
+		}
+		for (MesProductArcWelding row : list) {
+			if (row != null) {
+				row.setContent(null);
+			}
+		}
+	}
+
+	private String rowKey(MesProductArcWelding row) {
+		if (row == null) {
+			return "";
+		}
+		long ts = row.getCreateDate() == null ? 0L : row.getCreateDate().getTime();
+		return StringUtils.defaultString(row.getId()) + "|" + ts;
+	}
+
+	private void applyWeldingStationFilter(MesProductArcWelding mesProductArcWelding) {
+		if (mesProductArcWelding == null) {
+			return;
+		}
+		String keyword = null;
+		if ("spot".equals(mesProductArcWelding.getWeldingCategory())) {
+			keyword = "点焊";
+		} else if ("arc".equals(mesProductArcWelding.getWeldingCategory())) {
+			keyword = "弧焊";
+		}
+		if (keyword == null) {
+			return;
+		}
+		List<String> oprnos = mesLineProcessService.findOprnosByTitleLike(keyword);
+		if (ListUtils.isEmpty(oprnos)) {
+			mesProductArcWelding.getSqlMap().getWhere().and("a.id", QueryType.EQ, "__no_station__");
+			return;
+		}
+		mesProductArcWelding.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
+	}
+
 	private void fillOprnoTitle(List<MesProductArcWelding> list) {
 		if (ListUtils.isEmpty(list)) {
 			return;
@@ -223,6 +382,7 @@ public class MesProductArcWeldingController extends BaseController {
 	@RequiresPermissions("mes:mesProductArcWelding:view")
 	@RequestMapping(value = "exportData")
 	public void exportData(MesProductArcWelding mesProductArcWelding, HttpServletResponse response) {
+		applyWeldingStationFilter(mesProductArcWelding);
 		List<MesProductArcWelding> list = mesProductArcWeldingService.findList(mesProductArcWelding);
 		fillOprnoTitle(list);
 		fillCreateByFromProductRecord(list);
@@ -317,7 +477,7 @@ public class MesProductArcWeldingController extends BaseController {
 			mesProductArcWelding.setSn(obj.getString("sn"));
 			mesProductArcWelding.setOprno(obj.getString("oprno"));
 			mesProductArcWelding.setLineSn(obj.getString("lineSn"));
-			mesProductArcWelding.setContent(obj.getString("content"));
+			mesProductArcWelding.setContent(scaleSpotCurrent(obj.getString("content")));
 			mesProductArcWeldingService.save(mesProductArcWelding);
 		}
 
@@ -361,6 +521,49 @@ public class MesProductArcWeldingController extends BaseController {
 		return "";
 	}
 
+	/** 点焊电流入库时小数点右移一位(乘以 10),例如 0.81 -> 8.1 */
+	private String scaleSpotCurrent(String content) {
+		if (StringUtils.isBlank(content)) {
+			return content;
+		}
+		String text = content.trim();
+		if (!text.startsWith("{")) {
+			return content;
+		}
+		try {
+			JSONObject json = JSON.parseObject(text);
+			if (json == null || !"spot".equals(json.getString("weldingType"))) {
+				return content;
+			}
+			JSONArray samples = json.getJSONArray("samples");
+			if (samples == null || samples.isEmpty()) {
+				return content;
+			}
+			for (int i = 0; i < samples.size(); i++) {
+				JSONObject sample = samples.getJSONObject(i);
+				if (sample == null) {
+					continue;
+				}
+				multiplyByTen(sample, "robot1Current");
+				multiplyByTen(sample, "robot2Current");
+			}
+			return json.toJSONString();
+		} catch (Exception e) {
+			return content;
+		}
+	}
+
+	private void multiplyByTen(JSONObject sample, String key) {
+		if (sample.get(key) == null) {
+			return;
+		}
+		try {
+			BigDecimal value = new BigDecimal(sample.getString(key));
+			sample.put(key, value.multiply(BigDecimal.TEN));
+		} catch (Exception ignored) {
+		}
+	}
+
 	private String defaultWeldingProcessName(String weldingCategory, String processName) {
 		String text = StringUtils.trim(processName);
 		if (StringUtils.isNotBlank(text)) {

+ 25 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductCheckOneController.java

@@ -19,6 +19,7 @@ import com.jeesite.common.config.Global;
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.lang.DateUtils;
 import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.common.utils.excel.ExcelExport;
 import com.jeesite.common.web.BaseController;
 import com.jeesite.modules.mes.entity.MesProductCheckOne;
@@ -52,6 +53,7 @@ public class MesProductCheckOneController extends BaseController {
 	@ResponseBody
 	public Page<MesProductCheckOne> listData(MesProductCheckOne mesProductCheckOne, HttpServletRequest request, HttpServletResponse response) {
 		mesProductCheckOne.setStatus(null);
+		applyConfirmCheckQuery(mesProductCheckOne);
 		mesProductCheckOne.setPage(new Page<>(request, response));
 		return mesProductCheckOneService.findPage(mesProductCheckOne);
 	}
@@ -113,6 +115,13 @@ public class MesProductCheckOneController extends BaseController {
 		if (StringUtils.isBlank(mesProductCheckOne.getId()) || mesProductCheckOne.getIsNewRecord()) {
 			return renderResult(Global.FALSE, text("记录不存在"));
 		}
+		MesProductCheckOne dbRecord = mesProductCheckOneService.get(mesProductCheckOne.getId());
+		if (dbRecord == null) {
+			return renderResult(Global.FALSE, text("记录不存在"));
+		}
+		if (!"NG".equals(dbRecord.getResult())) {
+			return renderResult(Global.FALSE, text("仅NG记录需要确认检查"));
+		}
 		mesProductCheckOne.setConfirmCheck("1");
 		mesProductCheckOneService.update(mesProductCheckOne);
 		return renderResult(Global.TRUE, text("确认检查成功!"));
@@ -122,10 +131,26 @@ public class MesProductCheckOneController extends BaseController {
 	@RequestMapping(value = "exportData")
 	public void exportData(MesProductCheckOne mesProductCheckOne, HttpServletResponse response) {
 		mesProductCheckOne.setStatus(null);
+		applyConfirmCheckQuery(mesProductCheckOne);
 		List<MesProductCheckOne> list = mesProductCheckOneService.findList(mesProductCheckOne);
 		String fileName = "首件检记录" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
 		try (ExcelExport ee = new ExcelExport("首件检记录", MesProductCheckOne.class)) {
 			ee.setDataList(list).write(response, fileName);
 		}
 	}
+
+	/**
+	 * OK结果视为无需确认;已确认/未确认仅针对NG记录。
+	 */
+	private void applyConfirmCheckQuery(MesProductCheckOne mesProductCheckOne) {
+		String confirmCheck = StringUtils.trim(mesProductCheckOne.getConfirmCheck());
+		if ("N".equalsIgnoreCase(confirmCheck)) {
+			mesProductCheckOne.setConfirmCheck(null);
+			mesProductCheckOne.getSqlMap().getWhere().and("a.result", QueryType.EQ, "OK");
+			return;
+		}
+		if ("0".equals(confirmCheck) || "1".equals(confirmCheck)) {
+			mesProductCheckOne.getSqlMap().getWhere().and("a.result", QueryType.EQ, "NG");
+		}
+	}
 }

+ 46 - 1
src/main/java/com/jeesite/modules/mes/web/MesProductCmtController.java

@@ -86,7 +86,9 @@ public class MesProductCmtController extends BaseController {
 		mesProductCmt.setPage(new Page<>(request, response));
 		Page<MesProductCmt> page = mesProductCmtService.findPage(mesProductCmt);
 		fillOprnoTitle(page.getList());
+		fillContentForLimitCheck(page.getList());
 		mesProcessParamLimitCheckService.markCmt(page.getList());
+		clearContent(page.getList());
 		return page;
 	}
 
@@ -114,6 +116,47 @@ public class MesProductCmtController extends BaseController {
 		}
 	}
 
+	private void fillContentForLimitCheck(List<MesProductCmt> list) {
+		if (ListUtils.isEmpty(list)) {
+			return;
+		}
+		List<String> ids = new java.util.ArrayList<>();
+		for (MesProductCmt row : list) {
+			if (row != null && StringUtils.isNotBlank(row.getId())) {
+				ids.add(row.getId());
+			}
+		}
+		if (ids.isEmpty()) {
+			return;
+		}
+		List<MesProductCmt> contents = mesProductCmtService.findContentByIds(ids);
+		if (ListUtils.isEmpty(contents)) {
+			return;
+		}
+		Map<String, String> contentMap = new HashMap<>();
+		for (MesProductCmt row : contents) {
+			if (row != null && StringUtils.isNotBlank(row.getId())) {
+				contentMap.put(row.getId(), row.getContent());
+			}
+		}
+		for (MesProductCmt row : list) {
+			if (row != null) {
+				row.setContent(contentMap.get(row.getId()));
+			}
+		}
+	}
+
+	private void clearContent(List<MesProductCmt> list) {
+		if (ListUtils.isEmpty(list)) {
+			return;
+		}
+		for (MesProductCmt row : list) {
+			if (row != null) {
+				row.setContent(null);
+			}
+		}
+	}
+
 	private String findOprnoTitle(String lineSn, String oprno) {
 		MesLineProcess mesLineProcess = new MesLineProcess();
 		mesLineProcess.setLineSn(lineSn);
@@ -234,7 +277,9 @@ public class MesProductCmtController extends BaseController {
 	@GetMapping("info")
 	public String info(MesProductCmt mesProductCmt, Model model) {
 		applyLimitFlag(mesProductCmt);
-		model.addAttribute("arcLimitRules", mesProcessParamLimitCheckService.findCmtLimitRules());
+		model.addAttribute("arcLimitRules", mesProcessParamLimitCheckService.findCmtLimitRules(
+				mesProductCmt == null ? null : mesProductCmt.getLineSn(),
+				mesProductCmt == null ? null : mesProductCmt.getOprno()));
 		model.addAttribute("mesProductCmt", mesProductCmt);
 		return "modules/mes/mesProductCmtInfo";
 	}

+ 3 - 3
src/main/java/com/jeesite/modules/mes/web/MesProductController.java

@@ -1748,8 +1748,8 @@ public class MesProductController extends BaseController {
 	public CommonResp indexTj( HttpServletRequest req) {
 		CommonResp<Map<String, Object>> resp = new CommonResp<>();
 		Map<String, Object> map = MapUtils.newHashMap();
-		EmpUser empUser = new EmpUser();
-		List<EmpUser> userList = empUserService.findUserList(empUser);
+		// 与用户管理列表同口径:内连接员工表,默认排除已删除账号(含停用)
+		Long userNum = empUserService.findCount(new EmpUser());
 
 		MesProduct mesProduct1 = new MesProduct();
 //		mesProduct1.setState("1");
@@ -1769,7 +1769,7 @@ public class MesProductController extends BaseController {
 		map.put("productCount", productCount);
 //		map.put("productCountXt", productCountXt);
 //		map.put("productCountLb", productCountLb);
-		map.put("userNum", userList.size());
+		map.put("userNum", userNum);
 		map.put("lineNum", lineNum);
 		map.put("deviceNum", deviceNum);
 		resp.setData(map);

+ 9 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductFswController.java

@@ -8,6 +8,8 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.jeesite.common.lang.StringUtils;
+import com.jeesite.modules.mes.req.MesSearchDateReq;
+import com.jeesite.modules.mes.util.CommonUitl;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -51,6 +53,13 @@ public class MesProductFswController extends BaseController {
 	@RequiresPermissions("mes:mesProductFsw:view")
 	@RequestMapping(value = {"list", ""})
 	public String list(MesProductFsw mesProductFsw, Model model) {
+		MesSearchDateReq dateMap = CommonUitl.getSearchDate();
+		if (mesProductFsw.getCreateDate_gte() == null) {
+			mesProductFsw.setCreateDate_gte(dateMap.getStartDate());
+		}
+		if (mesProductFsw.getCreateDate_lte() == null) {
+			mesProductFsw.setCreateDate_lte(dateMap.getEndtDate());
+		}
 		model.addAttribute("mesProductFsw", mesProductFsw);
 		return "modules/mes/mesProductFswList";
 	}

+ 8 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductGlueDurationController.java

@@ -11,6 +11,7 @@ import com.jeesite.modules.mes.entity.MesProductGlueDuration;
 import com.jeesite.modules.mes.service.MesLineProcessService;
 import com.jeesite.modules.mes.service.MesLogService;
 import com.jeesite.modules.mes.service.MesProductGlueDurationService;
+import com.jeesite.modules.mes.req.MesSearchDateReq;
 import com.jeesite.modules.mes.util.CommonUitl;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -56,6 +57,13 @@ public class MesProductGlueDurationController extends BaseController {
 	@RequiresPermissions("mes:mesProductGlueDuration:view")
 	@RequestMapping(value = {"list", ""})
 	public String list(MesProductGlueDuration mesProductGlueDuration, Model model) {
+		MesSearchDateReq dateMap = CommonUitl.getSearchDate();
+		if (mesProductGlueDuration.getCreateDate_gte() == null) {
+			mesProductGlueDuration.setCreateDate_gte(dateMap.getStartDate());
+		}
+		if (mesProductGlueDuration.getCreateDate_lte() == null) {
+			mesProductGlueDuration.setCreateDate_lte(dateMap.getEndtDate());
+		}
 		model.addAttribute("mesProductGlueDuration", mesProductGlueDuration);
 		return "modules/mes/mesProductGlueDurationList";
 	}

+ 2 - 12
src/main/java/com/jeesite/modules/mes/web/MesProductGp12CheckController.java

@@ -155,18 +155,8 @@ public class MesProductGp12CheckController extends BaseController {
 		MesProductCate query = new MesProductCate();
 		query.setStatus(MesProductCate.STATUS_NORMAL);
 		List<MesProductCate> list = mesProductCateService.findList(query);
-		if (list == null) {
-			return new ArrayList<>();
-		}
-		// 仅展示 HEV 系列工件类型(新增 GP12 检查项时只能选择 HEV 产品)
-		List<MesProductCate> result = new ArrayList<>();
-		for (MesProductCate cate : list) {
-			if (cate != null && StringUtils.isNotBlank(cate.getSn())
-					&& cate.getSn().trim().toUpperCase().startsWith("HEV")) {
-				result.add(cate);
-			}
-		}
-		return result;
+		// 其他产线也可配置 GP12 检查项,展示全部启用中的工件类型
+		return list == null ? new ArrayList<>() : list;
 	}
 
 	private void fillCateTitle(MesProductGp12Check item) {

+ 3 - 2
src/main/java/com/jeesite/modules/mes/web/MesProductGp12Controller.java

@@ -294,10 +294,11 @@ public class MesProductGp12Controller extends BaseController {
 		try {
 			MesProduct mesProduct = null;
 			if (StringUtils.isNotBlank(sn)) {
-				mesProduct = mesProductService.findBySn(sn);
+				// 已有工件直接用;无则按编码规则自动创建,再走检查项
+				mesProduct = mesProductService.findOrCreateBySnForGp12(sn);
 				if (mesProduct == null) {
 					resp.setResult(Global.FALSE);
-					resp.setMessage("工件码不存在");
+					resp.setMessage("工件码不存在,且未匹配到编码规则");
 					return resp;
 				}
 			}

+ 72 - 3
src/main/java/com/jeesite/modules/mes/web/MesProductProdController.java

@@ -1,6 +1,9 @@
 package com.jeesite.modules.mes.web;
 
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -8,7 +11,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.jeesite.common.lang.StringUtils;
-import com.jeesite.modules.mes.entity.MesProductFsw;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
 import com.jeesite.modules.mes.req.MesSearchDateReq;
 import com.jeesite.modules.mes.util.CommonUitl;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -77,8 +80,38 @@ public class MesProductProdController extends BaseController {
 	@RequestMapping(value = "listData")
 	@ResponseBody
 	public Page<MesProductProd> listData(MesProductProd mesProductProd, HttpServletRequest request, HttpServletResponse response) {
-		mesProductProd.setPage(new Page<>(request, response));
-		Page<MesProductProd> page = mesProductProdService.findPage(mesProductProd);
+		Page<MesProductProd> page = new Page<>(request, response);
+		mesProductProd.setPage(page);
+		mesProductProd.getSqlMap().getOrder().setOrderBy("");
+		page = mesProductProdService.findSnGroupPage(mesProductProd);
+		markGroupLimit(page.getList(), mesProductProd);
+		return page;
+	}
+
+	/**
+	 * 工件拉铆记录详情页
+	 */
+	@RequiresPermissions("mes:mesProductProd:view")
+	@RequestMapping(value = "info")
+	public String info(MesProductProd mesProductProd, Model model) {
+		model.addAttribute("mesProductProd", mesProductProd);
+		return "modules/mes/mesProductProdInfo";
+	}
+
+	/**
+	 * 指定工件的拉铆记录明细
+	 */
+	@RequiresPermissions("mes:mesProductProd:view")
+	@RequestMapping(value = "listDetailData")
+	@ResponseBody
+	public Page<MesProductProd> listDetailData(MesProductProd mesProductProd, HttpServletRequest request, HttpServletResponse response) {
+		Page<MesProductProd> page = new Page<>(request, response);
+		if (StringUtils.isBlank(mesProductProd.getSn())) {
+			page.setList(ListUtils.newArrayList());
+			return page;
+		}
+		mesProductProd.setPage(page);
+		page = mesProductProdService.findPage(mesProductProd);
 		mesProcessParamLimitCheckService.markProd(page.getList());
 		return page;
 	}
@@ -193,4 +226,40 @@ public class MesProductProdController extends BaseController {
 		return renderResult(Global.TRUE, text("操作成功!"));
 	}
 
+	private void markGroupLimit(List<MesProductProd> groups, MesProductProd query) {
+		if (ListUtils.isEmpty(groups)) {
+			return;
+		}
+		List<String> sns = new ArrayList<>();
+		for (MesProductProd row : groups) {
+			if (row != null && StringUtils.isNotBlank(row.getSn())) {
+				sns.add(row.getSn());
+			}
+		}
+		if (sns.isEmpty()) {
+			return;
+		}
+		MesProductProd detailQuery = new MesProductProd();
+		detailQuery.setType(query.getType());
+		detailQuery.setOprno(query.getOprno());
+		detailQuery.setLineSn(query.getLineSn());
+		detailQuery.setCreateBy(query.getCreateBy());
+		detailQuery.setDateTime_gte(query.getDateTime_gte());
+		detailQuery.setDateTime_lte(query.getDateTime_lte());
+		detailQuery.getSqlMap().getWhere().and("sn", QueryType.IN, sns);
+		List<MesProductProd> details = mesProductProdService.findList(detailQuery);
+		mesProcessParamLimitCheckService.markProd(details);
+		Set<String> exceedSns = new HashSet<>();
+		if (!ListUtils.isEmpty(details)) {
+			for (MesProductProd detail : details) {
+				if (detail != null && "1".equals(detail.getLimitFlag())) {
+					exceedSns.add(detail.getSn());
+				}
+			}
+		}
+		for (MesProductProd row : groups) {
+			row.setLimitFlag(exceedSns.contains(row.getSn()) ? "1" : "0");
+		}
+	}
+
 }

+ 12 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductQmController.java

@@ -76,6 +76,7 @@ public class MesProductQmController extends BaseController {
 	@RequestMapping(value = "listWhitePart")
 	public String listWhitePart(MesProductQm mesProductQm, Model model) {
 		mesProductQm.setQmCategory("whitePart");
+		applyDefaultTestTime(mesProductQm);
 		model.addAttribute("mesProductQm", mesProductQm);
 		return "modules/mes/mesProductQmWhiteList";
 	}
@@ -87,6 +88,7 @@ public class MesProductQmController extends BaseController {
 	@RequestMapping(value = "listAssembly")
 	public String listAssembly(MesProductQm mesProductQm, Model model) {
 		mesProductQm.setQmCategory("assembly");
+		applyDefaultTestTime(mesProductQm);
 		model.addAttribute("mesProductQm", mesProductQm);
 		return "modules/mes/mesProductQmList";
 	}
@@ -112,6 +114,16 @@ public class MesProductQmController extends BaseController {
 		return page;
 	}
 
+	private void applyDefaultTestTime(MesProductQm mesProductQm) {
+		MesSearchDateReq dateMap = CommonUitl.getSearchDate();
+		if (mesProductQm.getTestTime_gte() == null) {
+			mesProductQm.setTestTime_gte(dateMap.getStartDate());
+		}
+		if (mesProductQm.getTestTime_lte() == null) {
+			mesProductQm.setTestTime_lte(dateMap.getEndtDate());
+		}
+	}
+
 	/**
 	 * 查看编辑表单
 	 */

+ 17 - 144
src/main/java/com/jeesite/modules/mes/web/MesProductRecordController.java

@@ -1571,51 +1571,10 @@ public class MesProductRecordController extends BaseController {
 					}
 				}
 			}
-			//查询首件检记录是否为OK或是确认状态
-			if (CommonUitl.needCheckOne(oldOprno, lineSn)) {
-				MesShiftDataResp mesShiftDataResp = mesShiftService.getCurShift();
-				try {
-					DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-					Date stdate = null;
-					stdate = dateFormat.parse(mesShiftDataResp.getStart());
-					Date etdate = dateFormat.parse(mesShiftDataResp.getEnd());
-					String checkOprno = oprno;
-					if (checkOprno.length() == 5) {
-						checkOprno += "A";
-					}
-					String formattedOprno = CommonUitl.formatOprno(checkOprno);
-					List<String> oprnos = new ArrayList<>();
-					oprnos.add(checkOprno);
-					if (!StringUtils.equals(checkOprno, formattedOprno)) {
-						oprnos.add(formattedOprno);
-					}
-					//查询当前班次的是否有加工记录
-					MesProductRecord mesProductRecord5 = new MesProductRecord();
-					mesProductRecord5.setLineSn(lineSn);
-					mesProductRecord5.setCraft("100000");
-					mesProductRecord5.setUpdateDate_gte(stdate);
-					mesProductRecord5.setUpdateDate_lte(etdate);
-					mesProductRecord5.getSqlMap().getWhere().and("a.content", QueryType.NE,"UDF");
-					mesProductRecord5.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
-					mesProductRecord5.getSqlMap().getOrder().setOrderBy("a.update_date DESC, a.id DESC");
-					List<MesProductRecord> productRecords = mesProductRecordService.findList(mesProductRecord);
-					if (ListUtils.isEmpty(productRecords)) {
-						//生成首件检记录
-						MesProductCheckOne mesProductCheckOne1 = new MesProductCheckOne();
-						mesProductCheckOne1.setSn(sn);
-						mesProductCheckOne1.setOprno(checkOprno);
-						mesProductCheckOne1.setLineSn(lineSn);
-						mesProductCheckOne1.setResult("UDF");
-						mesProductCheckOne1.setConfirmCheck("0");
-						mesProductCheckOne1.setCreateBy("system");
-						mesProductCheckOne1.setUpdateBy("system");
-						mesProductCheckOneService.save(mesProductCheckOne1);
-					}
-				} catch (ParseException e) {
-					throw new RuntimeException(e);
-				}
-			}
 			ret = mesProductRecordService.add(mesProductRecord,params,bmlists);
+			if ("RSOK".equals(ret)) {
+				mesProductCheckOneService.generateIfNeeded(sn, oldOprno, lineSn, user);
+			}
 		}catch (Exception e){
 			e.printStackTrace();
 			ret = "RSNS";
@@ -4594,10 +4553,11 @@ public class MesProductRecordController extends BaseController {
 			return resp;
 		}
 
-		//查询首件检记录是否为OK或是确认状态
 		if (CommonUitl.needCheckOne(oprno, lineSn)){
-			boolean checkOne=checkOne(sn,oprno,lineSn,userCode,resp);
-			if (checkOne==false){
+			String checkOneMsg = mesProductCheckOneService.getProcessBlockMessage(oprno, lineSn);
+			if (checkOneMsg != null) {
+				resp.setResult(Global.FALSE);
+				resp.setMessage(checkOneMsg);
 				return resp;
 			}
 		}
@@ -4656,99 +4616,6 @@ public class MesProductRecordController extends BaseController {
 
 	}
 
-	private boolean checkOne(String sn, String oprno, String lineSn, String userCode,CommonResp<String> resp) {
-		//查询当前班次
-		MesShiftDataResp mesShiftDataResp = mesShiftService.getCurShift();
-		if(com.jeesite.common.lang.ObjectUtils.isEmpty(mesShiftDataResp)){
-			resp.setMessage("未查询到班次");
-			resp.setResult(Global.FALSE);
-			return false; // 没有设置班次,返回false
-		}
-		try {
-			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-			Date stdate = dateFormat.parse(mesShiftDataResp.getStart());
-			Date etdate = dateFormat.parse(mesShiftDataResp.getEnd());
-			String checkOprno = oprno;
-			if(checkOprno.length() == 5){
-				checkOprno += "A";
-			}
-			String formattedOprno = CommonUitl.formatOprno(checkOprno);
-			List<String> oprnos = new ArrayList<>();
-			oprnos.add(checkOprno);
-			if(!StringUtils.equals(checkOprno, formattedOprno)){
-				oprnos.add(formattedOprno);
-			}
-
-			//查询当前班次的是否有加工记录
-			MesProductRecord mesProductRecord = new MesProductRecord();
-			mesProductRecord.setLineSn(lineSn);
-			mesProductRecord.setCraft("100000");
-			mesProductRecord.setUpdateDate_gte(stdate);
-			mesProductRecord.setUpdateDate_lte(etdate);
-			mesProductRecord.getSqlMap().getWhere().and("a.content", QueryType.NE,"UDF");
-			mesProductRecord.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
-			mesProductRecord.getSqlMap().getOrder().setOrderBy("a.update_date DESC, a.id DESC");
-			List<MesProductRecord> productRecords = mesProductRecordService.findList(mesProductRecord);
-		/*	if(ListUtils.isEmpty(productRecords)){
-			*//*	//生成首件检记录
-				MesProductCheckOne mesProductCheckOne1 = new MesProductCheckOne();
-				mesProductCheckOne1.setSn(sn);
-				mesProductCheckOne1.setOprno(checkOprno);
-				mesProductCheckOne1.setLineSn(lineSn);
-				mesProductCheckOne1.setResult("NG");
-				mesProductCheckOne1.setConfirmCheck("0");
-				mesProductCheckOne1.setCreateBy(userCode);
-				mesProductCheckOne1.setUpdateBy(userCode);
-				mesProductCheckOneService.save(mesProductCheckOne1);*//*
-				return true;
-			}*/
-			if(ListUtils.isEmpty(productRecords)){
-				return true;
-			}
-
-			//有,判断首件检记录
-			MesProductCheckOne mesProductCheckOne = new MesProductCheckOne();
-			mesProductCheckOne.setLineSn(lineSn);
-			mesProductCheckOne.setCreateDate_gte(stdate);
-			mesProductCheckOne.setCreateDate_lte(etdate);
-			mesProductCheckOne.getSqlMap().getWhere().and("a.oprno", QueryType.IN, oprnos);
-			mesProductCheckOne.getSqlMap().getOrder().setOrderBy("a.update_date DESC, a.id DESC");
-			List<MesProductCheckOne> firstCheckRecords = mesProductCheckOneService.findList(mesProductCheckOne);
-			if(ListUtils.isEmpty(firstCheckRecords)){
-				resp.setResult(Global.FALSE);
-				resp.setMessage("当前班次首件检查未完成");
-				return false;
-			}
-
-			//NG,查看最新生产记录与最新首件检记录是否相同
-			MesProductCheckOne lastFirstCheck = firstCheckRecords.get(0);
-
-			//相同,确认检查
-			MesProductRecord lastProductRecord = productRecords.get(0);
-			//OK直接走
-			if("OK".equals(lastFirstCheck.getResult())){
-				return true;
-			}
-			//NG,查看最新生产记录与最新首件检记录是否相同
-			if(!StringUtils.equals(lastFirstCheck.getSn(), lastProductRecord.getSn())){
-				resp.setMessage("确认最新首件检状态");
-				resp.setResult(Global.FALSE);
-				return false;
-			}
-
-			if("1".equals(lastFirstCheck.getConfirmCheck())){
-				return true;
-			}
-
-			resp.setResult(Global.FALSE);
-			resp.setMessage("当前班次首件检未完成");
-			return false;
-
-		} catch (ParseException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
 	// 客户端上传结果接口
 	@PostMapping(value = "pcresult")
 	@ResponseBody
@@ -5636,16 +5503,22 @@ public class MesProductRecordController extends BaseController {
 				resp.setMessage("工件码为空");
 				return resp;
 			}
-			MesProduct mesProduct = mesProductService.findBySn(sn);
+			// 已有工件直接用;无则按编码规则自动创建(仅 GP12 扫码入口)
+			MesProduct mesProduct = mesProductService.findOrCreateBySnForGp12(sn);
 			if (mesProduct == null) {
 				resp.setResult(Global.FALSE);
-				resp.setMessage("工件码不存在");
+				resp.setMessage("工件码不存在,且未匹配到编码规则");
 				return resp;
 			}
+			String cateSn = mesProduct.getCate();
 			Map<String, Object> data = MapUtils.newHashMap();
 			data.put("sn", sn);
-			data.put("cate", mesProduct.getCate().substring(0, mesProduct.getCate().length() - 2));
-			data.put("cateSn", mesProduct.getCate());
+			if (StringUtils.isNotBlank(cateSn) && cateSn.length() > 2) {
+				data.put("cate", cateSn.substring(0, cateSn.length() - 2));
+			} else {
+				data.put("cate", cateSn);
+			}
+			data.put("cateSn", cateSn);
 			data.put("title", mesProduct.getTitle());
 			data.put("oprno", "GP12");
 

+ 9 - 0
src/main/java/com/jeesite/modules/mes/web/MesTorsionalProcessController.java

@@ -16,7 +16,9 @@ import com.jeesite.common.lang.ObjectUtils;
 import com.jeesite.common.lang.StringUtils;
 import com.jeesite.modules.mes.entity.MesProductRecord;
 import com.jeesite.modules.mes.entity.MesToolLife;
+import com.jeesite.modules.mes.req.MesSearchDateReq;
 import com.jeesite.modules.mes.service.MesProductRecordService;
+import com.jeesite.modules.mes.util.CommonUitl;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -60,6 +62,13 @@ public class MesTorsionalProcessController extends BaseController {
 	@RequiresPermissions("mes:mesTorsionalProcess:view")
 	@RequestMapping(value = {"list", ""})
 	public String list(MesTorsionalProcess mesTorsionalProcess, Model model) {
+		MesSearchDateReq dateMap = CommonUitl.getSearchDate();
+		if (mesTorsionalProcess.getCreateDate_gte() == null) {
+			mesTorsionalProcess.setCreateDate_gte(dateMap.getStartDate());
+		}
+		if (mesTorsionalProcess.getCreateDate_lte() == null) {
+			mesTorsionalProcess.setCreateDate_lte(dateMap.getEndtDate());
+		}
 		model.addAttribute("mesTorsionalProcess", mesTorsionalProcess);
 		return "modules/mes/mesTorsionalProcessList";
 	}

+ 104 - 0
src/main/java/com/jeesite/modules/sys/web/ConfigSuperAdminAspect.java

@@ -0,0 +1,104 @@
+package com.jeesite.modules.sys.web;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.ui.Model;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.modules.sys.entity.Config;
+import com.jeesite.modules.sys.entity.User;
+import com.jeesite.modules.sys.service.ConfigService;
+import com.jeesite.modules.sys.utils.UserUtils;
+
+/**
+ * 参数设置:非超级管理员只能看到并修改 is_sys=0 的项,不能改「是否系统参数」。
+ */
+@Aspect
+@Order(1)
+@Component
+public class ConfigSuperAdminAspect {
+
+	@Autowired
+	private ConfigService configService;
+
+	@Around("execution(* com.jeesite.modules.sys.web.ConfigController.listData(..))")
+	public Object filterListData(ProceedingJoinPoint pjp) throws Throwable {
+		if (!isSystemSuperAdmin()) {
+			Config config = findConfig(pjp.getArgs());
+			if (config != null) {
+				config.setIsSys(Global.NO);
+			}
+		}
+		return pjp.proceed();
+	}
+
+	@Around("execution(* com.jeesite.modules.sys.web.ConfigController.form(..))")
+	public Object filterForm(ProceedingJoinPoint pjp) throws Throwable {
+		denyIfSystemConfig(findConfig(pjp.getArgs()), "查看");
+		for (Object arg : pjp.getArgs()) {
+			if (arg instanceof Model) {
+				((Model) arg).addAttribute("isSuperAdmin", isSystemSuperAdmin());
+			}
+		}
+		return pjp.proceed();
+	}
+
+	@Around("execution(* com.jeesite.modules.sys.web.ConfigController.save(..))")
+	public Object filterSave(ProceedingJoinPoint pjp) throws Throwable {
+		if (!isSystemSuperAdmin()) {
+			Config config = findConfig(pjp.getArgs());
+			keepOriginalIsSys(config);
+		}
+		return pjp.proceed();
+	}
+
+	@Around("execution(* com.jeesite.modules.sys.web.ConfigController.delete(..))")
+	public Object filterDelete(ProceedingJoinPoint pjp) throws Throwable {
+		denyIfSystemConfig(findConfig(pjp.getArgs()), "删除");
+		return pjp.proceed();
+	}
+
+	private void keepOriginalIsSys(Config config) {
+		if (config == null) {
+			return;
+		}
+		if (config.getIsNewRecord() || StringUtils.isBlank(config.getId())) {
+			config.setIsSys(Global.NO);
+			return;
+		}
+		Config old = configService.get(config.getId());
+		if (old != null && Global.YES.equals(old.getIsSys())) {
+			throw new ServiceException("越权操作,只有超级管理员才能修改系统参数");
+		}
+		config.setIsSys(old != null ? old.getIsSys() : Global.NO);
+	}
+
+	private void denyIfSystemConfig(Config config, String action) {
+		if (isSystemSuperAdmin() || config == null || config.getIsNewRecord()) {
+			return;
+		}
+		if (Global.YES.equals(config.getIsSys())) {
+			throw new ServiceException("越权操作,只有超级管理员才能" + action + "系统参数");
+		}
+	}
+
+	private Config findConfig(Object[] args) {
+		for (Object arg : args) {
+			if (arg instanceof Config) {
+				return (Config) arg;
+			}
+		}
+		return null;
+	}
+
+	private boolean isSystemSuperAdmin() {
+		User user = UserUtils.getUser();
+		return user != null && user.isSuperAdmin();
+	}
+}

+ 11 - 6
src/main/resources/config/application.yml

@@ -13,6 +13,11 @@ copyrightYear: 2026
 # 是否演示模式
 demoMode: false
 
+# 过程参数等生产数据列表默认查询天数
+mes:
+  search:
+    days: 7
+
 # 专为分离端提供接口服务
 apiMode: false
 
@@ -32,10 +37,10 @@ ding:
   at-all: false
   app-enabled: true
   # 生产环境
-  # app-id: 2372e61f-33b9-436c-b174-f58aa3049759
-  # agent-id: 4724073992
-  # client-id: dingpr9lhefdgk79mhqx
-  # client-secret: 18ClEucl6Fg2w_HwUGtqSgTiSmA1S_7Qee9GLp63xlVQPAQKWwB93A0QcEBidKOQ
+#  app-id: 2372e61f-33b9-436c-b174-f58aa3049759
+#  agent-id: 4724073992
+#  client-id: dingpr9lhefdgk79mhqx
+#  client-secret: 18ClEucl6Fg2w_HwUGtqSgTiSmA1S_7Qee9GLp63xlVQPAQKWwB93A0QcEBidKOQ
   # 测试环境(功能测试 / 消息通知)
   app-id: 4b2ac723-d8a8-4a7a-b66d-24ddfd70e19e
   agent-id: 4929082616
@@ -183,12 +188,12 @@ jdbc:
   driver: com.mysql.cj.jdbc.Driver
 # url: jdbc:mysql://127.0.0.1:3306/ce_liu?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
 #  url: jdbc:mysql://127.0.0.1:3306/mes_cloude_npd?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
-  url: jdbc:mysql://127.0.0.1:3306/mes_cloud_dy?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+  url: jdbc:mysql://127.0.0.1:3306/mes_cloud_ahdy?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
 #  url: jdbc:mysql://192.168.9.181:3306/mes_cloud?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
 #  username: mes_cloud
 #  password: s2ENj7KaEySTC7dW
   username: root
-  password: root
+  password: 123456
   testSql: SELECT 1
 
   #  # Oracle 数据库配置(若使用 12c,请修改 /modules/core/pom.xml 文件,打开 12c 依赖,去掉 11g 依赖)

+ 44 - 0
src/main/resources/mappings/modules/mes/MesAdw300DataDao.xml

@@ -115,6 +115,50 @@
 		ORDER BY hourLabel, deviceSn
 	</select>
 
+	<select id="findDailyEnergy" resultType="java.util.Map">
+		SELECT
+			first_t.device_sn AS deviceSn,
+			DATE_FORMAT(first_x.day_start, '%m-%d') AS dayLabel,
+			ROUND(GREATEST(CAST(last_t.point_value AS DECIMAL(18, 4)) - CAST(first_t.point_value AS DECIMAL(18, 4)), 0), 3) AS energy
+		FROM mes_adw300_data first_t
+		INNER JOIN (
+			SELECT
+				device_sn,
+				DATE_FORMAT(report_time, '%Y-%m-%d') AS day_start,
+				MIN(report_time) AS report_time
+			FROM mes_adw300_data
+			WHERE status = '0'
+			  AND point_id = 28
+			  AND report_time &gt;= #{startTime}
+			  AND report_time &lt; #{endTime}
+			  AND point_value REGEXP '^-?[0-9]+(\\.[0-9]+)?$'
+			GROUP BY device_sn, DATE_FORMAT(report_time, '%Y-%m-%d')
+		) first_x ON first_x.device_sn = first_t.device_sn AND first_x.report_time = first_t.report_time
+		INNER JOIN (
+			SELECT
+				device_sn,
+				DATE_FORMAT(report_time, '%Y-%m-%d') AS day_start,
+				MAX(report_time) AS report_time
+			FROM mes_adw300_data
+			WHERE status = '0'
+			  AND point_id = 28
+			  AND report_time &gt;= #{startTime}
+			  AND report_time &lt; #{endTime}
+			  AND point_value REGEXP '^-?[0-9]+(\\.[0-9]+)?$'
+			GROUP BY device_sn, DATE_FORMAT(report_time, '%Y-%m-%d')
+		) last_x ON last_x.device_sn = first_t.device_sn AND last_x.day_start = first_x.day_start
+		INNER JOIN mes_adw300_data last_t
+		  ON last_t.device_sn = last_x.device_sn
+		 AND last_t.report_time = last_x.report_time
+		 AND last_t.point_id = 28
+		WHERE first_t.status = '0'
+		  AND first_t.point_id = 28
+		  AND first_t.point_value REGEXP '^-?[0-9]+(\\.[0-9]+)?$'
+		  AND last_t.status = '0'
+		  AND last_t.point_value REGEXP '^-?[0-9]+(\\.[0-9]+)?$'
+		ORDER BY dayLabel, deviceSn
+	</select>
+
 	<!-- 查询数据
 	<select id="findList" resultType="MesAdw300Data">
 		SELECT ${sqlMap.column.toSql()}

+ 10 - 1
src/main/resources/mappings/modules/mes/MesLineProcessDao.xml

@@ -72,9 +72,18 @@
 		SELECT * FROM `mes_line_process` where pid IS NOT NULL
 	</select>
 
+	<select id="findOprnosByTitleLike" resultType="string">
+		SELECT DISTINCT a.oprno
+		FROM mes_line_process a
+		WHERE a.status = '0'
+		  AND a.oprno IS NOT NULL
+		  AND a.oprno != ''
+		  AND a.title LIKE CONCAT('%', #{title}, '%')
+	</select>
+
 	<select id="findOprnoListByLineSn" resultType="com.jeesite.modules.mes.entity.MesLineProcess">
 		SELECT a.oprno,
-		       a.title,
+			MAX(a.title) AS title,
 			b.sn AS lineSn,
 			MIN(a.sorts) AS sorts
 		FROM mes_line_process a

+ 45 - 12
src/main/resources/mappings/modules/mes/MesProductArcWeldingDao.xml

@@ -27,19 +27,14 @@
 		</where>
 		ORDER BY ${sqlMap.order.toSql()}
 	</select> -->
-	<select id="findList" resultType="MesProductArcWelding">
+	<select id="findList" resultType="com.jeesite.modules.mes.entity.MesProductArcWelding" weight="100">
 		SELECT
-			${sqlMap.column.toSql()},
-			(
-				SELECT r.update_by
-				FROM mes_product_record r
-				WHERE r.sn = a.sn
-				  AND r.oprno = a.oprno
-				  AND (r.line_sn = a.line_sn OR r.cate_sn = a.line_sn)
-				ORDER BY CASE WHEN r.update_by IS NOT NULL AND r.update_by != '' AND r.update_by != 'system' THEN 0 ELSE 1 END,
-					r.update_date DESC, r.create_date DESC
-				LIMIT 1
-			) AS "createBy"
+			a.id,
+			a.sn,
+			a.oprno,
+			a.line_sn AS lineSn,
+			a.create_date AS createDate,
+			b.title AS oprnoTitle
 		FROM ${sqlMap.table.toSql()}
 		<where>
 			${sqlMap.where.toSql()}
@@ -47,6 +42,21 @@
 		ORDER BY ${sqlMap.order.toSql()}
 	</select>
 
+	<select id="findContentByKeys" resultType="com.jeesite.modules.mes.entity.MesProductArcWelding">
+		SELECT id, create_date AS createDate, content
+		FROM mes_product_arc_welding
+		<where>
+			<if test="list != null and list.size() > 0">
+				<foreach collection="list" item="item" separator=" OR ">
+					(id = #{item.id} AND create_date = #{item.createDate})
+				</foreach>
+			</if>
+			<if test="list == null or list.size() == 0">
+				1 = 0
+			</if>
+		</where>
+	</select>
+
 	<select id="findProductRecordUpdateBy" resultType="String">
 		SELECT r.update_by
 		FROM mes_product_record r
@@ -57,5 +67,28 @@
 			r.update_date DESC, r.create_date DESC
 		LIMIT 1
 	</select>
+
+	<select id="findProductRecordUpdateByList" resultType="com.jeesite.modules.mes.entity.MesProductRecord">
+		SELECT r.sn,
+			r.oprno,
+			r.line_sn AS lineSn,
+			r.cate_sn AS cateSn,
+			r.update_by AS updateBy,
+			r.update_date AS updateDate,
+			r.create_date AS createDate
+		FROM mes_product_record r
+		<where>
+			<if test="list != null and list.size() > 0">
+				<foreach collection="list" item="item" separator=" OR ">
+					(r.sn = #{item.sn}
+					 AND r.oprno = #{item.oprno}
+					 AND (r.line_sn = #{item.lineSn} OR r.cate_sn = #{item.lineSn}))
+				</foreach>
+			</if>
+			<if test="list == null or list.size() == 0">
+				1 = 0
+			</if>
+		</where>
+	</select>
 	
 </mapper>

+ 24 - 5
src/main/resources/mappings/modules/mes/MesProductCmtDao.xml

@@ -2,14 +2,33 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jeesite.modules.mes.dao.MesProductCmtDao">
 	
-	<!-- 查询数据
-	<select id="findList" resultType="MesProductCmt">
-		SELECT ${sqlMap.column.toSql()}
+	<select id="findList" resultType="com.jeesite.modules.mes.entity.MesProductCmt" weight="100">
+		SELECT
+			a.id,
+			a.sn,
+			a.oprno,
+			a.line_sn AS lineSn,
+			a.create_date AS createDate
 		FROM ${sqlMap.table.toSql()}
 		<where>
 			${sqlMap.where.toSql()}
 		</where>
 		ORDER BY ${sqlMap.order.toSql()}
-	</select> -->
-	
+	</select>
+
+	<select id="findContentByIds" resultType="com.jeesite.modules.mes.entity.MesProductCmt">
+		SELECT id, content
+		FROM mes_product_cmt
+		<where>
+			<if test="ids != null and ids.size() > 0">
+				id IN
+				<foreach collection="ids" item="id" open="(" separator="," close=")">
+					#{id}
+				</foreach>
+			</if>
+			<if test="ids == null or ids.size() == 0">
+				1 = 0
+			</if>
+		</where>
+	</select>
 </mapper>

+ 35 - 9
src/main/resources/mappings/modules/mes/MesProductProdDao.xml

@@ -1,15 +1,41 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jeesite.modules.mes.dao.MesProductProdDao">
-	
-	<!-- 查询数据
-	<select id="findList" resultType="MesProductProd">
-		SELECT ${sqlMap.column.toSql()}
-		FROM ${sqlMap.table.toSql()}
+
+	<!-- 列表聚合:按工件码分组 -->
+	<select id="findSnGroupList" resultType="com.jeesite.modules.mes.entity.MesProductProd">
+		SELECT
+			CONCAT('SN_', a.sn) AS "id",
+			a.sn AS "sn",
+			GROUP_CONCAT(DISTINCT a.oprno ORDER BY a.oprno SEPARATOR ',') AS "oprno",
+			MAX(a.line_sn) AS "lineSn",
+			GROUP_CONCAT(DISTINCT a.type ORDER BY a.type SEPARATOR ',') AS "type",
+			COUNT(1) AS "recordCount",
+			CAST(SUM(CASE WHEN a.qty = '1' THEN 1 ELSE 0 END) AS SIGNED) AS "okCount",
+			CAST(SUM(CASE WHEN a.qty = '1' THEN 0 ELSE 1 END) AS SIGNED) AS "ngCount",
+			CASE WHEN SUM(CASE WHEN a.qty = '1' THEN 0 ELSE 1 END) > 0 THEN '0' ELSE '1' END AS "qty",
+			MAX(a.date_time) AS "dateTime",
+			SUBSTRING_INDEX(GROUP_CONCAT(a.create_by ORDER BY a.date_time DESC), ',', 1) AS "createBy",
+			MAX(a.create_date) AS "createDate"
+		FROM mes_product_prod a
 		<where>
 			${sqlMap.where.toSql()}
+			AND a.sn IS NOT NULL AND a.sn != ''
 		</where>
-		ORDER BY ${sqlMap.order.toSql()}
-	</select> -->
-	
-</mapper>
+		GROUP BY a.sn
+		ORDER BY MAX(a.date_time) DESC, a.sn DESC
+	</select>
+
+	<select id="findSnGroupCount" resultType="long">
+		SELECT COUNT(1) FROM (
+			SELECT a.sn
+			FROM mes_product_prod a
+			<where>
+				${sqlMap.where.toSql()}
+				AND a.sn IS NOT NULL AND a.sn != ''
+			</where>
+			GROUP BY a.sn
+		) t
+	</select>
+
+</mapper>

+ 10 - 0
src/main/resources/views/modules/mes/mesElectricTorqueList.html

@@ -51,6 +51,16 @@
 					</div>
 				</div>
 				<div class="form-group">
+					<label class="control-label">${text('创建时间')}:</label>
+					<div class="control-inline">
+						<#form:input path="createDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="createDate_lte.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="createDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+				<div class="form-group">
 					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
 					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
 				</div>

+ 46 - 9
src/main/resources/views/modules/mes/mesEnergyScreen.html

@@ -20,7 +20,7 @@
             height: 100vh;
             padding: 18px 22px;
             display: grid;
-            grid-template-rows: 74px 118px 310px 1fr;
+            grid-template-rows: 74px 118px 280px 1fr;
             gap: 14px;
             background: linear-gradient(135deg, #07121f 0%, #102234 48%, #081522 100%);
         }
@@ -39,10 +39,12 @@
             box-shadow: inset 0 0 22px rgba(49, 163, 220, .08);
             border-radius: 6px;
         }
-        .metric { padding: 18px 20px; display: flex; flex-direction: column; justify-content: center; }
+        .metric { padding: 14px 20px; display: flex; flex-direction: column; justify-content: center; }
         .metric-label { color: #9fb6c7; font-size: 15px; }
-        .metric-value { margin-top: 8px; font-size: 34px; font-weight: 700; color: #44e0c2; }
+        .metric-value { margin-top: 6px; font-size: 32px; font-weight: 700; color: #44e0c2; }
         .metric-unit { margin-left: 6px; font-size: 16px; color: #a8cfe7; }
+        .metric-sub { margin-top: 6px; color: #8fb3ca; font-size: 14px; }
+        .metric-sub strong { color: #79d9ff; font-size: 16px; }
         .main { min-height: 0; }
         .device-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; min-height: 0; }
         .device-card { padding: 16px; min-height: 0; }
@@ -51,20 +53,20 @@
         .badge { padding: 4px 10px; border-radius: 4px; font-size: 13px; background: rgba(68, 224, 194, .18); color: #44e0c2; }
         .badge.offline { background: rgba(255, 103, 103, .14); color: #ff8686; }
         .device-sn { margin-left: 10px; color: #8fb3ca; font-size: 13px; font-weight: 400; }
-        .kv-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
+        .kv-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
         .kv { padding: 10px; border-radius: 4px; background: rgba(255,255,255,.04); }
         .kv span { display: block; color: #92a9bb; font-size: 13px; margin-bottom: 5px; }
         .kv strong {
             display: block;
             width: 100%;
-            font-size: 22px;
+            font-size: 20px;
             color: #ffffff;
             line-height: 1.25;
             white-space: normal;
             overflow-wrap: anywhere;
         }
-        .kv strong.small { font-size: 17px; }
-        .chart-wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; min-height: 0; }
+        .kv strong.small { font-size: 16px; }
+        .chart-wrap { display: grid; grid-template-columns: 1fr 1.2fr 0.8fr; gap: 14px; min-height: 0; }
         .panel { min-height: 0; padding: 14px; display: flex; flex-direction: column; }
         .panel-title { height: 30px; line-height: 30px; font-size: 18px; font-weight: 700; color: #79d9ff; }
         .chart { flex: 1; min-height: 0; }
@@ -78,15 +80,24 @@
     </div>
     <div class="summary">
         <div class="metric"><div class="metric-label" id="meter1PowerLabel">电表1 当前功率</div><div class="metric-value"><span id="meter1Power">0</span><span class="metric-unit">kW</span></div></div>
-        <div class="metric"><div class="metric-label" id="meter1EnergyLabel">电表1 今日用电</div><div class="metric-value"><span id="meter1Energy">0</span><span class="metric-unit">kWh</span></div></div>
+        <div class="metric">
+            <div class="metric-label" id="meter1EnergyLabel">电表1 今日用电</div>
+            <div class="metric-value"><span id="meter1Energy">0</span><span class="metric-unit">kWh</span></div>
+            <div class="metric-sub">本月 <strong><span id="meter1MonthEnergy">0</span></strong> kWh</div>
+        </div>
         <div class="metric"><div class="metric-label" id="meter2PowerLabel">电表2 当前功率</div><div class="metric-value"><span id="meter2Power">0</span><span class="metric-unit">kW</span></div></div>
-        <div class="metric"><div class="metric-label" id="meter2EnergyLabel">电表2 今日用电</div><div class="metric-value"><span id="meter2Energy">0</span><span class="metric-unit">kWh</span></div></div>
+        <div class="metric">
+            <div class="metric-label" id="meter2EnergyLabel">电表2 今日用电</div>
+            <div class="metric-value"><span id="meter2Energy">0</span><span class="metric-unit">kWh</span></div>
+            <div class="metric-sub">本月 <strong><span id="meter2MonthEnergy">0</span></strong> kWh</div>
+        </div>
     </div>
     <div class="main">
         <div class="device-list" id="deviceList"></div>
     </div>
     <div class="chart-wrap">
         <div class="panel"><div class="panel-title">今日累计用电趋势</div><div id="trendChart" class="chart"></div></div>
+        <div class="panel"><div class="panel-title">本月每日用电</div><div id="monthChart" class="chart"></div></div>
         <div class="panel"><div class="panel-title">实时功率对比</div><div id="powerChart" class="chart"></div></div>
     </div>
 </div>
@@ -94,6 +105,7 @@
 <script src="${ctxStatic}/echarts/4.2/echarts.min.js"></script>
 <script>
     var trendChart = echarts.init(document.getElementById('trendChart'));
+    var monthChart = echarts.init(document.getElementById('monthChart'));
     var powerChart = echarts.init(document.getElementById('powerChart'));
 
     function fmt(value) {
@@ -127,6 +139,7 @@
                 '<div class="kv-grid">' +
                 '<div class="kv"><span>当前功率</span><strong>' + fmt(d.power) + ' kW</strong></div>' +
                 '<div class="kv"><span>今日用电</span><strong>' + fmt(d.todayEnergy) + ' kWh</strong></div>' +
+                '<div class="kv"><span>本月用电</span><strong>' + fmt(d.monthEnergy) + ' kWh</strong></div>' +
                 '<div class="kv"><span>A/B/C电压</span><strong class="small">' + fmt(d.ua) + ' / ' + fmt(d.ub) + ' / ' + fmt(d.uc) + ' V</strong></div>' +
                 '<div class="kv"><span>A/B/C电流</span><strong class="small">' + fmt(d.ia) + ' / ' + fmt(d.ib) + ' / ' + fmt(d.ic) + ' A</strong></div>' +
                 '<div class="kv"><span>上报时间</span><strong class="small">' + formatTime(d.reportTimeText || d.reportTime) + '</strong></div>' +
@@ -142,6 +155,7 @@
             $('#meter' + (i + 1) + 'EnergyLabel').text(title + ' 今日用电');
             $('#meter' + (i + 1) + 'Power').text(fmt(device.power));
             $('#meter' + (i + 1) + 'Energy').text(fmt(device.todayEnergy));
+            $('#meter' + (i + 1) + 'MonthEnergy').text(fmt(device.monthEnergy));
         }
     }
     function renderCharts(data) {
@@ -157,6 +171,28 @@
                 return { name: item.name, type: 'line', smooth: true, symbol: 'circle', symbolSize: 5, data: item.data || [] };
             })
         });
+        monthChart.setOption({
+            color: ['#44e0c2', '#79d9ff', '#ffcc66'],
+            tooltip: { trigger: 'axis' },
+            legend: { top: 0, right: 10, textStyle: { color: '#b8d9ee' } },
+            grid: { left: 50, right: 20, bottom: 34, top: 42 },
+            xAxis: {
+                type: 'category',
+                data: data.days || [],
+                axisLabel: { color: '#9fb6c7', interval: 0, rotate: 40 },
+                axisLine: { lineStyle: { color: '#31536a' } }
+            },
+            yAxis: {
+                type: 'value',
+                name: 'kWh',
+                nameTextStyle: { color: '#9fb6c7' },
+                axisLabel: { color: '#9fb6c7' },
+                splitLine: { lineStyle: { color: 'rgba(100,160,190,.16)' } }
+            },
+            series: (data.dailySeries || []).map(function (item) {
+                return { name: item.name, type: 'bar', barMaxWidth: 14, data: item.data || [] };
+            })
+        });
         powerChart.setOption({
             color: ['#44e0c2'],
             tooltip: {},
@@ -182,6 +218,7 @@
     setInterval(loadData, 10000);
     window.addEventListener('resize', function () {
         trendChart.resize();
+        monthChart.resize();
         powerChart.resize();
     });
 </script>

+ 173 - 1
src/main/resources/views/modules/mes/mesProcessCheckRecordInfo.html

@@ -67,7 +67,7 @@
 									<td>
 										<% for(var img in item.img){ %>
 										<span style="padding-left: 5px">
-											<img src="${img.url}" style="width: 60px" onclick="window.open(this.src)" alt="">
+											<img src="${img.url}" style="width: 60px; cursor: pointer;" onclick="preview_check_img(this)" title="${text('点击预览')}" alt="">
 										</span>
 										<% } %>
 									</td>
@@ -107,5 +107,177 @@
 </div>
 <% } %>
 <script>
+function get_preview_ctx() {
+	try {
+		if (window.top && window.top !== window && window.top.layer && window.top.$) {
+			return { layer: window.top.layer, $: window.top.$ };
+		}
+	} catch (e) {}
+	if (typeof js !== 'undefined' && js.layer) {
+		return { layer: js.layer, $: (js.window && js.window.$) ? js.window.$ : $ };
+	}
+	return { layer: layer, $: $ };
+}
 
+function ensure_preview_style(jq) {
+	jq('#img-preview-layer-style').remove();
+	jq('head').append('<style id="img-preview-layer-style">'
+		+ '.img-preview-layer{background:#fff!important;}'
+		+ '.img-preview-layer .layui-layer-title{height:42px;line-height:42px;padding-right:50px;}'
+		+ '.img-preview-layer .layui-layer-content{height:calc(100% - 42px)!important;overflow:hidden!important;padding:0!important;background:#111!important;}'
+		+ '.img-preview-wrap{position:relative;height:100%;background:#111;}'
+		+ '.img-preview-toolbar{position:absolute;top:10px;left:50%;transform:translateX(-50%);z-index:9;padding:4px 8px;background:rgba(0,0,0,.45);border-radius:4px;white-space:nowrap;}'
+		+ '.img-preview-toolbar .btn{margin:0 3px;}'
+		+ '.img-preview-scale{color:#fff;margin:0 8px;display:inline-block;min-width:48px;}'
+		+ '.img-preview-stage{position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;cursor:grab;}'
+		+ '.img-preview-stage.is-dragging{cursor:grabbing;}'
+		+ '.img-preview-target{position:absolute;left:50%;top:50%;max-width:none;transform-origin:center center;user-select:none;-webkit-user-drag:none;}'
+		+ '</style>');
+}
+
+function preview_check_img(_self) {
+	var src = $(_self).attr('src');
+	if (!src) {
+		return;
+	}
+	var ctx = get_preview_ctx();
+	var $doc = null;
+	ensure_preview_style(ctx.$);
+	var winW = $(window.top).width() || $(window).width();
+	var winH = $(window.top).height() || $(window).height();
+	var areaW = Math.max(720, Math.floor(winW * 0.8)) + 'px';
+	var areaH = Math.max(520, Math.floor(winH * 0.8)) + 'px';
+	var html = ''
+		+ '<div class="img-preview-wrap">'
+		+ '  <div class="img-preview-toolbar">'
+		+ '    <button type="button" class="btn btn-sm btn-default" data-act="zoom-out"><i class="fa fa-search-minus"></i> 缩小</button>'
+		+ '    <button type="button" class="btn btn-sm btn-default" data-act="zoom-in"><i class="fa fa-search-plus"></i> 放大</button>'
+		+ '    <button type="button" class="btn btn-sm btn-default" data-act="reset"><i class="fa fa-refresh"></i> 还原</button>'
+		+ '    <span class="img-preview-scale">100%</span>'
+		+ '    <button type="button" class="btn btn-sm btn-danger" data-act="close"><i class="fa fa-times"></i> 关闭</button>'
+		+ '  </div>'
+		+ '  <div class="img-preview-stage">'
+		+ '    <img class="img-preview-target" src="' + src + '" alt="">'
+		+ '  </div>'
+		+ '</div>';
+	ctx.layer.open({
+		type: 1,
+		title: '${text("图片预览")}',
+		closeBtn: 1,
+		shadeClose: true,
+		shade: 0.45,
+		maxmin: true,
+		scrollbar: false,
+		area: [areaW, areaH],
+		skin: 'img-preview-layer',
+		content: html,
+		success: function(layero, index) {
+			layero = ctx.$(layero);
+			$doc = ctx.$(layero[0].ownerDocument);
+			bind_img_preview(layero, $doc, function() {
+				ctx.layer.close(index);
+			});
+		},
+		end: function() {
+			if ($doc) {
+				$doc.off('.imgPreview');
+			}
+		}
+	});
+}
+
+function bind_img_preview(layero, $doc, closePreview) {
+	var $stage = layero.find('.img-preview-stage');
+	var $img = layero.find('.img-preview-target');
+	var $scaleText = layero.find('.img-preview-scale');
+	var scale = 1;
+	var baseScale = 1;
+	var minScale = 0.2;
+	var maxScale = 5;
+	var offsetX = 0;
+	var offsetY = 0;
+	var dragging = false;
+	var startX = 0;
+	var startY = 0;
+	var startOffsetX = 0;
+	var startOffsetY = 0;
+
+	function applyTransform() {
+		$img.css('transform', 'translate(-50%, -50%) translate(' + offsetX + 'px,' + offsetY + 'px) scale(' + scale + ')');
+		$scaleText.text(Math.round(scale * 100) + '%');
+	}
+
+	function setScale(next) {
+		scale = Math.min(maxScale, Math.max(minScale, next));
+		applyTransform();
+	}
+
+	function resetView() {
+		scale = baseScale;
+		offsetX = 0;
+		offsetY = 0;
+		applyTransform();
+	}
+
+	function fitImage() {
+		var img = $img[0];
+		var natW = img.naturalWidth;
+		var natH = img.naturalHeight;
+		var stageW = $stage.width();
+		var stageH = $stage.height();
+		if (natW && natH && stageW && stageH) {
+			baseScale = Math.min(1, (stageW - 24) / natW, (stageH - 24) / natH);
+			minScale = Math.min(0.2, baseScale);
+		}
+		resetView();
+	}
+
+	layero.find('[data-act="zoom-in"]').on('click', function() {
+		setScale(scale * 1.2);
+	});
+	layero.find('[data-act="zoom-out"]').on('click', function() {
+		setScale(scale / 1.2);
+	});
+	layero.find('[data-act="reset"]').on('click', resetView);
+	layero.find('[data-act="close"]').on('click', function() {
+		if (typeof closePreview === 'function') {
+			closePreview();
+		}
+	});
+	$stage.on('wheel', function(e) {
+		e.preventDefault();
+		var delta = (e.originalEvent.deltaY || 0) < 0 ? 1.1 : (1 / 1.1);
+		setScale(scale * delta);
+	});
+	$stage.on('dblclick', resetView);
+	$stage.on('mousedown', function(e) {
+		if (e.which !== 1) {
+			return;
+		}
+		e.preventDefault();
+		dragging = true;
+		startX = e.clientX;
+		startY = e.clientY;
+		startOffsetX = offsetX;
+		startOffsetY = offsetY;
+		$stage.addClass('is-dragging');
+	});
+	$doc.on('mousemove.imgPreview', function(e) {
+		if (!dragging) {
+			return;
+		}
+		offsetX = startOffsetX + (e.clientX - startX);
+		offsetY = startOffsetY + (e.clientY - startY);
+		applyTransform();
+	});
+	$doc.on('mouseup.imgPreview', function() {
+		dragging = false;
+		$stage.removeClass('is-dragging');
+	});
+	if ($img[0].complete && $img[0].naturalWidth) {
+		fitImage();
+	} else {
+		$img.on('load', fitImage);
+	}
+}
 </script>

+ 177 - 106
src/main/resources/views/modules/mes/mesProcessParamLimitForm.html

@@ -18,9 +18,26 @@
 				<div class="row">
 					<div class="col-xs-6">
 						<div class="form-group">
-							<label class="control-label col-sm-4">${text('工艺名称')}:</label>
+							<label class="control-label col-sm-4"><span class="required">*</span> ${text('产线编号')}:</label>
 							<div class="col-sm-8">
-								<select id="processNameSelect" name="processName" class="form-control"></select>
+								<#form:select path="lineSn" items="${lineList}" itemLabel="sn" itemValue="sn"
+									blankOption="true" class="form-control required"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4"><span class="required">*</span> ${text('工位号')}:</label>
+							<div class="col-sm-8">
+								<select id="oprnoSelect" name="oprno" class="form-control required"></select>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4">${text('工位名称')}:</label>
+							<div class="col-sm-8">
+								<#form:input path="processName" maxlength="100" class="form-control" readonly="true"/>
 							</div>
 						</div>
 					</div>
@@ -32,6 +49,18 @@
 							</div>
 						</div>
 					</div>
+					<div class="col-xs-6" id="gunTypeGroup" style="display:none;">
+						<div class="form-group">
+							<label class="control-label col-sm-4"><span class="required">*</span> ${text('类型')}:</label>
+							<div class="col-sm-8">
+								<select id="gunType" name="gunType" class="form-control">
+									<option value="">请选择</option>
+									<option value="A">A枪</option>
+									<option value="B">B枪</option>
+								</select>
+							</div>
+						</div>
+					</div>
 					<div class="col-xs-6">
 						<div class="form-group">
 							<label class="control-label col-sm-4">${text('下限')}:</label>
@@ -65,132 +94,168 @@
 </div>
 <% } %>
 <script>
-const processLimitOptions = [
-	{key:'whitePart', name:'白件气密', params:[
-		{code:'testPressure', name:'测试压'},
-		{code:'leakVal', name:'泄漏值'}
-	]},
-	{key:'assembly', name:'总成气密', params:[
-		{code:'testPressure', name:'测试压'},
-		{code:'leakVal', name:'泄漏值'}
-	]},
-	{key:'prod115Front', name:'115拉铆框架正面', params:[
-		{code:'fout', name:'拉力'},
-		{code:'sout', name:'行程'}
-	]},
-	{key:'prod115Back', name:'115液冷板装配拉铆', params:[
-			{code:'fout', name:'拉力'},
-			{code:'sout', name:'行程'}
-		]},
-	{key:'prodHevBack', name:'HEV拉铆', params:[
-			{code:'fout', name:'拉力'},
-			{code:'sout', name:'行程'}
-		]},
-/*	{key:'prodHevFront', name:'HEV正面拉铆', params:[
-			{code:'fout', name:'拉力'},
-			{code:'sout', name:'行程'}
-		]},*/
-	{key:'welder', name:'凸焊', params:[
-		{code:'capVoltage', name:'电容电压'},
-		{code:'weldPeakCurrent', name:'焊接峰值电流'}
-	]},
-	{key:'arc115', name:'115弧焊', params:[
-		{code:'voltage1', name:'电压1'},
-		{code:'current1', name:'电流1'},
-		{code:'speed1', name:'送丝速度1'},
-		{code:'voltage2', name:'电压2'},
-		{code:'current2', name:'电流2'},
-		{code:'speed2', name:'送丝速度2'}
-	]},
-	{key:'arcHev', name:'HEV弧焊', params:[
-		{code:'voltage1', name:'电压1'},
-		{code:'current1', name:'电流1'},
-		{code:'voltage2', name:'电压2'},
-		{code:'current2', name:'电流2'}
-	]},
-	{key:'spotHev', name:'HEV点焊', params:[
-		{code:'current1', name:'电流1'},
-		{code:'current2', name:'电流2'}
-	]}/*,
-	{key:'spot115', name:'115点焊', params:[
-		{code:'current1', name:'电流1'},
-		{code:'current2', name:'电流2'}
-	]}*/
-];
-
-const findProcess = (key, name) => processLimitOptions.find(item => item.name === name)
-	|| processLimitOptions.find(item => item.key === key);
-const findParam = (processKey, code, name) => {
-	const process = findProcess(processKey);
-	const params = process ? process.params : [];
-	return params.find(item => item.code === code || item.name === name);
+const processLimitParams = {
+	whitePart: [{code:'testPressure', name:'测试压'}, {code:'leakVal', name:'泄漏值'}],
+	assembly: [{code:'testPressure', name:'测试压'}, {code:'leakVal', name:'泄漏值'}],
+	prod115Front: [{code:'fout', name:'拉力'}, {code:'sout', name:'行程'}],
+	prod115Back: [{code:'fout', name:'拉力'}, {code:'sout', name:'行程'}],
+	prodHevBack: [{code:'fout', name:'拉力'}, {code:'sout', name:'行程'}],
+	welder: [{code:'capVoltage', name:'电容电压'}, {code:'weldPeakCurrent', name:'焊接峰值电流'}],
+	arc115: [
+		{code:'voltage1', name:'电压1'}, {code:'current1', name:'电流1'}, {code:'speed1', name:'送丝速度1'},
+		{code:'voltage2', name:'电压2'}, {code:'current2', name:'电流2'}, {code:'speed2', name:'送丝速度2'}
+	],
+	arcHev: [
+		{code:'voltage1', name:'电压1'}, {code:'current1', name:'电流1'},
+		{code:'voltage2', name:'电压2'}, {code:'current2', name:'电流2'}
+	],
+	spotHev: [{code:'current1', name:'电流1'}, {code:'current2', name:'电流2'}],
+	spot115: [{code:'current1', name:'电流1'}, {code:'current2', name:'电流2'}]
 };
 
-function fillProcessOptions() {
-	const processSelect = $('#processNameSelect');
-	processSelect.empty().append('<option value="">请选择工艺名称</option>');
-	processLimitOptions.forEach(item => {
-		processSelect.append('<option value="'+item.name+'" data-code="'+item.key+'">'+item.name+'</option>');
-	});
+const currentLineSn = ${toJson(mesProcessParamLimit.lineSn!'')};
+const currentOprno = ${toJson(mesProcessParamLimit.oprno!'')};
+const currentProcessName = ${toJson(mesProcessParamLimit.processName!'')};
+const currentParamName = ${toJson(mesProcessParamLimit.paramName!'')};
+const currentParamCode = ${toJson(mesProcessParamLimit.paramCode!'')};
+const currentProcessKey = ${toJson(mesProcessParamLimit.processKey!'')};
+const currentGunType = ${toJson(mesProcessParamLimit.gunType!'')};
+
+function parentOprno(oprno) {
+	const text = String(oprno || '').toUpperCase().trim();
+	const idx = text.lastIndexOf('OP');
+	if (idx >= 0 && text.length >= idx + 5) {
+		return text.substring(idx, idx + 5);
+	}
+	return text;
+}
+
+function is115ArcStation(lineSn, oprno) {
+	const line = String(lineSn || '').toUpperCase();
+	if (line.indexOf('115') < 0) {
+		return false;
+	}
+	const parent = parentOprno(oprno);
+	return parent === 'OP060' || parent === 'OP070' || parent === 'OP080';
+}
+
+function inferProcessKey(lineSn, title, oprno) {
+	const text = title || '';
+	const line = (lineSn || '').toUpperCase();
+	if (is115ArcStation(lineSn, oprno)) {
+		return 'arc115';
+	}
+	if (text.indexOf('点焊') >= 0) {
+		return line.indexOf('115') >= 0 ? 'spot115' : 'spotHev';
+	}
+	if (text.indexOf('弧焊') >= 0 || text.toUpperCase().indexOf('CMT') >= 0) {
+		return line.indexOf('115') >= 0 ? 'arc115' : 'arcHev';
+	}
+	if (text.indexOf('拉铆') >= 0) {
+		if (line.indexOf('115') >= 0 && text.indexOf('正面') >= 0) return 'prod115Front';
+		if (line.indexOf('115') >= 0) return 'prod115Back';
+		return 'prodHevBack';
+	}
+	if (text.indexOf('气密') >= 0) {
+		return text.indexOf('白件') >= 0 ? 'whitePart' : 'assembly';
+	}
+	if (text.indexOf('凸焊') >= 0) {
+		return 'welder';
+	}
+	return '';
 }
 
 function fillParamOptions(processKey, selectedParamName) {
 	const paramSelect = $('#paramNameSelect');
-	const process = findProcess(processKey);
+	const params = processLimitParams[processKey] || [];
 	paramSelect.empty().append('<option value="">请选择参数名称</option>');
-	if (!process) {
-		return;
-	}
-	process.params.forEach(item => {
+	params.forEach(item => {
 		paramSelect.append('<option value="'+item.name+'" data-code="'+item.code+'">'+item.name+'</option>');
 	});
 	if (selectedParamName) {
 		paramSelect.val(selectedParamName);
 	}
+	if (selectedParamName && currentParamCode && paramSelect.find('option').filter(function(){
+		return $(this).val() === selectedParamName;
+	}).length === 0) {
+		paramSelect.append('<option value="'+selectedParamName+'" data-code="'+currentParamCode+'">'+selectedParamName+'</option>');
+		paramSelect.val(selectedParamName);
+	}
+	syncProcessLimitFields();
 }
 
 function syncProcessLimitFields() {
-	const processSelect = $('#processNameSelect');
-	const paramSelect = $('#paramNameSelect');
-	const processName = processSelect.val() || '';
-	const processItem = processLimitOptions.find(item => item.name === processName);
-	$('#processKey').val(processItem ? processItem.key : '');
+	const lineSn = $('#lineSn').val() || '';
+	const oprnoSelect = $('#oprnoSelect');
+	const title = oprnoSelect.find('option:selected').attr('data-title') || $('#processName').val() || '';
+	$('#processName').val(title);
+	const inferredKey = inferProcessKey(lineSn, title, oprnoSelect.val());
+	const processKey = inferredKey || currentProcessKey;
+	$('#processKey').val(processKey);
+	const paramName = $('#paramNameSelect').val() || '';
+	const paramCode = $('#paramNameSelect').find('option:selected').data('code') || '';
+	$('#paramCode').val(paramCode || '');
+	toggleGunTypeField(inferredKey);
+}
 
-	const paramName = paramSelect.val() || '';
-	const paramItem = processItem ? processItem.params.find(item => item.name === paramName) : null;
-	$('#paramCode').val(paramItem ? paramItem.code : '');
+function isProdProcessKey(processKey) {
+	return String(processKey || '').indexOf('prod') === 0;
 }
 
-function initProcessLimitSelects() {
-	fillProcessOptions();
-	const currentProcessName = '${mesProcessParamLimit.processName!}';
-	const currentProcessKey = '${mesProcessParamLimit.processKey!}';
-	const currentParamName = '${mesProcessParamLimit.paramName!}';
-	const currentParamCode = '${mesProcessParamLimit.paramCode!}';
-	const processItem = findProcess(currentProcessKey, currentProcessName);
-	const processName = processItem ? processItem.name : currentProcessName;
-	$('#processNameSelect').val(processName);
-	fillParamOptions(processItem ? processItem.key : currentProcessKey, currentParamName);
-	if (currentParamName && currentParamCode && $('#paramNameSelect option').filter(function(){
-		return $(this).val() === currentParamName;
-	}).length === 0) {
-		$('#paramNameSelect').append('<option value="'+currentParamName+'" data-code="'+currentParamCode+'">'+currentParamName+'</option>');
-		$('#paramNameSelect').val(currentParamName);
+function toggleGunTypeField(processKey) {
+	const group = $('#gunTypeGroup');
+	const select = $('#gunType');
+	if (isProdProcessKey(processKey)) {
+		group.show();
+		select.addClass('required');
+	} else {
+		group.hide();
+		select.removeClass('required').val('');
 	}
-	if (!currentParamName && currentParamCode && processItem) {
-		const paramItem = findParam(processItem.key, currentParamCode, '');
-		if (paramItem) {
-			$('#paramNameSelect').val(paramItem.name);
-		}
+}
+
+function fillStationOptions(lineSn, selectedOprno, callback) {
+	const oprnoSelect = $('#oprnoSelect');
+	oprnoSelect.empty().append('<option value="">请选择工位号</option>');
+	if (!lineSn) {
+		$('#processName').val('');
+		fillParamOptions('', '');
+		if (callback) callback();
+		return;
 	}
-	syncProcessLimitFields();
+	$.getJSON('${ctx}/mes/mesProcessParamLimit/stationList', {lineSn: lineSn}, function(list){
+		if (list && list.length) {
+			$.each(list, function(i, item){
+				const oprno = item.oprno || '';
+				const title = item.title || '';
+				oprnoSelect.append('<option value="'+htmlEscape(oprno)+'" data-title="'+htmlEscape(title)+'">'+htmlEscape(oprno)+(title ? (' ' + htmlEscape(title)) : '')+'</option>');
+			});
+		}
+		if (selectedOprno) {
+			oprnoSelect.val(selectedOprno);
+			if (oprnoSelect.val() !== selectedOprno && currentProcessName) {
+				oprnoSelect.append('<option value="'+htmlEscape(selectedOprno)+'" data-title="'+htmlEscape(currentProcessName)+'">'+htmlEscape(selectedOprno)+' '+htmlEscape(currentProcessName)+'</option>');
+				oprnoSelect.val(selectedOprno);
+			}
+		}
+		syncProcessLimitFields();
+		fillParamOptions($('#processKey').val(), currentParamName);
+		if (selectedOprno && selectedOprno === currentOprno && currentGunType) {
+			$('#gunType').val(currentGunType);
+		}
+		if (callback) callback();
+	});
 }
 
-$('#processNameSelect').change(function(){
-	const processName = $(this).val() || '';
-	const processItem = processLimitOptions.find(item => item.name === processName);
-	fillParamOptions(processItem ? processItem.key : '', '');
+$('#lineSn').change(function(){
+	fillStationOptions($(this).val() || '', '', function(){
+		fillParamOptions($('#processKey').val(), '');
+	});
+});
+
+$('#oprnoSelect').change(function(){
 	syncProcessLimitFields();
+	fillParamOptions($('#processKey').val(), '');
 });
 
 $('#paramNameSelect').change(function(){
@@ -211,5 +276,11 @@ $("#inputForm").validate({
 	}
 });
 
-initProcessLimitSelects();
+fillStationOptions(currentLineSn, currentOprno);
+
+function htmlEscape(value) {
+	return String(value || '').replace(/[&<>"']/g, function(ch){
+		return {'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;'}[ch];
+	});
+}
 </script>

+ 31 - 2
src/main/resources/views/modules/mes/mesProcessParamLimitList.html

@@ -22,7 +22,19 @@
 			<#form:form id="searchForm" model="${mesProcessParamLimit}" action="${ctx}/mes/mesProcessParamLimit/listData" method="post" class="form-inline hide"
 					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
 				<div class="form-group">
-					<label class="control-label">${text('工艺名称')}:</label>
+					<label class="control-label">${text('产线编号')}:</label>
+					<div class="control-inline">
+						<#form:input path="lineSn" maxlength="20" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('工位号')}:</label>
+					<div class="control-inline">
+						<#form:input path="oprno" maxlength="20" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('工位名称')}:</label>
 					<div class="control-inline">
 						<#form:input path="processName" maxlength="100" class="form-control width-120"/>
 					</div>
@@ -34,6 +46,16 @@
 					</div>
 				</div>
 				<div class="form-group">
+					<label class="control-label">${text('类型')}:</label>
+					<div class="control-inline width-120">
+						<select name="gunType" class="form-control">
+							<option value="">${text('全部')}</option>
+							<option value="A">${text('A枪')}</option>
+							<option value="B">${text('B枪')}</option>
+						</select>
+					</div>
+				</div>
+				<div class="form-group">
 					<label class="control-label">${text('状态')}:</label>
 					<div class="control-inline width-120">
 						<#form:select path="status" dictType="sys_search_status" blankOption="true" class="form-control isQuick"/>
@@ -54,7 +76,14 @@
 $('#dataGrid').dataGrid({
 	searchForm: $("#searchForm"),
 	columnModel: [
-		{header:'${text("工艺名称")}', name:'processName', index:'a.process_name', width:140, align:"center"},
+		{header:'${text("产线编号")}', name:'lineSn', index:'a.line_sn', width:120, align:"center"},
+		{header:'${text("工位号")}', name:'oprno', index:'a.oprno', width:120, align:"center"},
+		{header:'${text("工位名称")}', name:'processName', index:'a.process_name', width:160, align:"center"},
+		{header:'${text("类型")}', name:'gunType', index:'a.gun_type', width:80, align:"center", formatter: function(val){
+			if (val === 'A') return 'A枪';
+			if (val === 'B') return 'B枪';
+			return val || '';
+		}},
 		{header:'${text("参数名称")}', name:'paramName', index:'a.param_name', width:140, align:"center"},
 		{header:'${text("下限")}', name:'lowerLimit', index:'a.lower_limit', width:120, align:"center"},
 		{header:'${text("上限")}', name:'upperLimit', index:'a.upper_limit', width:120, align:"center"},

+ 0 - 0
src/main/resources/views/modules/mes/mesProductCheckOneInfo.html


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio