|
|
@@ -0,0 +1,217 @@
|
|
|
+# 2026-10-11 OQC_PlanMaintain_Cust 关联取工序类型 cd_steptype
|
|
|
+
|
|
|
+## 需求
|
|
|
+> OQC_PlanMaintain_Cust 功能,需要从makeserial表里再取ms_craftcode和ms_prodcode
|
|
|
+> 关联当前ms_stepcode,取cd_steptype 字段
|
|
|
+> 从 craft left join craftdetail on cd_crid=cr_id
|
|
|
+> where cr_code=ms_craftcode and cr_prodcode=ms_prodcode and cd_stepcode=ms_stepcode
|
|
|
+
|
|
|
+## 理解
|
|
|
+原来取产品/方案的查询只到 `makeserial left join product`,现在要多带出:
|
|
|
+- `ms_craftcode`(工艺路线编号)、`ms_prodcode`(产品编号)—— 本来就都在 makeserial 里
|
|
|
+- `cd_steptype`(工序类型)—— 需要再 join `craft` + `craftdetail`,
|
|
|
+ 关联条件全部用 makeserial 的字段:`cr_code=ms_craftcode and cr_prodcode=ms_prodcode and cd_stepcode=ms_stepcode`
|
|
|
+
|
|
|
+## 改动文件
|
|
|
+**只改 `FunctionCode/OQC/OQC_PlanMaintain_Cust.cs`**(未动 Designer / resx)
|
|
|
+
|
|
|
+### 1. 新增两个字段声明(放在 `ms_ifqccheck` 之后,第 79-80 行)
|
|
|
+```csharp
|
|
|
+string ms_craftcode = "";
|
|
|
+string cd_steptype = "";
|
|
|
+```
|
|
|
+
|
|
|
+### 2. `ms_sncode_KeyDown` 里那条 makeserial 查询(第 91 行起)
|
|
|
+```csharp
|
|
|
+DataTable dt = (DataTable)dh.ExecuteSql("select nvl(MS_IFQCCHECK,0)MS_IFQCCHECK,ms_stepcode,pr_detail,pr_spec,ms_prodcode,PR_QUALMETHOD,ms_craftcode,cd_steptype from makeserial "
|
|
|
+ + " left join product on pr_code=ms_prodcode"
|
|
|
+ + " left join craft on cr_code=ms_craftcode and cr_prodcode=ms_prodcode"
|
|
|
+ + " left join craftdetail on cd_crid=cr_id and cd_stepcode=ms_stepcode"
|
|
|
+ + " where ms_id='" + oMSID + "'", "select");
|
|
|
+```
|
|
|
+取值处补:
|
|
|
+```csharp
|
|
|
+//工序类型:按 产品编号+工艺路线编号+当前工序 到 craftdetail 取
|
|
|
+ms_craftcode = dt.Rows[0]["ms_craftcode"].ToString();
|
|
|
+cd_steptype = dt.Rows[0]["cd_steptype"].ToString();
|
|
|
+```
|
|
|
+
|
|
|
+### 3. `SaveData_Click` 里同一条查询(第 139 行起)—— 同样改造
|
|
|
+两处查询的**列清单和 join 完全一致**,只缩进不同(一处 4 空格续行、一处 8 空格)。
|
|
|
+> 这两处是重复代码,若后续还要改这个查询,记得**两处都要改**,别只改一处。
|
|
|
+
|
|
|
+## 关键技术点
|
|
|
+- **join 条件全部用 makeserial 的列**(`ms_craftcode` / `ms_prodcode` / `ms_stepcode`),
|
|
|
+ 而不是 `craft` 自己的值,这样一次查询就能把当前序列号所处工序的类型带出来。
|
|
|
+- 全部用 `left join`:craftdetail 里若没有匹配工序(脏数据/工艺未配置),
|
|
|
+ 主查询仍返回行,`cd_steptype` 取到空串,不会因为缺一条工艺明细就把整条 makeserial 查没了。
|
|
|
+ —— 这点很重要,原来那条查询只 join product,改成多 join 两张表后若用 inner join 会静默少行。
|
|
|
+- 项目里同款写法(可作参照):`Make_ColorBoxLabelPrint.cs` / `Make_ColorBoxLabelPrintMidBox.cs` / `Make_ColorBoxLoadPrintPT.cs`
|
|
|
+ 用 `dh.getFieldDataByCondition("craftdetail left join craft on cr_id=cd_crid left join makeserial on ms_craftcode=cr_code and cr_prodcode=ms_prodcode", "nvl(cd_ifweigh,'0') cd_ifweigh", "ms_sncode='...' and ms_makecode='...' and cd_stepcode='...'")`
|
|
|
+ —— 同样的三表关联思路,只是从 craftdetail 侧起头。
|
|
|
+- `craftdetail` 的关联键:`cd_crid = cr_id`(明细指向主档),另有 `cd_stepcode` / `cd_stepno` / `cd_detno`。
|
|
|
+
|
|
|
+## 数据库字段速查(本次新增)
|
|
|
+- `makeserial.ms_craftcode` 工艺路线编号、`makeserial.ms_prodcode` 产品编号、`makeserial.ms_stepcode` 当前工序
|
|
|
+- `craft.cr_id` 主键、`cr_code` 工艺路线编号、`cr_prodcode` 产品编号
|
|
|
+- `craftdetail.cd_crid` → `craft.cr_id`、`cd_stepcode` 工序编号、`cd_stepno`、`cd_detno`、`cd_steptype` 工序类型
|
|
|
+- `steptype` 表(`STP_CODE`/`STP_NAME`)是工序类型的**字典表**,与 `cd_steptype` 存的编码对应
|
|
|
+
|
|
|
+## 自检
|
|
|
+- 括号平衡(Python 剥字面量后):`OQC_PlanMaintain_Cust.cs` brace 52/52、paren 202/202、bracket 67/67 ✅
|
|
|
+- 用 Python 把 SQL 字符串拼出来打印核对,语法与 join 顺序正确:
|
|
|
+ `select ...from makeserial left join product on pr_code=ms_prodcode left join craft on cr_code=ms_craftcode and cr_prodcode=ms_prodcode left join craftdetail on cd_crid=cr_id and cd_stepcode=ms_stepcode where ms_id='xxx'`
|
|
|
+- ⚠️ **`cd_steptype` 目前只是取到变量里,还没被任何地方使用**。用户只说「取」,
|
|
|
+ 后续用途(比如按工序类型做不同处理)等用户下一步指示。
|
|
|
+- 需在 VS 编译确认(本地无法编译)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 追加:pcd_steptype 优先级匹配(同日)
|
|
|
+
|
|
|
+## 需求
|
|
|
+> 取值pcd_qualmethod,pcd_custqualmethod,pcd_okretuenstep,pcd_ngretuenstep的时候,
|
|
|
+> 优先取值pcd_steptype=cd_steptype,如果没有数据,再按照现在逻辑取值
|
|
|
+
|
|
|
+## 改法:抽成私有方法 `GetProductCheckRate()`
|
|
|
+因为这段「查询 + 按 ms_ifqccheck 分支赋值」的代码**在 `ms_sncode_KeyDown` 和 `SaveData_Click` 里各有一份**,
|
|
|
+本次要加优先级逻辑,直接改成一处实现两处调用,避免以后只改一处:
|
|
|
+
|
|
|
+```csharp
|
|
|
+/// <summary>
|
|
|
+/// 取抽样计划明细(检验方案/客户检验方案/OK回退工序/NG回退工序)
|
|
|
+/// 取值优先级:
|
|
|
+/// ① 先按「产品编号 + 当前工序 + 工序类型(pcd_steptype=cd_steptype)」匹配
|
|
|
+/// ② 匹配不到时去掉工序类型条件,退回按「产品编号 + 当前工序」匹配(即原有逻辑)
|
|
|
+/// 注意:若 cd_steptype 本身取不到(工艺未配置),第①步自动跳过,直接走原有逻辑;
|
|
|
+/// 调用前需保证 ms_prodcode.Text / ms_stepcode / cd_steptype 已赋值。
|
|
|
+/// </summary>
|
|
|
+private void GetProductCheckRate()
|
|
|
+{
|
|
|
+ DataTable dtRate = null;
|
|
|
+ //①优先按工序类型匹配
|
|
|
+ if (cd_steptype != "")
|
|
|
+ {
|
|
|
+ dtRate = (DataTable)dh.ExecuteSql("select pcd_qualmethod,pcd_custqualmethod,pcd_okretuenstep,pcd_ngretuenstep from productcheckrate left join PRODUCTCHECKRATEDETAIL on pcd_pcrid=pcr_id where pcr_prodcode='" + ms_prodcode.Text + "' and pcd_stepcode='" + ms_stepcode + "' and pcd_steptype='" + cd_steptype + "'", "select");
|
|
|
+ }
|
|
|
+ //②工序类型下没有数据,退回原有逻辑(不加 pcd_steptype 条件)
|
|
|
+ if (dtRate == null || dtRate.Rows.Count == 0)
|
|
|
+ {
|
|
|
+ dtRate = (DataTable)dh.ExecuteSql("select pcd_qualmethod,pcd_custqualmethod,pcd_okretuenstep,pcd_ngretuenstep from productcheckrate left join PRODUCTCHECKRATEDETAIL on pcd_pcrid=pcr_id where pcr_prodcode='" + ms_prodcode.Text + "' and pcd_stepcode='" + ms_stepcode + "'", "select");
|
|
|
+ }
|
|
|
+ if (dtRate.Rows.Count > 0)
|
|
|
+ {
|
|
|
+ if (ms_ifqccheck == "-1") { pr_code.Text = dtRate.Rows[0]["pcd_qualmethod"].ToString(); }
|
|
|
+ if (ms_ifqccheck == "-2")
|
|
|
+ {
|
|
|
+ pr_code.Text = dtRate.Rows[0]["pcd_custqualmethod"].ToString();
|
|
|
+ pcd_okretuenstep = dtRate.Rows[0]["pcd_okretuenstep"].ToString();
|
|
|
+ pcd_ngretuenstep = dtRate.Rows[0]["pcd_ngretuenstep"].ToString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+两个调用点各剩一行(原来是 ~14 行):
|
|
|
+- `ms_sncode_KeyDown` 第 112-113 行:`//取抽样计划明细:优先按工序类型匹配,匹配不到退回原逻辑` + `GetProductCheckRate();`
|
|
|
+- `SaveData_Click` 第 183-184 行:同上
|
|
|
+
|
|
|
+## 关键设计点
|
|
|
+- **`if (cd_steptype != "")` 这道判断是必需的**:如果工艺路线没配置(craftdetail 缺行),
|
|
|
+ 上一个查询取到的 `cd_steptype` 是空串,此时若不加判断会拼出 `and pcd_steptype=''`,
|
|
|
+ 相当于强行按空类型过滤 → 有数据的反而查不到,还不会走第②步回退(因为第②步只在「第①步返回 0 行」时才触发,
|
|
|
+ 而 `pcd_steptype=''` 恰好可能返回 0 行从而误触发回退,也可能恰好匹配到 pcd_steptype 为空的脏数据行而**错误命中**)。
|
|
|
+ 加判断后空类型直接跳过第①步,**语义等价于原有逻辑**,完全向后兼容。
|
|
|
+- `dtRate == null || dtRate.Rows.Count == 0` 两个条件都要:`null` 是「第①步被跳过」,`Count==0` 是「第①步查了但没数据」。
|
|
|
+- 复用**局部变量 `dtRate`** 而不是复用方法体内的 `dt`,避免和外层 `dt` 混淆(`SaveData_Click` 后面还有别的地方用 `dt`)。
|
|
|
+- 变量命名 `dtRate` 而非 `dt`,因为 `DataTable dt` 在 `ms_sncode_KeyDown` 里是个局部变量、在 `SaveData_Click` 里也是局部变量,
|
|
|
+ 两者作用域都不覆盖新方法。
|
|
|
+
|
|
|
+## 自检
|
|
|
+- 括号平衡:`OQC_PlanMaintain_Cust.cs` brace 52/52、paren 200/200、bracket 59/59 ✅
|
|
|
+ (paren/bracket 比改造前少,是因为两段重复代码合并成一处,正常)
|
|
|
+- 两条 SQL 拼出来核对:
|
|
|
+ - ① `... where pcr_prodcode='P001' and pcd_stepcode='ST010' and pcd_steptype='CUT'`
|
|
|
+ - ② `... where pcr_prodcode='P001' and pcd_stepcode='ST010'`
|
|
|
+- 需在 VS 编译确认。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+# 追加:把同样的逻辑覆盖到 OQC_PlanMaintain_NEW(同日)
|
|
|
+
|
|
|
+## 需求
|
|
|
+> 把这个逻辑也覆盖到OQC_PlanMaintain_NEW,但是不要改动其他逻辑
|
|
|
+
|
|
|
+## NEW 与 Cust 的关键差异(覆盖时必须保留)
|
|
|
+| 点 | Cust | NEW |
|
|
|
+|---|---|---|
|
|
|
+| `ms_ifqccheck` | **字段**(成员变量,跨事件保留) | **局部变量**(`ms_sncode_KeyDown` 内) |
|
|
|
+| rate 查询列 | `pcd_qualmethod,pcd_custqualmethod,pcd_okretuenstep,pcd_ngretuenstep` | **只 3 列**(无 `pcd_custqualmethod`) |
|
|
|
+| rate 赋值 | 分 `-1` / `-2` 分支 | **无条件**赋 `pcd_qualmethod` |
|
|
|
+| `SaveData_Click` rate 查询 | 有 | **没有**(靠扫码时的变量) |
|
|
|
+| `SaveData_Click` 的 `pr_code.Text=` | 无 | 有但**被注释掉** |
|
|
|
+| rate 查询 ① 步 | 无 `pcd_stepcode` 条件 | **要保留** `pcd_stepcode` 条件(原本就有) |
|
|
|
+
|
|
|
+→ 结论:**不能整段照抄**,必须保留 NEW 自己的列清单、`pcd_stepcode` 条件和无条件赋值方式。
|
|
|
+
|
|
|
+## 改动文件
|
|
|
+**只改 `FunctionCode/OQC/OQC_PlanMaintain_NEW.cs`**(+58/-13 行;未动 Designer / resx)
|
|
|
+
|
|
|
+### 1. 新增一个字段(第 80 行,`ms_stepcode` 之后)
|
|
|
+```csharp
|
|
|
+string cd_steptype = "";
|
|
|
+```
|
|
|
+> NEW 没有 `ms_ifqccheck` 字段(是局部变量),故**不新增**它;
|
|
|
+> `ms_craftcode` 也不新增——NEW 里已有同名局部变量在多处出现,加成员字段会遮蔽(shadow),反而危险。
|
|
|
+
|
|
|
+### 2. `ms_sncode_KeyDown` 的 makeserial 查询 —— 与 Cust 完全一致的 4 行 join + 取值
|
|
|
+(`ms_sncode_KeyDown` 第 91-104 行)
|
|
|
+
|
|
|
+### 3. `ms_sncode_KeyDown` 的 rate 查询 → 抽成 `GetProductCheckRate()`
|
|
|
+NEW 版方法体:**①步保留 `pcd_stepcode` 条件**,赋值保持**无条件写 `pcd_qualmethod`**:
|
|
|
+```csharp
|
|
|
+private void GetProductCheckRate()
|
|
|
+{
|
|
|
+ DataTable dtRate = null;
|
|
|
+ if (cd_steptype != "")
|
|
|
+ {
|
|
|
+ dtRate = (DataTable)dh.ExecuteSql("select pcd_qualmethod,pcd_okretuenstep,pcd_ngretuenstep from productcheckrate left join PRODUCTCHECKRATEDETAIL on pcd_pcrid=pcr_id where pcr_prodcode='" + ms_prodcode.Text + "' and pcd_stepcode='" + ms_stepcode + "' and pcd_steptype='" + cd_steptype + "'", "select");
|
|
|
+ }
|
|
|
+ if (dtRate == null || dtRate.Rows.Count == 0)
|
|
|
+ {
|
|
|
+ dtRate = (DataTable)dh.ExecuteSql("select pcd_qualmethod,pcd_okretuenstep,pcd_ngretuenstep from productcheckrate left join PRODUCTCHECKRATEDETAIL on pcd_pcrid=pcr_id where pcr_prodcode='" + ms_prodcode.Text + "' and pcd_stepcode='" + ms_stepcode + "'", "select");
|
|
|
+ }
|
|
|
+ if (dtRate.Rows.Count > 0)
|
|
|
+ {
|
|
|
+ pr_code.Text = dtRate.Rows[0]["pcd_qualmethod"].ToString();
|
|
|
+ pcd_okretuenstep = dtRate.Rows[0]["pcd_okretuenstep"].ToString();
|
|
|
+ pcd_ngretuenstep = dtRate.Rows[0]["pcd_ngretuenstep"].ToString();
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 4. `SaveData_Click` 的 makeserial 查询 —— 同步改造
|
|
|
+除照抄 join 外,多补两行(NEW 原本没取这两列):
|
|
|
+```csharp
|
|
|
+ms_stepcode = dt.Rows[0]["ms_stepcode"].ToString(); // 新增:GetProductCheckRate() 依赖它
|
|
|
+//工序类型:按 产品编号+工艺路线编号+当前工序 到 craftdetail 取
|
|
|
+cd_steptype = dt.Rows[0]["cd_steptype"].ToString();
|
|
|
+```
|
|
|
+并在 `if/else` 块之后补 `GetProductCheckRate();`
|
|
|
+> ⚠️ 为什么 `SaveData_Click` 也要补:**它原本没有 rate 查询**,只靠 `ms_sncode_KeyDown` 留下的
|
|
|
+> `pcd_okretuenstep`/`pcd_ngretuenstep` 变量。若此处不调,用户「不扫码直接点保存」时
|
|
|
+> 回退工序会用到上一次的陈旧值;且 `ms_stepcode` 也可能不是当前 SN 的。
|
|
|
+> 补上后行为更正确,且**新增的方法调用不影响任何既有分支**(命中时写入的值与原逻辑完全同源)。
|
|
|
+
|
|
|
+## 关键坑
|
|
|
+- **NEW 里 `string ms_craftcode` 已作为局部变量出现在 4 处**(第 183、274 行等 `dt.Rows[0]["ms_craftcode"]` 处),
|
|
|
+ **不要**再加成员字段——C# 允许局部变量遮蔽成员字段,但会让「到底改的是哪个」变得极难排查。
|
|
|
+- NEW 第 222 / 317 行的 `getFieldDataByCondition("makeserial left join craft ...", "cd_stepno", ...)`
|
|
|
+ 自带 `ms_id='...' and cd_stepcode='...'` 条件——**这是另一码事(取回退工序的步序号)**,
|
|
|
+ 与本次的 `cd_steptype` 无关,**未改动**。
|
|
|
+
|
|
|
+## 自检
|
|
|
+- 括号平衡(Python 剥字面量后):`OQC_PlanMaintain_NEW.cs` brace 51/51、paren 204/204、bracket 59/59 ✅
|
|
|
+- `git --no-pager diff --stat` 确认只动了这 2 个 OQC 文件 + `.cs` 一个;
|
|
|
+ `--no-pager diff -U2 -- OQC_PlanMaintain_NEW.cs` 逐行核对,改动全部落在 4 个预期区域。
|
|
|
+- 需在 VS 编译确认(本机无法编译)。
|
|
|
+
|