Ver Fonte

修改SOP文件版本更新

callm há 3 semanas atrás
pai
commit
85d71a0617

+ 51 - 0
UAS_MES_ZKLH/.workbuddy/memory/2026-09-17.md

@@ -0,0 +1,51 @@
+# 2026-09-17 工作日志
+
+## Query_SOP.cs 上传逻辑改造(FunctionCode/Query/Query_SOP.cs)
+
+背景:SOP 上传(JPG/Excel 转图片、PDF 两种模式)需要按 SOP 编号解析并写入 productsop 表。
+
+### 改动 1:ps_prcode 取 Excel 中的 PN/TOOLS 列
+- 新增 `GetPnToolsFromExcel(Workbook)`:遍历所有 Sheet,先在单元格里找标题含 `PN/TOOLS` 的列;
+  找不到再从形状(文本框)`Shapes[].Text` 定位列号(取 LeftColumn/UpperLeftRow)。
+- 收集标题下方该列所有非空内容,去重且保持出现顺序,用英文逗号拼接。
+- 解析结果写入 productsop 的 `ps_prcode`(insert 两条语句 + update 两条语句都改为用 `pnTools`)。
+- 兜底:解析为空时回退为表单 `pr_code.Text`;界面输出「解析PN/TOOLS: xxx」便于核对。
+- JPG 分支中 Workbook 提前到查库前加载(原来在查库之后 new,导致取不到数据)。
+
+### 改动 2:SOP 编号从文件名中截取(去重判断口径变化)
+- 「版本号在变、编号不变」是客户约定:(R1)WI-LC-31-544… 与 (R0)WI-LC-31-544… 必须匹配到同一条数据。
+- 新增 `GetProdCodeFromFileName(string)`:
+  1) 先去版本号:`[((]\s*[Rr](?:[Ee][Vv]?)?\.?\s*\d+\s*[))]` 与开头 `^\s*[Rr](?:[Ee][Vv]?)?\.?\s*\d+\s*[-_\s]+`
+     (覆盖 (R1)/(R0)/(R2)/(Rev.1)/R1-/R0_ 等写法);
+  2) 再取第一个编号段:正则 `[A-Za-z0-9]+(?:-[A-Za-z0-9]+)+`;
+  3) 都匹配不到则返回原文件名。
+- 回归用例结果:新旧版本号、全角括号、R1- 前缀、编号后置 (R1) → 全部得到 WI-LC-31-544。
+- 重复处理逻辑改为「先删后插」:按解析出的编号查 productsop,
+  存在则删除 `ProductSOPdetail`(按 psd_psid)+ 删除 `productsop`(按 ps_id),随后无条件重新 insert。
+  (原逻辑是保留主表记录、只删明细并复用旧 ps_prodcode。)
+
+### 改动 3:兼容历史数据(库里存的是完整文件名)
+- 关键事实:**旧数据 ps_prodcode 里存的是完整文件名**,如 `(R0)WI-LC-31-544 冷端热端铜柱焊接组件检漏作业指导书x`,
+  只按 `= 'WI-LC-31-544'` 查是匹配不到的。
+- 新增 `FindDuplicatedSopIds(prodcode)`:先 `ps_prodcode like '%编号%'` 粗捞,
+  再逐行用 `GetProdCodeFromFileName(库值) == 编号`(忽略大小写)精确比对,返回 ps_id 列表。
+  这样既命中历史全名数据,又避免 `WI-LC-31-5441` 这类前缀相同的误删。
+- 两个分支的删除循环改为遍历 `oldIds`,界面输出「已删除原SOP编号【xxx】的旧数据(N条),重新插入」。
+- JPG 与 PDF 两个分支都按此口径统一处理。
+
+### 改动 4:PN/TOOLS 取值排除 JT 开头
+- `GetPnToolsFromExcel` 收集值时,`text.ToUpper().StartsWith("JT")` 的一律跳过。
+- 返回值语义细化为:**找不到 PN/TOOLS 列 → null;找到列但内容为空/被JT过滤完 → 空字符串**。
+- 调用处回退逻辑改为只在 `pnTools == null` 时用表单 `pr_code.Text`,
+  即"有PN/TOOLS列但全是JT"时 ps_prcode 存空,而不是拿旧值顶上。
+
+### 改动 5:入库值回到完整文件名,编号只用于匹配
+- `ps_prodcode` 入库/更新 **存完整文件名**(如 `(R1)WI-LC-31-544 冷端热端铜柱焊接组件检漏作业指导书x`),
+  不再只存截取出的编号。
+- 截取结果改存局部变量 `prodCode`,仅用于重复数据匹配与删除。
+- 界面日志同时打印编号和文件名:`解析SOP编号: WI-LC-31-544,文件名: (R1)WI-LC-31-544 冷端...`。
+- 注意:此改动后 `ps_attachsop` 更新语句里的 `where ps_prodcode=完整文件名` 与刚插入的记录一致;
+  但图片输出目录也用完整文件名(`Application.StartupPath\完整文件名\`),Windows 路径合法性取决于文件名里的字符。
+
+### 待确认
+- PDF 分支也套用了同样的编号截取规则,若 PDF 文件名规则不同需回退。

+ 30 - 11
UAS_MES_ZKLH/FunctionCode/Query/Query_SOP.cs

@@ -80,18 +80,23 @@ namespace UAS_MES_NEW.Query
             //}
             if (JPG.Checked)
             {
-                ps_prodcode.Text = GetProdCodeFromFileName(FilePath.Text.Substring(FilePath.Text.LastIndexOf(@"\") + 1).Replace(".xls", "").Replace(".xlsx", ""));
-                OperatResult.AppendText("解析SOP编号: " + ps_prodcode.Text + "\n");
+                string fileName = FilePath.Text.Substring(FilePath.Text.LastIndexOf(@"\") + 1).Replace(".xls", "").Replace(".xlsx", "");
+                // 入库的ps_prodcode用完整文件名,如 (R1)WI-LC-31-544 冷端热端铜柱焊接组件检漏作业指导书x
+                ps_prodcode.Text = fileName;
+                // 匹配/删除时用截取出来的编号,如 WI-LC-31-544(新旧版本号都指向同一条数据)
+                string prodCode = GetProdCodeFromFileName(fileName);
+                OperatResult.AppendText("解析SOP编号: " + prodCode + ",文件名: " + ps_prodcode.Text + "\n");
                 pr_code_Leave(new object(), new EventArgs());
                 Workbook workbook = new Workbook(FilePath.Text);
                 string pnTools = GetPnToolsFromExcel(workbook);
-                if (pnTools == "")
+                if (pnTools == null)
                 {
+                    // 整个Excel都没有PN/TOOLS列时,回退用表单上的产品编号
                     pnTools = pr_code.Text;
                 }
                 OperatResult.AppendText("解析PN/TOOLS: " + pnTools + "\n");
                 // 匹配已存在的旧数据:新旧版本号不同(如(R0)/(R1))、或历史数据存的是完整文件名,都按中间不变的SOP编号(如WI-LC-31-544)来匹配
-                List<string> oldIds = FindDuplicatedSopIds(ps_prodcode.Text);
+                List<string> oldIds = FindDuplicatedSopIds(prodCode);
                 if (oldIds.Count > 0)
                 {
                     // 已存在相同SOP编号:先删除原明细和主表数据,后面重新插入
@@ -100,7 +105,7 @@ namespace UAS_MES_NEW.Query
                         dh.ExecuteSql("delete from ProductSOPdetail where psd_psid='" + oldIds[d] + "'", "delete");
                         dh.ExecuteSql("delete from productsop where ps_id='" + oldIds[d] + "'", "delete");
                     }
-                    OperatResult.AppendText("已删除原SOP编号【" + ps_prodcode.Text + "】的旧数据(" + oldIds.Count + "条),重新插入\n");
+                    OperatResult.AppendText("已删除原SOP编号【" + prodCode + "】的旧数据(" + oldIds.Count + "条),重新插入\n");
                 }
                 string code = LogicHandler.GetPiInoutCode("ProductSOP", "1");
                 ps_code.Text = code;
@@ -362,11 +367,15 @@ namespace UAS_MES_NEW.Query
             }
             else if (PDF.Checked)
             {
-                ps_prodcode.Text = GetProdCodeFromFileName(FilePath.Text.Substring(FilePath.Text.LastIndexOf(@"\") + 1).Replace(".pdf", ""));
-                OperatResult.AppendText("解析SOP编号: " + ps_prodcode.Text + "\n");
+                string fileName = FilePath.Text.Substring(FilePath.Text.LastIndexOf(@"\") + 1).Replace(".pdf", "");
+                // 入库的ps_prodcode用完整文件名
+                ps_prodcode.Text = fileName;
+                // 匹配/删除时用截取出来的编号
+                string prodCode = GetProdCodeFromFileName(fileName);
+                OperatResult.AppendText("解析SOP编号: " + prodCode + ",文件名: " + ps_prodcode.Text + "\n");
                 pr_code_Leave(new object(), new EventArgs());
                 // 匹配已存在的旧数据:新旧版本号不同(如(R0)/(R1))、或历史数据存的是完整文件名,都按中间不变的SOP编号(如WI-LC-31-544)来匹配
-                List<string> oldIds = FindDuplicatedSopIds(ps_prodcode.Text);
+                List<string> oldIds = FindDuplicatedSopIds(prodCode);
                 if (oldIds.Count > 0)
                 {
                     // 已存在相同SOP编号:先删除原明细和主表数据,后面重新插入
@@ -375,7 +384,7 @@ namespace UAS_MES_NEW.Query
                         dh.ExecuteSql("delete from ProductSOPdetail where psd_psid='" + oldIds[d] + "'", "delete");
                         dh.ExecuteSql("delete from productsop where ps_id='" + oldIds[d] + "'", "delete");
                     }
-                    OperatResult.AppendText("已删除原SOP编号【" + ps_prodcode.Text + "】的旧数据(" + oldIds.Count + "条),重新插入\n");
+                    OperatResult.AppendText("已删除原SOP编号【" + prodCode + "】的旧数据(" + oldIds.Count + "条),重新插入\n");
                 }
                 string code = LogicHandler.GetPiInoutCode("ProductSOP", "1");
                 ps_code.Text = code;
@@ -464,9 +473,12 @@ namespace UAS_MES_NEW.Query
 
         /// <summary>
         /// 从Excel中查找标题为PN/TOOLS的列,收集该列标题下方所有非空内容,去重后用逗号拼接返回
+        /// 值为JT开头的不记录
+        /// 找不到PN/TOOLS列时返回null;找到但内容为空(或被JT过滤完)时返回空字符串
         /// </summary>
         private string GetPnToolsFromExcel(Workbook workbook)
         {
+            bool headerFound = false;
             List<string> values = new List<string>();
             for (int i = 0; i < workbook.Worksheets.Count; i++)
             {
@@ -509,18 +521,25 @@ namespace UAS_MES_NEW.Query
                     }
                 }
                 if (headerCol < 0) continue;
-                // 3. 收集标题下方该列所有非空内容,去重(保持顺序)
+                headerFound = true;
+                // 3. 收集标题下方该列所有非空内容,去重(保持顺序),JT开头的不记录
                 for (int r = headerRow + 1; r <= Math.Max(maxRow, cells.MaxDataRow); r++)
                 {
                     object val = cells[r, headerCol].Value;
                     if (val == null) continue;
                     string text = val.ToString().Trim();
-                    if (text != "" && !values.Contains(text))
+                    if (text == "") continue;
+                    if (text.ToUpper().StartsWith("JT")) continue;
+                    if (!values.Contains(text))
                     {
                         values.Add(text);
                     }
                 }
             }
+            if (!headerFound)
+            {
+                return null;
+            }
             return string.Join(",", values.ToArray());
         }