Commit 1ac5825c authored by 段廷瑞's avatar 段廷瑞

pref: 行业知识,SQL及问题排查能力内置

parent 5cdb8136
......@@ -65,5 +65,7 @@ bin
*.zip
/AppHome/AgentChat
/AppHome/Agent/history
/AppHome/Agent
/AppHome/Agent/*
!/AppHome/Agent/dialect/
!/AppHome/Agent/industry/
/AppHome/Agent/config/AgentConfig.json
......@@ -45,6 +45,18 @@
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="NPOI, Version=2.5.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.1\lib\net45\NPOI.dll</HintPath>
</Reference>
<Reference Include="NPOI.OOXML, Version=2.5.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.1\lib\net45\NPOI.OOXML.dll</HintPath>
</Reference>
<Reference Include="NPOI.OpenXml4Net, Version=2.5.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.1\lib\net45\NPOI.OpenXml4Net.dll</HintPath>
</Reference>
<Reference Include="NPOI.OpenXmlFormats, Version=2.5.1.0, Culture=neutral, PublicKeyToken=0df73ec7942b34e1, processorArchitecture=MSIL">
<HintPath>..\packages\NPOI.2.5.1\lib\net45\NPOI.OpenXmlFormats.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
......@@ -54,8 +66,10 @@
<Compile Include="AgentEngineLogicTests.cs" />
<Compile Include="FailoverPolicyTests.cs" />
<Compile Include="KbServiceSandboxTests.cs" />
<Compile Include="DialectServiceTests.cs" />
<Compile Include="EmbeddingClientTests.cs" />
<Compile Include="ToolPermissionTests.cs" />
<Compile Include="TextEncodingTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Tools\Tools.csproj">
......
This diff is collapsed.
This diff is collapsed.
# 产品排查方言(内化版)
行业简介:Ftt 产品线排查方言——桌面端业务链路(窗口→业务类→SQL/SP→数据库)、审批引擎、SQL 规范与热点归因模式,供 SQL 排查与问题归因对齐产品事实。适用:ERP(U6_*、风行等)、PDM(PDM_LN、LNCenterApi)、MES(MES_*、mes_geshiwei)桌面端与 cloud Api 服务端。
## 01-排查方法论
- troubleshoot-core/five-steps.md:排查五步法:复现取证/链路定位/模式对比/单一假设/根因修复(触发词:排查、报错、数据不对、超时、闪退、定位问题、怎么查、根因、证据)
- troubleshoot-core/output-spec.md:排查输出规范:一句话根因+证据链+影响范围(触发词:输出规范、根因一句话、证据链、修复建议)
## 02-SQL 规范
- sql-core/sql-templates.md:四库通用查询模板(触发词:加列、索引、执行计划、分页、核对查询、幂等)
- sql-core/sql-style.md:SQL 格式规范(触发词:格式化、CRLF、别名、注释头)
- sql-core/sql-scripts.md:脚本生成规范(触发词:生成脚本、落盘、脚本命名)
## 03-ERP 排查链路
- erp/winforms.md:桌面端排查链路(触发词:库存不对、报表数据不对、单据状态、提交报错、程序异常、性能、约束、App.Run.Log)
- erp/verification-flow.md:审批流程引擎(触发词:审批不触发、审批流程、VF_FlowMap、在审、已审、审批节点)
- erp/sql-script-location.md:SQL 脚本存放规范(触发词:脚本存放、2999-01-01、GB2312、AddTable、存储过程命名)
- erp/special-modules.md:报表类模块 SQL 获取三途径(触发词:自定义报表、FrmRPTView、动态表结构、TableIdentic、报表列空)
- erp/grid-filter.md:网格过滤联动机制(触发词:过滤不联动、复选框过滤、PivotGrid、GridView)
- erp/parent-provider.md:父子单据联动(触发词:产生了任务、跟单、ParentProvider、A单据产生B任务)
- erp/aspnet.md:Api 服务端排查(触发词:Api、接口报错、ApiLog、LNCenterApi、FttData.Api、接口慢)
- erp/cases/hotspots.md:ERP 热点归因案例(触发词:数量变0、库存多扣、二次保存、缓存失效、提交报错、8114)
## 04-MES 排查方言
- mes/sql-templates-mes.md:MES 查询模板(触发词:MES、报工、检验、成型配套、排程、生产计划、尺码明细)
- mes/cases/hotspots.md:MES 热点归因案例(触发词:成型配套、合计行小于明细)
## 05-PDM 排查方言
- pdm/cases/hotspots.md:PDM 热点归因案例(触发词:PDM、材料汇总、报表慢、风险评估)
## 06-常见问题
> 本地沉淀区:排查确认的典型问题经维护者整理追加到本大类(内置目录只读,禁止智能体直接写入)。
# ASP.NET 排查(数据错误 / 程序异常 / 性能 / 约束 / SQL 日志)
> 适用:cloud(FttData.Api)、LNCenterApi。
> 项目事实(数据库连接、ModuleName 路由机制、App_Sys_Operation_Log 表结构)从知识库检索获取。
> 排查任一步因信息不足卡住 → 向用户索要关键信息(入参/日志文件),或建议补强(开启 SqlLog / 加完整异常日志)。
> 通用方法论见 dialect/troubleshoot-core(五步法 / 输出规范)。
## 取证工具
- 查库:`db_query`(SELECT-only)/ `db_schema`,需先在设置中预存连接(connectionId)。
- 无预置连接时:把 SQL 给用户在 SSMS 执行,取回结果再分析。
- 读代码:源码检索(知识库内代码分析文档)。
## ASP.NET 数据错误排查
```
1. 查操作日志:
SELECT TOP 10 * FROM App_Sys_Operation_Log
WHERE Action LIKE '%关键词%' ORDER BY OperateDate DESC
→ 获取 RequestParams(入参 JSON)+ ResponseParams(出参 JSON)
2. 定位源码 → Controller/{名称}Controller.cs → Action 方法
3. 找到 SP → Action 中 "Exec dbo.SP_xxx" 调用 → 提取 SP 名和参数
4. db_query 复现 → 用日志入参执行 SP → 比对结果 vs 日志出参
→ 一致但数据错 = SP 逻辑问题 / 不一致 = 参数绑定/序列化问题
```
## ASP.NET 程序异常排查
```
1. 查 App_Sys_Operation_Log WHERE ResponseMessage != '' → 获取错误
2. 分类:参数校验失败 / 500 内部错误 / 序列化失败 / 数据库连接失败
3. 卡住处理(ResponseMessage 为空 / ApiLog 缺失 / 现象模糊):
→ 向用户索要入参与 ApiLog 文件,建议开启 SqlLog / 加完整异常日志
```
## ASP.NET 性能问题排查
```
1. SELECT TOP 20 * FROM App_Sys_Operation_Log ORDER BY SpendTime DESC
2. 找到对应 SP → SSMS 执行计划 → 缺失索引/参数嗅探/锁等待/无分页
```
## 数据库约束异常排查(ASP.NET 侧)
```
1. 获取完整错误 → App_Sys_Operation_Log 的 ResponseMessage
2. 提取约束名和表名 → 找出违反约束的数据
3. 追踪数据来源 → 业务链路上溯到写入点
常见类型:违反唯一性约束(主键/唯一索引冲突)/ 值检查约束(CHECK)/ 外键约束
```
## ASP.NET SQL 日志排查(ApiLog)
```
API 请求日志位于:{程序目录}/ApiLog/versionXXX/Controller_yyyyMMdd.log
排查流程:
1. 确定时间范围和接口:
→ 让用户提供或检索 ApiLog 目录:ls ApiLog/versionPM/TaskController_20260701.log
→ 或用 grep "start:接口名" 搜索
2. 定位具体请求:
→ grep "traceId=xxx" ApiLog/versionXXX/*.log
→ 或 grep "user=用户名" ApiLog/versionXXX/*.log
→ 或 grep "-- start:Controller.Action" ApiLog/versionXXX/*.log
3. 分析请求链路:
→ 从 -- start 到 -- end 之间的所有 SQL 按执行时间排列
→ 每条 SQL 格式:SQL语句; -- 参数名=值 -- 耗时ms, 行数, 模块
4. 排查异常:
→ grep "失败" ApiLog/versionXXX/*.log
→ grep "错误:" ApiLog/versionXXX/*.log
5. 慢查询分析:
→ grep -E "\-\- [0-9]{4,}ms" ApiLog/versionXXX/*.log
```
日志格式:
```
-----------------------------------------------------
-- start:Controller.Action (request={...}) [时间] user=用户 ip=IP traceId=GUID
SELECT * FROM Table WHERE Col=@Param; -- @Param='Value' -- 45ms, 12 rows, Module
EXEC SP_Name @P1, @P2; -- @P1=1, @P2='text' -- 230ms, Module
-- end: Controller.Action 总耗时=Nms SQL数=N 成功/失败 [时间]
```
**配置**(`WebAppSettings.config`):
```xml
<add key="SqlLog:Enabled" value="true" /> <!-- 开关 -->
<add key="SqlLog:SlowQueryThresholdMs" value="0" /> <!-- 慢查询阈值,0=全部 -->
<add key="SqlLog:MaxSqlLength" value="4000" /> <!-- SQL截断长度 -->
<add key="SqlLog:RetentionDays" value="30" /> <!-- 保留天数 -->
```
**技术架构摘要**:
| 组件 | 作用 |
|------|------|
| `SqlTraceAttribute` | ActionFilter — 请求开始时创建缓冲区,结束时写文件 |
| `SqlTraceContext` | HttpContext.Items 中存储 TraceId + `List<string>` 缓冲区 |
| `SqlLogHelper.Log()` | 格式化 SQL 行并追加到缓冲区 |
| `SqlLogWriter` | ThreadPool 异步写入,按文件路径 lock 防交错 |
| `SqlLogContextWrapper` | 包装 `IDbContext`,拦截 `Sql()` 和 `MultiResultSql` |
| `SqlLogCommandWrapper` | 包装 `IDbCommand`,拦截所有 QueryMany/Execute 等方法 |
**文件位置**:`ApiLog/versionXXX/Controller_yyyyMMdd.log`,位于程序 bin 目录下,例如:
`FttData.Api\bin\ApiLog\versionPM\TaskController_20260701.log`
**排查技巧**:
- 请求块的 `-- start` 行包含完整请求参数(复杂对象以 JSON 序列化)
- 每个 SQL 行末尾 `-- @param=value` 显示实际参数值
- `traceId` 可在不同请求间唯一标识,关联同一请求的所有 SQL
- 文件按天滚动,过期自动清理(默认保留 30 天)
- 日志写入失败不影响主业务(静默忽略)
# ERP 产品线热点问题统计(归因模式库)
> 每次排查确认根因后由维护者追加;智能体遇到相似症状时优先比对本库模式,再按五步法取证。
> 通用桌面端排查链路(窗口→业务类→SQL/SP→数据库)见 dialect/erp/winforms.md。
> 最后更新:2026-08-24
## 采购单 / 辅料采购合同(frmEditPurchaseDoc / ucPurchaseShip / PurchaseShipMaterial.xml)
### 二次保存提示「采购数量大于未采数量(0)+可多采数量(0)」(已采统计自包含)
- **分类**:数据错误(校验口径)
- **根因**:`SelectByDocTree` 的 has 子查询未排除当前单据 → 首次保存后 AfterDataSave 重载把当前单自身计入 HasPurchaseCount → 未采=需求−已采(含自身)=0 → 二次保存 checkPurchaseCountInput 必拦
- **修复**:has 子查询加 `AND a.DocTreeID <> @DocTreeID`
- **归因模式**:**自包含统计**——校验口径的聚合查询把「当前正在处理的单据」计入了统计基数。排查时先核对统计 SQL 是否排除自身。
### 保存后提交,明细采购数量变 0 / 数量不守恒(155→4.3278)
- **分类**:数据错误
- **根因**:AfterDataSave 中「移除明细缓存 + 数据库重载 + 重建合并视图」,用新 DataRow 实例替换明细数据集,而 GridSpliceDetailMerge 分摊缓存(m_hasComputeTotal/m_hasSingleCol)按 DataRow 哈希键控且从不失效 → 重载后下次保存/提交以 0 为基数分摊/截断 → 采购数量清零
- **修复**:缓存失配检测重建(IsDetailCacheValid/RebuildDetailCache)+ SetTotalDetailMerge 清空三缓存
- **归因模式**:**按对象哈希键控的缓存不清理**——重载/重建行实例后缓存命中错误基线。排查「保存后数量变化」先找按 DataRow/对象实例做键的缓存。
### 保存检查错误:表头中不存在列 LastModifiedDate 或 LastModifiedMemo
- **分类**:程序异常(日志级,非致命)
- **根因**:Update 保存表头行取自列表查询 SelectObject,PurchaseDoc.xml 列表查询缺 LastModifiedMemo 列 → ObjectModefiedHelper 并发修改检查静默失效(多模块长期存在)
- **归因模式**:**XML 列表查询缺列导致框架特性静默失效**——报错指向框架机制(并发检查)时,先核对 ConfigFile XML 的列是否齐全。
### 保存异常:无法访问已释放的对象 ucRoundDeskShow
- **分类**:程序异常
- **根因**:消息提醒平台模板数≤3 时 Init() Remove 了承载 ucRoundDeskShow1 的 tabPage1(Remove 释放子控件),DbAsynClient 异步回调仍 Invoke 访问 → ObjectDisposedException
- **归因模式**:**异步回调访问已释放控件**——Remove/Dispose 控件后,异步回调未取消仍 Invoke。排查「无法访问已释放的对象」先找异步回调生命周期。
## 样品单提交(ucObjectSubmit / SP_Sync_NoticeToMesOnSubmit)
### 样品单提交报错:未将对象引用设置到对象的实例(MES 同步链路失败)
- **分类**:程序异常
- **根因**:① 真实错误 = 样品单的 EachExpend 非法数字文本,FTT_MES.SP_Sync_U6NoticeToStyleMaterial `Convert(Decimal(18,6), EachExpend)` 抛 SQL 8114(varchar→numeric);② 表象错误 = 事务失败后 DBCommand.Dispose() 仍调 GetCurrentTransactionLevel() 在失败 SqlTransaction 上执行 SELECT @@TRANCOUNT → SqlHelper.PrepareCommand 抛 NullReferenceException,**掩盖真实错误**
- **修复**:SP 加固(Convert→Try_Convert);DBCommand.Dispose 失败路径直接 Rollback(不再查 @@TRANCOUNT);日志增强(SqlException.Procedure/LineNumber 定位)
- **归因模式**:**表象错误掩盖真实错误**——提交报错先看堆栈是否是框架清理路径(Dispose/事务回滚)抛的异常,真实错误常在更早的 SQL 层(SqlException.Procedure/LineNumber 直接定位)。
## 风行正式订单简易版(UOrderDocImport)
### 数量修改同步到正式订单的触发时机(仅手动【更新订单信息】,提交不触发)
- **分类**:其他(功能改动方案/模块分析)
- **根因**:同步仅挂在【更新订单信息】链接(linkLabel3_LinkClicked → Update() 尾部 exec SP_ImportToOrderDoc_Change);保存走重写版 Save()、提交走 _EditForm.Save() 多态,均不触发同步;另 SP 依赖日志字段导致增删尺码不同步
- **归因模式**:**多入口保存路径不一致**——「保存能同步/提交不能」类问题,先枚举所有保存入口(保存/提交/审核/异步),比对同步钩子挂点。
## 仓库管理-出库/调拨
### 物料出库库存多扣(现存量与流水不符)
- **分类**:数据错误
- **根因**:出库/调拨 SP(up_StockOutSubmit/up_StockAssignSubmit)按 Factory+Warehouse+MaterialID+BatchNo 松条件扣减现存量,不按选料库存行(MCSID);BatchNo=NULL 时唯一约束失效可同键多行 → N 倍多扣;提交/撤回条件不对称;找不到库存行时插负行;调拨确认/取消到料入方不同步;StockOutDetail 无 MCSID 字段
- **归因模式**:**扣减键过松**——库存多扣先核对扣减条件是否含明细行唯一键(MCSID),再核对提交/撤回对称性。
## 样品单-物料表选择物料(frmDataImportFilter)
### 选择物料按款式+颜色筛选 + 颜色兼容匹配(去掉-x后缀)
- **分类**:数据错误(筛选漏数据)+ 功能优化
- **根因**:filter 只对 PDMSample 页签启用,样品单/正式订单页签不按款式+颜色过滤;颜色过滤精确等值导致 云雾白-3 与 云雾白 互不匹配
- **修复**:非 StyleBOM 调用方且 Filter_StyleCode/Filter_ColorName 非空时启用过滤;双方去掉末尾"-数字"后缀后比较
- **归因模式**:**筛选条件语义不一致**——「选不到数据/漏数据」先核对过滤口径(等值 vs 兼容、后缀归一化)与页签覆盖范围。
# 网格过滤联动机制(GridView / PivotGrid)
> WinForms 客户端有两种分析表格,均支持复选框过滤。但普通表格有**联动效果**(如部门过滤后,工艺过滤框只显示该部门的工艺),多维表格原生无联动,需额外实现。
## 普通分析表格(GridView)— GridViewFilterHelper
**入口**:`U.WinCtl.OpCtl.UP4XtraGrid.AddToGrid(grdXtrMainGrid, dsDetail, busObj)` → 自动附加 `GridViewFilterHelper`
**核心文件**:
| 文件 | 位置 | 作用 |
|------|------|------|
| `GridViewFilterHelper.cs` | `U.WinCtl\OpCtl\` | 复选框过滤 + 联动核心类 |
| `UP4XtraGrid.cs` | `U.WinCtl\OpCtl\` | 在 `createGridView` 中调用 `SetGridViewFilterCheckedListModel` |
**调用链**:
```
UP4XtraGrid.AddToGrid()
→ AddToGridEx()
→ createGridView()
→ GridViewFilterHelper.SetGridViewFilterCheckedListModel(gridView) // 第 226 行
→ new GridViewFilterHelper(gridView) // 构造即注册事件
```
**联动原理**:
```
用户点击列头过滤图标
→ ShowFilterPopupCheckedListBox 事件触发
→ 判断 FilterValues 是否为空:
├── 不为空(已有过滤):直接 return,让 DevExpress 用内置缓存值(已反映过滤)
└── 为空(首次或无过滤):
→ 遍历 gridView 中所有**可见行**(gridView.RowCount)
→ 对每行调用 GetRowCellValue / GetRowCellDisplayText
→ SortedDictionary 去重排序
→ 填充 e.CheckedComboBox.Items
```
**联动关键**:每次遍历的是 `gridView` 中**当前可见的行**(已被其他列过滤筛选后的结果),天然实现了级联过滤效果。
**其他调用点**(共 6 处,模式相同):
- `OPEditXtraGrid.cs:405`
- `DefaultXGridView.cs:559`
- `frmViewDocDataLink.linkData.cs:248`
- `frmViewDocDataLink.cs:1407`
- `frmViewDocDataLink.cs:1673`
## 多维分析表格(PivotGrid)— PivotGridHelper + CustomFilterPopupItems
**入口**:`XWinLib.PivotGrid.PivotGridHelper.LoadPivotGridData(pivGridCtl, dsDetail.Tables[0], busObj, _PivotColList);`
**核心文件**:
| 文件 | 位置 | 作用 |
|------|------|------|
| `PivotGridHelper.cs` | `XWinLib\PivotGrid\` | PivotGrid 数据加载 + 过滤联动(**已实现**) |
| `PivotGridHelper_U10.cs` | `XWinLib\PivotGrid\` | U10 版本(**未实现联动**) |
| `PivotGridEx.cs` | `XWinLib\PivotGrid\` | PivotGrid 控件包装器(继承 DevExpress PivotGridControl) |
| `GridViewFilterHelper.cs` | `U.WinCtl\OpCtl\` | 参考实现(仅 GridView,非 PivotGrid) |
**联动实现**(`PivotGridHelper.cs`,`addDataToCtl` 方法中注册):
```
用户点击 FilterArea 字段的过滤下拉框
→ DevExpress 触发 CustomFilterPopupItems 事件
→ GridCtl_CustomFilterPopupItems 事件处理器:
→ ① 检查其他字段是否有激活的过滤条件(FilterValues.HasFilter)
→ 无 → 保持默认行为(显示全部值)
→ 有 → 继续
→ ② 获取底层 DataTable(pivotGrid.DataSource → DataView → DataTable)
→ ③ 为每个其他字段构建 DataTable.Select 过滤表达式(BuildFilterExpression)
- Included 类型: [FieldName] IN (val1, val2, ...)
- Excluded 类型:[FieldName] NOT IN (val1, val2, ...)
- 值格式化:字符串加引号 + 转义、DateTime 用 #...#、数值直接用 ToString
→ ④ 组合过滤条件(AND 连接),dt.Select(combinedFilter) 交叉过滤
→ ⑤ 从过滤后行中提取当前字段去重值(HashSet<string>)
→ ⑥ 从 e.Items 中移除不在去重集合中的项(倒序遍历 RemoveAt)
```
**关键差异(GridView vs PivotGrid)**:
| 维度 | GridViewFilterHelper | PivotGrid CustomFilterPopupItems |
|------|----------------------|----------------------------------|
| 联动机制 | 遍历可见行(天然联动) | DataTable.Select 手动交叉过滤 |
| 事件 | `ShowFilterPopupCheckedListBox` | `CustomFilterPopupItems` |
| 数据源 | `gridView.GetRowCellValue()` | `pivotGrid.DataSource` → DataView → DataTable |
| 值获取 | 按行索引逐行读取 | DataTable.Select 批量过滤后取列值 |
| 勾选状态 | 手动跟踪 `checkedItems` 列表 | DevExpress 原生管理 |
**注意事项**:
- `field.FilterValues.Values` 返回 `object[]` 数组(非 IList),使用 `.Length` 而非 `.Count`
- `PivotGridHelper_U10.cs`(U10 版本)尚未实现联动过滤,如需为 U10 版本表单添加联动,参考主版本 `PivotGridHelper.cs` 的实现
- `FilterArea` 字段的过滤才是复选框形式,RowArea/ColumnArea/DataArea 字段不走此逻辑
**其他项目已有类似实现**:
- `PDM_LN` 和 `YB_FX` 的 `PivotGridHelper.cs` 中已订阅 `CustomFilterPopupItems` 事件,但过滤值操作被注释掉(仅配置了弹出选项)
## 排查步骤
当遇到「多维表格过滤不联动」或「过滤下拉框显示值不对」时:
```
1. 确认表格类型:
→ 普通表格(GridView)→ 检查 GridViewFilterHelper 是否已附加
→ 多维表格(PivotGrid)→ 检查 PivotGridHelper 中 CustomFilterPopupItems 是否已注册
2. 多维表格联动排查:
→ 确认 LoadPivotGridData 是否被调用
→ 确认 addDataToCtl 中是否有 gridCtl.CustomFilterPopupItems += GridCtl_CustomFilterPopupItems
→ 检查 BuildFilterExpression 中 field.FilterValues.Values 的数据类型
→ 检查 DataTable.Select 过滤表达式中值格式化是否正确(字符串需加引号并转义)
3. 性能排查:
→ 数据量大时 DataTable.Select 可能较慢(每次弹出下拉框都全表扫描)
→ 可考虑缓存过滤结果或使用 DataView.RowFilter 替代
```
## 相关文件速查
```
网格过滤功能涉及文件:
├── U.WinCtl\OpCtl\GridViewFilterHelper.cs ← 普通表格复选框过滤联动(完整实现)
├── U.WinCtl\OpCtl\UP4XtraGrid.cs ← 普通表格数据绑定入口(调用 GridViewFilterHelper)
├── XWinLib\PivotGrid\PivotGridHelper.cs ← 多维表格数据加载 + 过滤联动(已实现)
├── XWinLib\PivotGrid\PivotGridHelper_U10.cs ← 多维表格 U10 版本(联动未实现)
├── XWinLib\PivotGrid\PivotGridEx.cs ← 多维表格控件包装器
└── XWinLib\Share\XmlCfgHelper.cs ← PivotGrid 列配置读取(ColPivotList)
```
# 父子单据联动机制(ParentProvider)
> 排查"为什么A单据产生了B任务"。当遇到"单据A保存后异常产生了单据B的任务/通知"类问题时,这是 ParentProvider 跟单联动机制在起作用。
**核心组件**:
| 组件 | 作用 | 位置 |
|------|------|------|
| `[ParentProvider]` 特性 | 声明式定义"谁是当前类的父级" | 业务类上方(AllowMultiple=true) |
| `IDataLinkObjRule.ParentDocType` | 运行时决定"当前数据属于哪个父级" | 业务类的属性实现 |
| `ORMappingByAttHelper.GetParentProviderAttByType()` | 路由方法:DocType → 匹配的 ParentProvider 特性 | `U.Rule/Share/ORMappingByAttHelper.cs` |
| `ObjectModefiedHelper.AfterSaveDate()` | 执行UPDATE:更新父级表的修改时间和状态 | `U.Rule/Share/ObjectModefiedHelper.cs` |
**工作链路**:
```
UI 保存 → BusinessObject.SaveObjectData()
→ ModefiedHelper.AfterSaveDate(busObj, ...)
→ pDocType = busObj.ParentDocType // ① 获取运行时父级类型
→ att = GetParentProviderAttByType(busObj, pDocType) // ② 路由匹配
→ if (att != null)
UPDATE {att.ProviderTableName} // ③ 更新父级表
SET B_MODIFIED_DATE, B_MODIFIED_MEMO='FollowDoc'
WHERE {att.KeyFieldName} IN (keys)
→ 跟单系统检测到父级表变动 // ④ 级联通知
→ 触发父级单据的跟单逻辑 → 产生任务
```
**排查步骤**:
```
1. 确认当前单据的 ParentDocType 返回值
→ 查看业务类中 ParentDocType get 属性
→ 不同业务场景可能返回不同的 DocType(如 UStockAssignTwo 按 StockAssignType 分支)
2. 查看类上所有 [ParentProvider] 特性声明
→ 在源码中检索(知识库内代码分析文档;本地工程目录需用户协助定位)
→ 注意:可能有被注释掉的旧特性(如 //[ParentProvider(OrderSendProject, ...)])
3. 校验路由匹配逻辑
→ 打开 ORMappingByAttHelper.GetParentProviderAttByType()
→ 检查是否存在硬编码 fallback(else if att.DocType == OrderSendProject)
→ 预期:ParentDocType 返回值应精确匹配某个 [ParentProvider] 的 DocType
→ 异常:ParentDocType 返回的 DocType 无对应特性,但被 else fallback 捕获
4. 确认父级表 UPDATE 是否执行
→ 在 AfterSaveDate 中查看 att.ForeingKeyField 是否为 null(null 时直接 return)
→ 外键字段存在于子表明细中时才会收集 keys 并执行 UPDATE
5. 追踪跟单通知链
→ 父级表被 UPDATE 后,跟单系统检测到变更
→ 通知父级单据 → 触发父级自身的跟单 → 产生任务
```
**常见问题模式**:
| 模式 | 症状 | 根因 | 修复 |
|------|------|------|------|
| **硬编码 fallback** | ParentDocType 返回 A,但路由到了 B 父级 | GetParentProviderAttByType 中 else if 无条件匹配 | 改为精确匹配优先,仅单父级类启用降级 |
| **注释残留** | 代码注释掉了一个 [ParentProvider],但运行时仍生效 | DLL 未重新编译/部署 | 检查 bin 目录中的 DLL 是否最新 |
| **ParentDocType 分支遗漏** | 新业务场景走 default 分支返回了错误的 DocType | ParentDocType 的 if/switch 未覆盖新场景 | 新增业务场景分支 |
| **外键字段为 null** | AfterSaveDate 不执行 UPDATE,但跟单仍被触发 | 问题不在 ParentProvider 链路上 | 检查是否有其他触发跟单的路径 |
**关键文件(修改时需谨慎)**:
| 文件 | 说明 |
|------|------|
| `U.Model/Att/ParentProviderAttribute.cs` | 特性定义(禁止随意修改) |
| `U.IFace/IDataLinkObjRule.cs` | ParentDocType 接口定义(禁止修改) |
| `U.Rule/Share/ORMappingByAttHelper.cs:1297` | **核心路由方法**(修改影响所有业务类) |
| `U.Rule/Share/ObjectModefiedHelper.cs:324-380` | **执行UPDATE**(修改影响所有单据保存) |
> **修改 ORMappingByAttHelper.GetParentProviderAttByType() 必须做全量影响分析**:在源码中检索 `[ParentProvider.*OrderSendProject` 找出所有声明了该父级的类,逐一验证其 ParentDocType 返回值能否精确匹配。
# 报表类模块 SQL 获取(三途径 — 按 SysFunction.Winform 分流)
> 旧范式认为报表模块"不走标准窗口加载、SysFunction 无记录"——实际**全部模块在 SysFunction 中都有记录**。区别在于 Winform 类型不同,SQL 定义来源也因此不同。
## 前置查询(所有途径共用)
```sql
SELECT sm.Name AS ModuleName, sf.Name AS WindowType,
sf.BusinessObject, sf.Winform, sf.AssemblyName
FROM SysBusinessModel sm
JOIN SysFunction sf ON sf.ModelID = sm.ID
WHERE sm.Name LIKE '%关键词%'
```
取得 `Winform` 和 `BusinessObject` 后,按以下三途径分流:
```
Winform = U.WinClientDoc.FrmRPTView → 途径 A:自定义报表
Winform = U.WinClient.SysSetting.FrmEditPreviewView → 途径 B:动态表结构定义
其他 Winform(Name = Form 无 View / 标准 View+编辑窗口) → 途径 C:普通业务模块
```
---
## 途径 A:自定义报表(Winform = FrmRPTView)
**特征**:`Winform = U.WinClientDoc.FrmRPTView`,`BusinessObject = U.Rule.Doc.Schedule`。基于存储过程,支持列头合并和字段级权限控制。
**SQL 定位**:四个表均通过 `ReportCode` 关联,由 `Schedule` 引擎逻辑按模块名或 ID 匹配。
| 表 | 作用 | 关键字段 |
|----|------|----------|
| `Sys_RPT_TableDef` | 主表 | `ReportCode`(主键)、`ReportName`(报表名/菜单名)、`CommandType`(一般是 `SP`)、`CommandText`(一般是存储过程名称) |
| `Sys_RPT_GridColumn` | 列配置 | `ReportCode`、`Caption`(显示名称)、`FieldName`(字段名)、`DataType`(字段类型)、`BandCode`(合并列头 UID) |
| `Sys_RPT_GridBand` | 列头合并 | `BandCode`(关联 GridColumn)、`Caption`(合并列头显示名称) |
| `Sys_RPT_Auth` | 权限控制 | `ReportCode`、`FieldName`(字段名)、`AuthCode`(`Edit` 可编辑 / `Visible` 可见)、`UserID`(用户 ID,仅该用户有此权限) |
### 排查步骤
```
1. 确认 Winform = FrmRPTView → 此模块为自定义报表
2. 通过模块名反查 ReportCode(db_query,无连接则给用户 SSMS 执行):
SELECT ReportCode, ReportName, CommandType, CommandText
FROM Sys_RPT_TableDef
WHERE ReportName LIKE '%模块名%'
→ 得到 ReportCode + CommandText(SP 名称)
3. 分析列配置(含合并列头):
SELECT gc.Caption, gc.FieldName, gc.DataType, gc.BandCode,
gb.Caption AS BandCaption
FROM Sys_RPT_GridColumn gc
LEFT JOIN Sys_RPT_GridBand gb ON gb.BandCode = gc.BandCode
WHERE gc.ReportCode = @ReportCode
ORDER BY gc.SortNo
4. 检查权限:
SELECT FieldName, AuthCode, UserID
FROM Sys_RPT_Auth
WHERE ReportCode = @ReportCode
→ AuthCode = 'Edit' 可编辑,'Visible' 可见
→ UserID 非空表示仅该用户有此权限
5. 数据排查 → 提取 CommandText(SP 名)→ db_query 执行
→ 用界面实际参数调用 SP,比对结果
→ 检查:SP 内部逻辑 / 参数过滤 / 权限过滤
6. 常见问题:
- SP 逻辑缺陷(关联/过滤/聚合错误)
- GridColumn 中 FieldName 与 SP 返回列名不匹配 → 列显示空
- GridBand 中 BandCode 写错 → 列头合并失效
- Sys_RPT_Auth 中 AuthCode 配置错误 → 用户看不到列或无法编辑
- 权限冲突(同一字段多条 Auth 记录,UserID 条件互斥)
```
---
## 途径 B:动态表结构定义(Winform = FrmEditPreviewView)
**特征**:`Winform = U.WinClient.SysSetting.FrmEditPreviewView`,`BusinessObject = U.Rule.SysSetting.UPreviewView`(或 UP4 变体,如 `UP4.Rule.SysSetting.UP4PreviewView`)。基于 SQL 动态生成表格。
**SQL 定位**:`UPreviewView` 引擎通过菜单名(`SysBusinessModel.Name`)匹配 `TableIdentic.TableText`。
| 表 | 作用 | 关键字段 |
|----|------|----------|
| `TableIdentic` | 主表 | `TableText`(表描述/模块名)、`SqlString`(查询 SQL 语句) |
| `TableDef` | 列定义 | `FieldName`(字段名)、`FieldType`(字段类型)、`Description`(显示名称) |
### 排查步骤
```
1. 确认 Winform = FrmEditPreviewView → 此模块为动态表结构定义
2. 通过模块名查 TableIdentic(db_query):
SELECT * FROM TableIdentic WHERE TableText LIKE '%模块名%'
→ 得到 SqlString(查询 SQL)
3. 分析列定义:
SELECT FieldName, FieldType, Description
FROM TableDef
WHERE TableIdenticID = @ID
ORDER BY SortNo
4. 数据排查 → 提取 SqlString → db_query 执行
→ 检查:WHERE 过滤条件 / JOIN 关联逻辑 / 子查询 / 聚合计算
5. 常见问题:
- SqlString 中硬编码了错误的过滤条件
- 关联表字段名拼写错误
- TableDef 中 FieldType 与实际查询列类型不匹配
```
---
## 途径 C:普通业务模块(其他 Winform)
**特征**:`Winform` 不是 `FrmRPTView` 或 `FrmEditPreviewView`。不走报表引擎,SQL 定义在 `ConfigFile` XML 中。
又分两类:
- **标准列表窗口**:`Name = View` 存在 → 按常规 dialect/erp/winforms.md 排查链路
- **直接弹窗基础模块**:`Name = Form` 但无 `View` → 按 dialect/erp/winforms.md 通用链路(窗口 → 业务类 → ConfigFile XML Sqls)排查
---
## 三途径速查表
```
SysBusinessModel JOIN SysFunction
↓ 取得 Winform
├── FrmRPTView → 途径 A → Sys_RPT_TableDef.CommandText(SP)
├── FrmEditPreviewView → 途径 B → TableIdentic.SqlString(SQL)
└── 其他 → 途径 C → ConfigFile XML Sqls 节点
├── Name = View 存在 → 标准列表窗口(dialect/erp/winforms.md)
└── Name = Form 无 View → 直接弹窗基础模块(dialect/erp/winforms.md)
```
This diff is collapsed.
This diff is collapsed.
# WinForms 排查(数据错误 / 程序异常 / 性能 / 约束)
> 适用:ERP / PDM / MES 桌面端(F1, U6_*, PDM_LN, MES_*, mes_geshiwei, PDM_MES, Ftt_Common 等)。
> 项目事实(数据库连接、模块加载机制)从知识库检索获取(kb_find / kb_grep / kb_read)。
> 排查任一步因信息不足卡住 → 按 dialect/troubleshoot-core 五步法第 1 步收集证据:向用户索要关键信息(报错全文/操作步骤/日志文件),或建议补强(加异常堆栈日志 / 调试打点)。
## 取证工具
- 查库:`db_query`(SELECT-only)/ `db_schema`,需先在设置中预存连接(connectionId)。
- 无预置连接时:把 SQL 给用户在 SSMS 执行,取回结果再分析。
- 读代码:源码检索(知识库内代码分析文档;本地工程目录需用户协助定位)。
## WinForms 数据错误排查
### 快速分流
```
库存类问题(入库/出库/调拨/盘点/结存/进销存)
→ 先查 `view_MaterialStockDocFlow` 流水视图定界
→ 按 MaterialID + Warehouse + 日期范围查流水,比对各单据类型汇总数 vs 界面展示
→ 确认差异后再按单据类型追踪到具体源表:
入库 → StockIn + StockInDetail
出库 → StockOut + StockOutDetail
调拨 → StockAssign + StockAssignDetail
盘点 → StockBalance + StockCheck + StockCheckDetail
→ 仍无法定位 → 走下方通用流程步骤 1
```
### 通用排查流程
```
1. 确认问题窗口
→ 让用户提供:哪个模块的哪个窗口?
→ 查数据库:
SELECT sm.Name AS ModuleName, sf.Name AS WindowType,
sf.BusinessObject, sf.Winform, sf.AssemblyName
FROM SysBusinessModel sm
JOIN SysFunction sf ON sf.ModelID = sm.ID
WHERE sm.Name LIKE '%关键词%'
→ 得到:AssemblyName(项目), BusinessObject(业务类), Winform(窗口类)
→ 按 Winform 值分流:
- FrmRPTView → 途径 A:自定义报表(读 dialect/erp/special-modules.md)
- FrmEditPreviewView → 途径 B:动态表结构定义(读 dialect/erp/special-modules.md)
- 其他 → 途径 C:普通业务模块(继续下方步骤 2)
2. 定位源码
→ BusinessObject 全限定名 = 项目下文件夹路径 + 文件名
→ 如 U.WinClientDR.BO.DR_BO_Order → U.WinClientDR 项目下 BO/DR_BO_Order.cs
3. 找到配置 SQL
→ 查看业务类中 OBJECT_xx 常量 → 定位 ConfigFile XML
→ 找到 Sqls 节点中问题相关的 SQL(按 Name 匹配)
4. 数据库验证
→ 截取 SQL + 从 temp/(日期)App.Run.Log 获取实际参数
→ db_query 执行(无连接则给用户 SSMS 执行),比对结果与界面展示
→ 分析:过滤条件 / JOIN / GROUP BY / 子查询
5. 根因判定
→ SQL 逻辑缺陷 / 数据脏数据 / 并发覆盖 / XML 配置错误 / 复制后遗症
```
## WinForms 程序异常排查
```
1. 获取错误 → temp/(日期)App.Run.Log → Exception 段落 → 堆栈最上层
2. 分类处理:
空引用 → 构造方法/Load 事件/数据查询后未初始化 → 数据库返回 NULL / XML 缺节点
反射失败 → SysFunction 中信息是否正确 / DLL 是否部署 / 复制后是否重命名完整
类型转换 → ConfigFile Columns 节点类型 vs 数据库实际字段类型
3. 卡住处理(信息不足 / 无堆栈 / 现象模糊 / 日志缺失):
→ 向用户索要关键信息(报错全文/复现步骤/App.Run.Log)
→ 建议补强:异常堆栈日志 / 调试打点(先确认再改代码)
```
## WinForms 性能问题排查
```
1. 定位慢环节 → 列表打开/编辑加载/保存?→ 查看日志耗时
2. 列表慢 → 定位查询 SQL → SSMS 执行计划 → 缺失索引/全表扫描
3. 保存慢 → 检查存储过程/触发器/级联更新
```
## 数据库约束异常排查(WinForms 侧)
```
1. 获取完整错误 → temp/(日期)App.Run.Log 中的异常信息
2. 提取约束名和表名 → 找出违反约束的数据
3. 追踪数据来源 → 业务链路上溯到写入点
常见类型:违反唯一性约束(主键/唯一索引冲突)/ 值检查约束(CHECK)/ 外键约束
```
# MES 产品线热点问题统计(归因模式库)
> 涵盖:MES_*, mes_geshiwei, PDM_MES。每次排查确认根因后由维护者追加。
> 通用桌面端排查链路(窗口→业务类→SQL/SP→数据库)见 dialect/erp/winforms.md。
> 最后更新:2026-08-14
## 成型配套汇总查询(Summary_PartTaskReport / GetStyleIndexNo_CXPT)
### 合计行小于明细行之和
- **分类**:数据错误
- **根因**:合计 UNION 按 `GROUP BY SizeName, SizeSN` 生成 + 最终 `PIVOT (MAX(Qty))` 折叠,多指令查询时同尺码多行被 MAX 吞减(SN 为指令内序号,跨指令不唯一)
- **归因模式**:**聚合键跨上下文不唯一**——UNION 合计与明细用同一 GROUP BY 键,但键只在单指令内唯一;多指令场景被 MAX/折叠吞数。排查「合计<明细」先核对聚合键的唯一性域。
# MES 查询模板(产品线方言)
> 四库通用模板见 `dialect/sql-core/sql-templates.md`;本文件仅 MES 产品线专属查询。
> 表前缀速查:`MES_*` MES 制造执行 / `Order*` ERP 订单 / `Factory*` 工厂车间 / `OrderDocImport*` 订单导入。
## 生产订单-订单关联(查指令的款式/车间)
```sql
SELECT ppd.IndexNo, ppd.StyleCode, a.CustomStyleCode,
b.WorkSectionID, ws.Name AS SectionName
FROM MES_ProductionPlanDetail ppd
INNER JOIN OrderDocImportPlanDetail b ON b.ID = ppd.OrderDetailID
INNER JOIN OrderDocImportDetail a ON a.ID = b.OrderDocImportDetailID
LEFT JOIN FactoryWorkSection ws ON ws.ID = b.WorkSectionID
WHERE ppd.IndexNo LIKE '%关键词%'
AND (a.StyleCode LIKE '%关键词%' OR a.CustomStyleCode LIKE '%关键词%')
```
## 检验批次汇总(查不良明细)
```sql
SELECT ir.ID, ir.InspectionQty, qid.QIItemName,
ird.Qty AS DefectQty, wt.Name AS TeamName
FROM MES_InspectionReport ir
INNER JOIN MES_InspectionReportDetail ird ON ird.InspectionReportID = ir.ID
INNER JOIN MES_QIDetail qid ON qid.ID = ird.QIDetailID
LEFT JOIN FactoryWorkShopTeam wt ON wt.ID = ir.TeamID
WHERE ir.CreateDate >= @StartDate
```
## 尺码明细(查指令的尺码数量)
```sql
SELECT sd.SizeName, sd.Qty, ppd.IndexNo
FROM MES_ProductionPlanSizeDetail sd
INNER JOIN MES_ProductionPlanDetail ppd ON ppd.ID = sd.ProductionPlanDetailID
```
## 订单附加数据(预补数等)
```sql
SELECT ad.AddCount, tp.Name AS AddTypeName
FROM OrderDocImportDetailAddData ad
INNER JOIN FTT_U6.dbo.OrderAddDataType tp ON tp.ID = ad.OrderAddDataTypeID
INNER JOIN OrderDocImportDetail a ON a.ID = ad.OrderDocImportDetailID
```
## 注意
- MES 库与 ERP 库跨库关联时显式写库名(如 `FTT_U6.dbo.OrderAddDataType`),先确认当前连接库。
- 跨库查询需确认账号有对应库权限;无权限时分别查询后在结果侧关联。
# PDM 产品线热点问题统计(归因模式库)
> 涵盖:PDM_LN, LNCenterApi。每次排查确认根因后由维护者追加。
> 通用桌面端排查链路(窗口→业务类→SQL/SP→数据库)见 dialect/erp/winforms.md。
> 最后更新:2026-08-14
## 季节材料汇总表(RPT_SessionMaterialPrice)
### 报表查询慢(>3分钟)
- **分类**:性能
- **根因**:① SP 主查询 3 个相关子查询(STUFF+FOR XML PATH)对无索引临时表全表扫描拼接,工作量=分组数×行数×3(单季度约 8.9 亿次),单季查询数分钟;② SP 返回后客户端用 BeginInvoke+递归串行按批(每批 100 ID)查询 `Sys_StyleConditionDetail`/`Sys_ReportComment`,几十批串行,额外约 30 秒
- **修复**:① 临时表建覆盖索引 + 三个拼接列预去重,SP 提速约 120 倍(>5 分钟→2.5 秒);② 客户端改为一次性拆批 + 受限并发(最多 8 并发);③ 拼接索引键改 MD5 hash,拼接键 UPPER+RTRIM+全角转半角规范化对齐 collation,消除 nvarchar(8000) 索引键超长风险
- **归因模式**:**XML PATH 拼接全表扫描 + 串行批查询**——报表慢先看两个层面:SP 内拼接子查询是否打爆临时表;客户端回填是否串行按批查询。优化方向:覆盖索引/预去重/受限并发。
## 高危风险评估(RK_RiskAssessment)
### 更新模式追加明细保存时 @RiskAssessmentID=0(明细外键没拿到主单ID)
- **分类**:数据错误
- **根因**:明细外键由框架 `SaveDataByObjectDataType` 用主单 ID(mainID)回填,mainID 来自 `_ObjectDataList[BaseData]["ID"]`;更新模式下该行 ID 失效(re-fetch 失败 / 阶段切换 drNext 陈旧未复位 / OptType 误入新增分支),导致 mainID=0 透传成 @RiskAssessmentID=0
- **归因模式**:**主单 ID 回填失效**——「新增正常、更新/编辑模式保存外键为 0」先检查主单 ID 获取路径在更新模式下是否失效(re-fetch/阶段切换/OptType 分支)。
# SQL 脚本生成规范
## 生成与落盘
- 模型生成变更类 SQL 时,产出 `.sql` 脚本文件,落盘到 `Agent/output/sql/`(kb_write 沙箱)。
- **不直接对业务库执行**变更语句(SELECT 查询用 db_query / 结构分析用 db_schema / 计划用 SSMS)。
- 文件名规范:`<动作>_<对象>_<描述>.sql`,如 `AddColumn_Orders_Remark.sql`、`FixData_OrderStatus.sql`。
## 内容规范
1. 顶部注释头(见 sql-style.md:名称/用途/执行人/日期/可重复执行)。
2. 变更语句**幂等**(IF NOT EXISTS / 先查后改)。
3. 数据修正类脚本先给影响行数查询,再给变更语句,最后给验证查询。
4. 脚本用 CRLF 换行,UTF-8 编码。
## 模板
```sql
-- 脚本名称:FixData_OrderStatus
-- 用途:修正订单状态异常数据
-- 执行人:xxx 日期:2024-09-01
-- 可重复执行:是
-- 1. 影响范围核对
SELECT OrderNo, Status FROM dbo.Orders WHERE Status = 'X';
-- 2. 修正
UPDATE dbo.Orders SET Status = 'Y' WHERE Status = 'X';
-- 3. 验证
SELECT OrderNo, Status FROM dbo.Orders WHERE Status = 'X'; -- 期望 0 行
```
## 方言差异提示
- sqlserver:IDENTITY/新增列用 `ALTER TABLE ... ADD` + 幂等判断;NVARCHAR。
- sqlite:`ALTER TABLE ADD COLUMN` 有限制(不能加主键/非空默认复杂值);先 PRAGMA 检查。
- mysql/postgres:类型/引号差异按库适配。
# SQL 格式化规范
## 换行
- **默认以 CRLF 换行**(Windows 标准;与公司既有脚本一致)。
- 禁止在同一文件混用 LF/CRLF。
## 结构
- 关键字大写:`SELECT`、`FROM`、`WHERE`、`JOIN`、`GROUP BY`、`ORDER BY`、`INSERT`、`UPDATE`、`ALTER`。
- 单条语句内缩进 4 空格;子查询/JOIN 条件换行对齐。
- 每张表一个别名(可读性优先):`FROM dbo.Orders o`。
## 注释头(脚本必带)
```sql
-- 脚本名称:AddColumn_Orders_Remark
-- 用途:订单表增加备注列
-- 执行人:xxx 日期:2024-09-01
-- 可重复执行:是(IF NOT EXISTS 幂等)
```
- 变更类脚本(加列/改表/改数据)必须写注释头:名称/用途/执行人/日期/是否可重复执行。
- 查询类(SELECT)不强制,但复杂查询建议注明用途。
## 其它
- 行尾不留空格;文件末尾一个换行。
- 字符串用单引号;标识符含保留字时用方括号(sqlserver)或双引号(其他库)。
- 禁止 `SELECT *` 之外的无条件 UPDATE/DELETE(先查影响行)。
# SQL 查询模板(四库通用)
> 可重复执行原则:所有脚本/查询必须以幂等方式编写——重复执行结果一致、不报错、不产生重复数据。
## 加列(可重复执行)
```sql
-- sqlserver:先查再改(存在才加)
IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID('dbo.Orders') AND name = 'Remark')
ALTER TABLE dbo.Orders ADD Remark NVARCHAR(200) NULL;
```
```sql
-- sqlite:PRAGMA 查询列名,不存在才 ALTER
SELECT COUNT(*) FROM pragma_table_info('Orders') WHERE name = 'Remark';
-- 结果 = 0 时执行:
ALTER TABLE Orders ADD COLUMN Remark TEXT;
```
## 更新前先查(核对影响行)
```sql
SELECT COUNT(*) FROM dbo.Orders WHERE Status = 'X'; -- 先看影响范围
```
## 报表/核对查询
```sql
SELECT o.OrderNo, o.Amount, SUM(d.Qty) AS TotalQty
FROM dbo.Orders o
LEFT JOIN dbo.OrderDetails d ON d.OrderId = o.Id
WHERE o.OrderDate >= '2024-01-01'
GROUP BY o.OrderNo, o.Amount
HAVING o.Amount <> SUM(d.Qty) -- 核对金额与明细不一致
ORDER BY o.OrderNo;
```
## 分页(sqlserver OFFSET-FETCH / sqlite LIMIT)
```sql
SELECT * FROM dbo.Orders ORDER BY Id OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY; -- sqlserver
SELECT * FROM Orders ORDER BY Id LIMIT 50 OFFSET 0; -- sqlite/mysql/postgres
```
## 执行计划(定位慢查询)
```sql
EXPLAIN QUERY PLAN SELECT ... ; -- sqlite
EXPLAIN SELECT ...; -- mysql
EXPLAIN ANALYZE SELECT ...; -- postgres
-- sqlserver 用 SSMS 执行计划(或 db_query 验证数据分布)
```
# 排查五步法
> 对齐系统化调试方法论(根因先行,禁止症状修复)。
## 第 1 步:复现与证据
- 完整读报错信息:堆栈全文、行号、文件路径、错误码(错误信息常含直接答案)。
- 稳定复现:能否稳定触发?触发步骤是什么?每次都出现吗?
- 不能复现 → 收集更多数据(日志/截图/现场),**不猜**。
- 检查近期变更:代码提交、配置、数据、环境差异。
## 第 2 步:链路定位(桌面端业务链路)
```
窗口/界面 → 业务类/Controller → SQL/SP → 数据库
```
- 沿链路逐层取证(`db_query` / `db_schema` / 文件读取)。
- **每一层边界记录**:什么数据进入、什么数据出去、状态/配置是否传递。
- 一次取证找出**在哪一层断**,再深入那一层(不要全链路乱翻)。
## 第 3 步:模式对比
- 找可用的同类链路/相似功能作为对照(「什么能用、和坏的很像」)。
- 对照参考实现时**完整读**(不扫读),列出每一个差异(哪怕很小)。
- 不假设「那个差异不可能有关」。
## 第 4 步:单一假设 + 最小验证
- 明确写出假设:「我认为 X 是根因,因为 Y」。
- 用**最小改动**验证一个变量;一次只验证一个假设。
- 验证不通过 → 形成新假设,**不要在失败修复上叠加修复**。
## 第 5 步:根因修复
- 先造**失败用例**(自动化测试优先;无框架则一段复现脚本)——必须在修复前有。
- 一次只改一处(无「顺手优化」、无捆绑重构)。
- 验证:用例通过?其他用例没坏?问题真正消失?
- **已试 3 次仍失败 → 停止并质疑架构**:每个修复都暴露新耦合/新问题、修复需「大重构」、每修一个又出新的 → 与用户讨论是否重构架构,而非继续第 4 次硬试。
## 环境/外部因素
若系统排查确认是环境、时序或外部因素(95% 的「无根因」是调查不完整,先自查):
1. 记录已调查内容;2. 做合理处理(重试/超时/明确报错);3. 加监控便于后续定位。
# 排查输出规范
回答排查类问题时,按以下结构输出:
```markdown
【任务类型】数据错误 / 程序异常 / 性能 / 约束 / 模块分析
【追踪链路】窗口/接口 → 业务类/Controller → SQL/SP → 数据库
【根因定位】一句话根本原因(必须基于证据,禁止臆断)
【证据链】取证过程(哪一层、用了什么工具、得到什么)
【修复建议】具体修改方案(含文件/配置/SQL)
【影响范围】可能受影响的关联功能
【测试数据】验证用关键记录 / 测试 SQL
```
## 要求
- **根因一句话**:能说清「什么环节、因为什么、导致什么」。
- **证据链可回溯**:每步结论标注来源(文件路径/查询结果/计划),读者能复现。
- **不确定要明说**:证据不足时明确「尚未确认 X」,给下一步取证建议,不编造。
- **修复建议可执行**:具体到文件/字段/SQL;附验证方式(失败用例先造)。
- 排查完的典型案例可经用户确认后整理进 dialect 热点案例(内置只读,由维护者落盘)。
# 凉鞋与拖鞋
## 品类细分
- **EVA 注塑拖鞋**:一体注塑成型,轻量防水,居家/沙滩/酒店用。
- **PVC 发泡拖鞋**:成本低,冬季凉拖/浴室拖。
- **凉鞋**:帮面(织带/皮革/超纤)+ 大底(EVA/橡胶),分平底与坡跟。
- **沙滩鞋/涉水鞋**:速干面料+排水结构+防滑底。
## 工艺特点
- **注塑成型**:模具合模注射(EVA 交联发泡或 PVC),一双一双成型,模具成本高但单双成本低。
- **冷粘**:凉鞋帮面与大底胶粘,款式变化灵活。
- 大底防滑纹路设计(排水槽/人字纹)是卖点与质检点。
## 业务要点
- 季节性强(夏季爆量),产能集中在 Q1-Q2 备货。
- 注塑款模具管理重要(模具编号/寿命/存放)。
- 尺码跨度大(成人 34-46),码重成本差异小。
# 劳保鞋
## 品类细分
- **安全鞋**:防砸(钢包头/复合包头,耐冲击≥200J 等级)、防刺穿(防刺中底)。
- **绝缘鞋**:电绝缘(6kV/10kV 等级),禁止金属部件外露。
- **防静电鞋**:表面电阻/体积电阻控制,用于电子/化工车间。
- **耐油/耐酸碱鞋**:特种材质鞋底与帮面。
- **户外/矿山劳保靴**:高帮、耐磨耐折。
## 标准与认证(国内)
- **GB 21148**《足部防护 安全鞋》:防砸/防刺穿/防静电/电绝缘等安全性能通用要求。
- 需第三方检测报告(SGS/CTI 等),出欧盟 CE 需 EN ISO 20345 系列。
- 钢包头:GB 21148 规定冲击能量 200J 与压缩 15kN 试验。
## 工艺特点
- 帮面常用:头层牛皮/二层牛皮(耐摩擦)、超纤、帆布(轻便款)。
- 大底:橡胶/聚氨酯(PU)双密度(中底缓震+外底耐磨防滑)。
- 成型:冷粘或硫化(橡胶大底硫化结合强度高,耐油款常用)。
- 中底防刺层:钢板/凯夫拉(Kevlar)复合中底。
## 业务要点
- 证书与检测报告是接单必要条件(客户验厂/验货重点)。
- 鞋码偏大(欧码),内长标注重要。
- 单量稳定但品类固定,翻单率高。
# 皮鞋与休闲鞋
## 品类细分
- **正装皮鞋**:头层牛皮帮面、真皮/橡胶大底、固特异沿条工艺(可换底)。
- **休闲皮鞋**:胶粘工艺为主,超纤/二层皮帮面,EVA/橡胶底。
- **商务休闲鞋**:轻量软底,飞织+皮革拼接。
## 材料
- 帮面:头层牛皮(粒面/修面)、二层牛皮(剖层贴膜)、超纤(PU 涂层的仿皮,物性稳定)、PU 革。
- 内里:猪皮/羊皮里(透气)、超纤里、织物里。
- 大底:真皮底(固特异)、橡胶、PU、TPU(耐磨止滑)。
## 工艺特点
- **固特异(Goodyear)**:沿条+缝线+软木填充,可换底、耐穿,工艺链长(绷帮→沿条→缝线→上底)。
- **胶粘(Cemented)**:绷帮后直接胶粘大底,主流工艺,周期短。
- **绷帮**:鞋面套楦定型,决定鞋型美观与合脚度(绷帮不良→歪楦/开胶)。
## 业务要点
- 真皮采购有批差/色差(缸差),同款多批次需预留配色余量。
- 皮鞋尺码偏大,内长标注;半码需求多。
- 固特异款交期长(工艺链长),报价高。
# 童鞋
## 品类细分
- **学步鞋(1~3 岁)**:软底、轻量、易弯折,鞋头宽敞保护脚趾。
- **机能鞋(3~6 岁)**:足弓支撑、后跟加固,纠正步态。
- **中大童鞋(6~12 岁)**:接近成人鞋结构,运动款为主(校园/日常)。
- **婴幼鞋(<1 岁)**:防掉跟、无鞋带,装饰件最少化。
## 安全标准(国内重点)
- **GB 30585**《儿童鞋安全技术规范》:物理安全(小附件抗拉、锐边)与化学安全(六价铬、可分解致癌芳香胺、甲醛、重金属限量)。
- 小附件(鞋带扣/装饰件)拉力 ≥70N 测试,防脱落误吞。
- 童鞋号型按 GB/T 3293(内长制),鞋内腔尺寸必须标注。
## 工艺特点
- 成型:注塑一体成型占比高(EVA/TPU/橡胶注塑),成本低、无胶水污染。
- 帮面:网布/飞织/超纤/帆布,避免小颗粒装饰。
- 大底:EVA(轻)或橡胶(防滑),学步鞋强调 1/3 处易弯折。
## 业务要点
- 检测报告(GB 30585 全套)是商超/电商平台入驻门槛。
- 款式多、单款量小、翻单快,对开发与排产柔性要求高。
- 尺码分段(段码)管理:婴幼段/小童段/中童段/大童段,BOM 按段码区分。
# 运动鞋
## 品类细分
- **跑步鞋**:缓震中底(EVA/TPU/超临界发泡),网布/飞织鞋面,轻量化。专业跑鞋分缓震/支撑/竞速。
- **篮球鞋**:高帮包裹、防侧翻(TPU 抗扭转片)、耐磨大底(橡胶/人字纹)。
- **足球鞋**:鞋钉(FG/SG/AG/TF 按场地)、触球面材料(袋鼠皮/超纤/合成革)。
- **综训/休闲运动鞋**:通用缓震+稳定结构,鞋面网布+合成革拼接。
## 工艺特点
- 主流成型路线:**冷粘**(占多数,鞋面+大底胶粘,工艺灵活)与**注塑**(PVC/TPU/EVA 一体成型,多用于童鞋/拖鞋)。
- 飞织鞋面:一体织造无裁片,减少针车工序,需热熔贴合支撑片。
- 大底常见组合:EVA 中底 + 橡胶外底(耐磨防滑)。
## 业务要点
- 开发节奏快(季度上新),样品确认(确认样/船头样)是关键节点。
- 尺码体系:欧码(EU)/美码(US)/英码(UK)换算,半码/整码分布影响 BOM 与排产。
- 配色多(每款多色),材料单耗按配色分别核算。
# 包装与入库
## 包装流程
- **配对**:左右脚配对(同码同色,色差/号码核对),补单件。
- **装盒**:内衬/纸盒/防潮剂;盒标(款号/颜色/尺码/条码)。
- **装箱**:箱规(每箱双数,如 12/24 双)、外箱唛(毛净重/箱号/款号)。
- **吊牌/三标**:洗标/主标/尺码标齐备(三标错漏属外观不良)。
## 入库
- 成品仓按款/色/码/批次入库,批次追溯(生产批→原材料批)。
- 尾数管理:订单完成后未销完的零头数量(库存尾数/生产尾数),需单独标识与处理。
## 排查要点(数据不对时)
- 箱规与实际装箱不符 → 出货数量差异(装盒/装箱环节)。
- 配对错误(鸳鸯鞋)→ 质检漏检(OQC 抽检比例不足)。
- 批次混放 → 追溯断链(先入库先出库原则)。
# 成型工艺
> 鞋类最后成型(贴合/上底),三大路线决定设备、胶水、交期与成本结构。
## 冷粘(Cemented)——主流
- 流程:鞋面套楦(绷帮)→ 刷处理剂/胶水(鞋面+大底)→ 烘箱活化 → 贴合 → 压合 → 冷定型。
- 特点:工艺灵活、款式切换快;胶水环保要求高(水性胶替代油性胶)。
- 常见:运动鞋、休闲鞋、凉鞋。
## 硫化(Vulcanized)
- 流程:生胶大底贴鞋面 → 硫化罐加温加压(硫磺交联)→ 橡胶熟化成型。
- 特点:橡胶大底与鞋面结合强度高、耐油耐磨;工艺链长、周期长。
- 常见:劳保鞋(耐油款)、帆布硫化鞋(经典款)。
## 注塑(Injection)
- 流程:模具合模,PVC/TPU/EVA 注射成型,大底与鞋面一体或直接成型。
- 特点:无胶水、效率高、成本低;模具投入大。
- 常见:童鞋、拖鞋、凉鞋、劳保鞋(PU 注塑底)。
## 绷帮(Lasting)
- 鞋面套楦定型工序(三大路线共用前置),决定鞋型与合脚度。
- 常见方式:手工绷帮/机器绷帮(绷帮机);后跟定型/包头定型。
## 排查要点(质量问题)
- 开胶:处理剂/胶水工艺参数(温湿度、活化温度)或大底材质污染。
- 歪楦/不对称:绷帮不正、楦头配对错误。
- 溢胶/缺胶:贴合对位、压合力与时间。
- 成型产能:成型线节拍 = 瓶颈,排产与交期核心。
# 裁断与针车
## 裁断
- **裁片**:按唛架排版裁剪出的面料片(鞋面/内里/衬片)。
- **唛架(Marker)**:裁剪排版图,决定面料利用率(利用率=裁片面积/用料面积)。
- **裁断设备**:液压裁断机(刀模冲裁)/电脑裁床(多层)。
- 要点:刀模管理(编号/寿命)、错裁/色差片隔离、余料利用。
## 针车(鞋面缝制)
- **针数**:每英寸针数(针织密度指标,影响手感与强度,常规 8~12 针/英寸)。
- 工序:合缝(帮片拼接)→ 压线 → 包边 → 装饰线 → 缝标(洗标/主标/尺码标)。
- 设备:单针/双针平缝机、花样机、包边机。
- 要点:针距均匀、线色匹配、跳针/断针记录(IPQC 巡检点)。
## 排查要点(数据不对时)
- 裁片损耗:实际裁断用量 vs BOM 单耗(损耗率是否漏加/多加,行业常见 3%~8%)。
- 针车产能:瓶颈工序负载(针车工位数量×效率 vs 排产)。
- 色差:不同缸次面料混裁混缝 → 同双色差(IQC 与仓库批次追溯)。
# BOM 与单耗
## 核心概念
- **BOM(物料清单)**:鞋款的结构化物料清单——面料/辅料/配件/大底/中底/鞋垫/包装,含单耗与用量单位。
- **单耗**:单双鞋的物料用量(如鞋面材料按平方英尺/码/米,大底按双,织带按米)。
- **损耗率**:裁断损耗/缝制损耗计入材料成本(行业常见 3%~8%,按面料弹性与排版;皮料按伤残率更高)。
- **BOM 版本**:样品 BOM → 确认样 BOM → 量产 BOM,版本与变更记录(ECN)管理。
## 核算链路
```
BOM(面料/辅料单耗×单价) + 工价(工序×工价) + 制费分摊 + 损耗加成
→ 制造成本 → + 管理/销售费用 → 完全成本 → 报价
```
## 排查要点(数据不对时)
- **单耗 vs 实际用量**:BOM 单耗与裁剪实际用量是否一致(损耗率是否漏加/多加)。
- **单价来源**:面料单价是否按最新采购价(价差未更新 → 成本虚高/虚低)。
- **工价版本**:工序工价表是否与当前工艺单版本一致。
- **分摊口径**:制费分摊基数(产量 vs 工时)是否与成本中心配置一致。
- **BOM 缺失/错挂**:配色多时按配色 BOM 区分,错挂导致材料计划偏差。
# 鞋底材料
## 大底/中底材料
- **RB(橡胶)**:耐磨、止滑、耐油,外底常用(人字纹/水波纹);硫化工艺用生胶。
- **EVA**:轻量、缓震,中底主流(发泡密度决定软硬度);成本低,压缩永久变形偏大。
- **PU(聚氨酯)**:缓震回弹好、耐疲劳,中底/整底;怕水解(储存环境要求)。
- **TPU**:高回弹、耐折、耐磨,中底/外底/结构件(抗扭转片);成本高。
- **MD(Phylon)**:EVA 二次发泡(射坯发泡),轻量回弹好,运动鞋中底。
- **PVC**:低成本,拖鞋/凉鞋注塑;低温变硬。
## 结构件
- 抗扭转片(TPU/碳板)、防刺穿中底(钢板/凯夫拉——劳保鞋)、鞋垫(EVA/乳胶/ortholite)。
## 排查要点(数据不对时)
- 单耗:大底按双计(一双两件:左+右),模具腔数决定单位产出。
- 密度/硬度规格:发泡密度波动影响克重与缓震(物性测试项)。
- 橡胶 vs 发泡类物料管理差异:橡胶需防硫化时间超期,EVA 发泡片需熟化期。
# 鞋面材料
## 织物类
- **网布(Mesh)**:透气,运动鞋鞋面主材;按纱线分涤纶网布/尼龙网布,强度与透气权衡。
- **飞织(Flyknit)**:一体织造鞋面,无裁片、轻量、贴合;需热熔丝/支撑片补强。
- **帆布**:棉/涤帆布,硫化鞋/休闲鞋经典材料,耐磨耐折。
## 皮革类
- **头层牛皮**:粒面/修面,正装皮鞋;需注意缸差与伤残。
- **二层牛皮**:剖层贴膜(PU 涂层),性价比。
- **超纤(Microfiber)**:PU 涂层的仿皮,物性稳定、色牢度好、环保,运动/休闲大量使用。
- **PU 革/合成革**:低成本,需关注耐磨与低温耐折。
## 辅料
- 织带/松紧带/鞋带、五金(鞋眼/扣具/装饰件——童鞋小附件拉力要求)、热熔胶膜(补强/贴合)、衬片(港宝:后跟定型片)。
## 排查要点(数据不对时)
- 单耗:鞋面材料单耗按唛架排版核算(利用率),实际裁断用量 vs BOM 差异定位损耗口径。
- 色差:不同缸次/批次混用(缸差),IQC 检验记录与仓库批次追溯。
- 缩水率:面料水洗/热缩参数影响裁片尺寸(工艺单参数核对)。
# 报价与成本
## 核心概念
- **料(直接材料)**:鞋面/内里/大底/中底/辅料/包装成本 = 单耗 × 单价。BOM 是核算基准。
- **工(直接人工)**:工价 × 标准工时(按工序:裁断/针车/成型/包装)。
- **费(制造费用)**:车间折旧/水电/管理分摊,按产量或工时摊入。
- **损耗率**:裁断损耗/缝制损耗计入材料成本(常见 3%~8%,皮料更高)。
- **报价口径**:FOB(离岸价)不含运费保险;CIF 含。报价 = 料 + 工 + 费 + 毛利 + 税费。
## 鞋业核算链路
```
BOM(面料/辅料/大底单耗×单价) + 工价(工序×工价,按成型路线差异) + 制费分摊 + 损耗加成
→ 制造成本 → + 管理/销售费用 → 完全成本 → 报价
```
## 排查要点(数据不对时)
- **单耗 vs 实际用量**:BOM 单耗与裁剪实际用量是否一致(损耗率是否漏加/多加)。
- **单价来源**:面料单价是否按最新采购价(价差未更新 → 成本虚高/虚低)。
- **工价版本**:工序工价表是否与当前工艺单版本一致(成型路线变化影响工价)。
- **分摊口径**:制费分摊基数(产量 vs 工时)是否与成本中心配置一致。
- **汇率**:外购件按采购币种折算是否使用正确汇率日期。
# 接单与订单评审
## 流程要点
1. **接单**:客户订单(款号/颜色/尺码/数量/单价/交期/贸易条款)。
2. **评审**:产能可接?物料齐套?报价覆盖成本?交期可行?(鞋业加评:材料到位周期、模具状态、检测证书齐备)
3. **下单**:订单转工单,生成 BOM 与工艺单(含缩水率/唛架/工序工价)。
## 鞋业评审要点
- **模具**:注塑款模具是否就绪(新模/修模状态);硫化款鞋底模具腔数。
- **材料**:特殊材料(真皮/飞织纱线/防刺中底)采购周期长,需提前备料确认。
- **检测**:劳保鞋/童鞋需检测报告(GB 21148 / GB 30585),出证周期 2~4 周,订单评审必须覆盖。
- **配色**:多配色订单按配色分别评审材料齐套。
## 排查要点
- 订单未流转:查评审状态字段(待评审/评审通过/已下单)与审批节点。
- 数量差异:接单数量 vs 工单数量 vs 出货数量核对(尾数/损耗加成口径)。
- 交期冲突:同款多订单产能重叠 → 排产冲突。
# 翻单与交期
## 核心概念
- **翻单**:老款/老订单再次下单生产(材料与模具齐备,交期短)。
- **交期承诺**:下单日 → 打样 → 备料 → 生产 → 出货(制鞋典型周期 45~90 天;翻单可缩短至 30~45 天)。
- **产能与排产**:按产线/工序产能排产;瓶颈工序(针车/成型)决定节拍。
- **齐套**:面料/辅料/大底/配件齐套后才投产(缺料 = 排产延迟主因)。
- **跟催**:交期预警(逾期/临期清单)→ 催料/调产能/插单。
## 排查要点(交期延误)
- **缺口定位**:交期延误先定位「承诺交期 vs 实际」差在哪一环(打样/备料/生产/出货)。
- **齐套率**:物料齐套率不足 → 查采购到货计划与缺料清单。
- **产能占用**:插单/急单占用瓶颈产能 → 查排产甘特/产能负载。
- **工序异常**:返工/停线 → 查质量问题与设备故障记录。
- **数据口径**:交期承诺是否按「工作日 vs 自然日」计算(口径不一致是常见根因)。
## 关键术语
- 交期(Delivery Date)/ 承诺交期(Promise Date)
- 齐套率(Kit Rate):物料备齐订单比例
- 瓶颈工序:限制整线产能的工序(针车/成型)
- 插单:临时插入高优先订单
# 检验体系
## 核心环节
- **IQC(来料检验)**:面料/辅料/大底进厂检验(色差、克重、缩水率、瑕疵、物性)。
- **IPQC(制程检验)**:裁断/针车/成型各工序巡检(针距、对称度、粘合、绷帮)。
- **OQC(出货检验)**:成品抽检(AQL 标准、功能/外观/包装)。
- **返工率/不良率**:按批次/款号统计,异常时定位到工序与班次。
- **客诉**:售后投诉按「批次 → 工序 → 原料」追溯。
## 排查要点(质量问题)
- **不良集中度**:按款/颜色/尺码/日期/班次分组,定位集中点(单一因素主导 → 该环节问题)。
- **色差/克重差异**:面料缸差(批次混用)→ 查 IQC 记录与仓库批次追溯。
- **尺寸偏差**:缩水率未按面料实测调整 → 查工艺单缩水参数。
- **缝制瑕疵**:针距/断针 → 查 IPQC 巡检记录与针车工位。
- **开胶/脱底**:成型工艺参数(活化温度/压合力)或大底材质污染 → 查成型巡检记录。
- **追溯链**:成品 → 出货单 → 生产批次 → 采购单 → 原料批(反向查证)。
## 关键术语
- AQL:可接受质量水平(抽样标准,如 AQL 2.5/4.0)
- 疵点:面料瑕疵(竹节/色斑/断纱)
- 三标:洗标/主标/尺码标(错漏属外观不良)
# 物性测试
> 鞋类材料与成品的关键物性测试项(实验室/第三方检测),影响接单、验货与客诉归因。
## 材料级
- **耐折(耐弯折)**:帮面/大底反复弯折(如 4 万次/6 万次),开裂/断裂判定。
- **耐磨**:大底/外底磨耗(DIN 磨耗/阿克隆磨耗),劳保鞋与运动鞋重点。
- **剥离强度**:鞋面与大底粘合牢度(开胶归因的核心指标)。
- **拉伸/撕裂强度**:面料/超纤/织带。
- **止滑(防滑)**:大底动/静摩擦系数,出口欧美需测。
## 成品级
- **整鞋耐折**:成品鞋动态弯折测试(屈挠次数)。
- **耐黄变**:浅色材料/大底光照黄变。
- **低温耐折**:-10℃/-20℃ 弯折(冬季鞋/劳保鞋)。
- **安全性能**(劳保鞋):防砸(200J 冲击)、防刺穿(1100N)、电绝缘(6kV/10kV)。
- **化学安全**(童鞋):六价铬、甲醛、可分解致癌芳香胺、重金属(GB 30585)。
## 排查要点
- 客诉「开胶/断底/掉色」→ 先查对应物性测试报告与生产批次测试记录。
- 材料批次差异:同供应商不同批次物性波动 → IQC 抽样测试频率不足。
- 测试标准口径:客户标准 vs 国标(GB)vs 国际(ISO/EN/ASTM)不一致是常见争议点。
# 鞋业专业术语
## 生产工艺
- **裁片**:按唛架排版裁剪出的面料片(鞋面/内里/衬片)。
- **唛架(Marker)**:裁剪排版图,决定面料利用率。
- **针数**:每英寸针数(针织密度指标,影响手感与强度)。
- **针车**:鞋面缝制工序(合缝/压线/包边)。
- **绷帮(Lasting)**:鞋面套楦定型工序,决定鞋型与合脚度。
- **成型**:鞋类最后成型(贴合/上底),分冷粘/硫化/注塑三路线。
- **冷粘**:鞋面与大底胶粘成型(主流工艺)。
- **硫化**:生胶大底加温加压熟化成型(耐油耐磨,劳保鞋常用)。
- **注塑**:PVC/TPU/EVA 模具注射成型(童鞋/拖鞋/凉鞋)。
- **港宝**:后跟定型片(热熔胶/皮革材质)。
- **飞织(Flyknit)**:一体织造鞋面技术。
## 材料
- **网布**:透气织造面料,运动鞋鞋面主材。
- **超纤**:PU 涂层的仿皮材料,物性稳定。
- **RB**:橡胶大底(耐磨止滑)。
- **EVA / MD / TPU / PU**:中底材料(发泡/二次发泡/高回弹/聚氨酯)。
- **缸差**:同色不同缸次的色差。
## 计划与贸易
- **BOM**:物料清单(面料/辅料/大底结构与用量)。
- **单耗**:单双鞋的物料用量。
- **MOQ**:最小起订量(Minimum Order Quantity)。
- **FOB / CIF**:贸易术语(离岸价/到岸价含运费保险)。
- **在制**:生产进行中的在产数量。
- **尾数**:订单完成后未销完的零头数量(库存尾数/生产尾数)。
- **翻单**:老款/老订单再次下单生产。
- **齐套**:物料备齐可投产。
- **三标**:洗标/主标/尺码标。
## 质量
- **AQL**:可接受质量水平(抽检标准)。
- **IQC / IPQC / OQC**:来料/制程/出货检验。
- **疵点**:材料瑕疵(色斑/断纱/竹节)。
- **物性测试**:耐折/耐磨/剥离/止滑等物理性能测试。
- **GB 21148**:劳保安全鞋国家标准。
- **GB 30585**:儿童鞋安全技术规范。
# 常见问题(本地沉淀区)
> 本目录为鞋业行业问答沉淀区:智能体在行业问答中确认的典型问题,由维护者整理成 Markdown 主题文件放入本目录,并在 `../INDEX.md` 的 07-常见问题 大类登记(文件名 + 一句话说明 + 触发词)。
>
> 当前为空:暂无沉淀条目。
>
> 注意:内置目录只读,智能体禁止直接写入;沉淀由维护者(人工)执行。
# 鞋业(别名:制鞋、鞋类、鞋服)
行业简介:制鞋行业基础知识——品类认知(运动鞋/劳保鞋/童鞋等)、生产工艺(裁断/针车/成型)、材料与 BOM、业务与贸易、质量管理与专业术语,供排查与需求理解对齐业务语境。适用:运动鞋、劳保鞋、童鞋、皮鞋、凉拖鞋等各类鞋生产制造企业。
## 01-品类认知
- 运动鞋.md:跑鞋/篮球鞋/足球鞋/综训鞋(触发词:运动鞋、跑鞋、篮球鞋、飞织、综训)
- 劳保鞋.md:安全鞋/防砸防刺/绝缘/钢包头(触发词:劳保鞋、安全鞋、钢包头、防刺穿、绝缘鞋)
- 童鞋.md:学步鞋/机能鞋/中大童(触发词:童鞋、学步鞋、机能鞋、小附件、GB 30585)
- 皮鞋与休闲鞋.md:真皮/超纤/固特异/胶粘(触发词:皮鞋、真皮、超纤、固特异、休闲鞋)
- 凉鞋与拖鞋.md:EVA 注塑/PVC 发泡(触发词:凉鞋、拖鞋、EVA、注塑、沙滩鞋)
## 02-生产工艺
- 裁断与针车.md:裁片/唛架/针数/鞋面针车(触发词:裁断、针车、裁片、唛架、针数、鞋面)
- 成型工艺.md:冷粘/硫化/注塑/绷帮(触发词:成型、冷粘、硫化、注塑、绷帮、上底)
- 包装与入库.md:配对/装盒/箱规(触发词:包装、配对、装盒、箱规、入库)
## 03-材料与BOM
- 鞋面材料.md:网布/飞织/皮革/超纤/PU(触发词:鞋面、网布、飞织、超纤、PU、皮革)
- 鞋底材料.md:RB/EVA/PU/TPU/橡胶/MD(触发词:鞋底、大底、EVA、TPU、RB、橡胶、MD)
- BOM与单耗.md:单耗/损耗率/用量核算(触发词:BOM、单耗、损耗、用量、核算)
## 04-业务与贸易
- 接单与订单评审.md:订单评审/下单(触发词:接单、订单评审、报价、翻单、下单)
- 报价与成本.md:料工费/报价口径(触发词:成本、核算、料工费、报价、FOB、CIF)
- 翻单与交期.md:翻单/齐套/交期(触发词:交期、延误、跟催、齐套、尾数、翻单)
## 05-质量管理
- 检验体系.md:IQC/IPQC/OQC/AQL(触发词:质量、IQC、IPQC、OQC、返工、客诉、AQL)
- 物性测试.md:耐折/耐磨/剥离/止滑(触发词:物性、耐折、耐磨、剥离、止滑、拉力)
## 06-专业术语
- 术语表.md:裁片/针数/唛架/绷帮/翻单/齐套(触发词:术语、MOQ、FOB、唛架、绷帮、翻单)
## 07-常见问题
> 本地沉淀区:行业问答中确认的常见问题经维护者整理追加到本大类(内置目录只读,禁止智能体直接写入)。
......@@ -196,6 +196,25 @@ namespace Ftt.PatchPack
#endregion
#region 内置方言/行业知识(Agent/dialect、Agent/industry,随程序发布)
// 轻量智能体内置知识:产品排查方言(dialect)+ 行业知识(industry),只读、随程序发布。
// 新增/修改的内置知识进入增量补丁,解包到客户端 {ExeName}\Agent\ 下(时间窗同 XML,默认 30 天)。
var dialectPath = Path.Combine(AbsoluteRootDirectory, RelativeAppFilePath, "Agent", "dialect");
if (System.IO.Directory.Exists(dialectPath))
{
valid.AddRange(GetValidPatchFile(dialectPath, "*.*", SearchOption.AllDirectories, dialectPath, $"{ExeName}\\Agent\\dialect", PatchTimeFrame_Xml));
}
var industryPath = Path.Combine(AbsoluteRootDirectory, RelativeAppFilePath, "Agent", "industry");
if (System.IO.Directory.Exists(industryPath))
{
valid.AddRange(GetValidPatchFile(industryPath, "*.*", SearchOption.AllDirectories, industryPath, $"{ExeName}\\Agent\\industry", PatchTimeFrame_Xml));
}
#endregion
#region 额外附加的文件.
foreach (var fileName in ContainFiles)
......
......@@ -23,6 +23,7 @@ namespace Tools.MyAgent.Agent
private IOpenAiChatClient _client = new OpenAiCompatibleClient();
private readonly KbService _kb;
private readonly PromptBuilder _prompts = new PromptBuilder();
private readonly DialectService _dialect; // 内置方言/行业知识(程序目录 Agent/dialect + Agent/industry)
private CancellationTokenSource _cts;
/// <summary>上下文 token 预算(由配置注入;默认 32000)</summary>
......@@ -138,6 +139,9 @@ namespace Tools.MyAgent.Agent
_kb = kb;
_backupClient = new OpenAiCompatibleClient();
_failover = new FailoverPolicy(_client, _backupClient);
// 内置方言/行业知识:随程序发布(AppDomain.BaseDirectory + Agent),目录缺失时自动降级为空
_dialect = new DialectService(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Agent"));
_prompts.Dialect = _dialect;
}
/// <summary>应用配置(ApiKey/BaseUrl/Model/Temperature/MaxTokens/代理/上下文预算)</summary>
......@@ -920,6 +924,7 @@ namespace Tools.MyAgent.Agent
{
CancelToken = ct,
DbConnections = DbConnections,
Dialect = _dialect,
};
string result = tool.Execute(args, ctx);
sw.Stop();
......
......@@ -18,6 +18,9 @@ namespace Tools.MyAgent.Agent
/// <summary>系统提示词启用开关(由设置注入;仅启用后才注入 CustomLayer)</summary>
public bool SystemPromptEnabled { get; set; }
/// <summary>内置方言/行业知识服务(产品排查方言 + 鞋业行业知识;由引擎注入,可空)</summary>
public DialectService Dialect { get; set; }
public string BuildSystemMessage(KbService kb)
{
// B2 提示词外置:静态层优先读 输出目录/prompts/*.md 模板(用户可定制),
......@@ -29,6 +32,8 @@ namespace Tools.MyAgent.Agent
sb.AppendLine();
sb.AppendLine(BuildKbLayer(kb));
sb.AppendLine();
sb.AppendLine(BuildDialectLayer());
sb.AppendLine();
// 自定义系统提示词:仅启用开关打开时注入(关闭时即使输入框有内容也不注入)
if (SystemPromptEnabled && !string.IsNullOrWhiteSpace(CustomLayer))
{
......@@ -155,6 +160,23 @@ namespace Tools.MyAgent.Agent
return sb.ToString();
}
/// <summary>
/// §2.2b 方言层(动态,随内置知识注入):产品排查方言 + 鞋业行业知识导航摘要。
/// 触发词路由:排查/业务类问题先按摘要命中 → d_grep 定位 → d_read 精读(禁止全量读取)。
/// </summary>
private string BuildDialectLayer()
{
if (Dialect == null || !Dialect.IsAvailable) return "";
try
{
return Dialect.BuildSummary();
}
catch
{
return ""; // 内置知识损坏不影响智能体可用性
}
}
/// <summary>搜索范围描述(空 = 整个知识库根目录)</summary>
private static string ScopeText(KbService kb)
{
......
......@@ -355,7 +355,8 @@ namespace Tools.MyAgent.Agent.Tools
return Truncate(sb.ToString());
}
private static IDbConnection OpenConnection(string type, string connection)
/// <summary>打开非 sqlserver 数据库连接(sqlserver 走平台 SmpDB,见 ExecuteQuery);供 DbSchemaTool 复用</summary>
internal static IDbConnection OpenConnection(string type, string connection)
{
switch (type)
{
......
This diff is collapsed.
This diff is collapsed.
......@@ -26,6 +26,9 @@ namespace Tools.MyAgent.Agent.Tools
/// <summary>预存数据库连接串(ID → 连接串,已解密明文;来自 AgentConfig.DbConnections)</summary>
public IReadOnlyDictionary<string, string> DbConnections { get; set; }
/// <summary>内置方言/行业知识服务(d_* 工具沙箱;程序目录 Agent/dialect + Agent/industry)</summary>
public DialectService Dialect { get; set; }
public ToolContext(KbService kb, Action<string> onFileProduced)
{
Kb = kb;
......@@ -155,9 +158,14 @@ namespace Tools.MyAgent.Agent.Tools
Register(new KbWriteTool());
Register(new KbWriteKbTool());
Register(new DbQueryTool());
Register(new DbSchemaTool());
Register(new DocExportTool());
Register(new ImageSearchTool());
Register(new ModulePatchTool());
// 内置方言/行业知识(d_* 系列,只读沙箱,默认启用)
Register(new DialectListTool());
Register(new DialectGrepTool());
Register(new DialectReadTool());
}
/// <summary>全部已注册工具(下发顺序)</summary>
......
......@@ -13,8 +13,8 @@ namespace Tools.MyAgent.Forms
{
/// <summary>
/// 智能体设置弹窗(选项卡一体化,纯 UI):
/// <para>基础配置(模型/知识库)、高级配置(生成参数/语义检索)、
/// 提示词(启用开关 + 角色模板 + 自定义系统提示词)、其他(可选能力/故障转移),无二次弹窗。</para>
/// <para>基础配置(模型/知识库)、高级配置(二级页:生成参数/策略参数/语义检索/故障转移/可选能力)、
/// 提示词(启用开关 + 角色模板 + 自定义系统提示词)、数据库连接(预存连接串),无二次弹窗。</para>
/// <para>控件布局由 AgentSettingsForm.Designer.cs(设计器)实现;本文件仅含逻辑:
/// 配置绑定(BindConfig)、布局联动(ApplyProviderMode / ApplyKbMode)、交互事件与保存回写。</para>
/// <para>保存语义:「保存」一次性回写全部改动;「取消」放弃全部改动。</para>
......@@ -139,7 +139,7 @@ namespace Tools.MyAgent.Forms
private TextBox txtToolRoles;
/// <summary>在「其他」页可选能力组追加工具权限输入区(角色白名单,一行一规则)</summary>
/// <summary>在「可选能力」页追加工具权限输入区(角色白名单,一行一规则)</summary>
private void BuildToolPermissionUi()
{
var lbl = new Label
......@@ -251,11 +251,11 @@ namespace Tools.MyAgent.Forms
chkPromptEnabled.Checked = _config.SystemPromptEnabled;
PopulateRoles();
// 其他:可选能力
// 可选能力页:可选工具开关
chkOpt.Checked = _config.EnableOptionalTools;
chkImageInput.Checked = _config.EnableImageInput; // v2.2 多模态:图片提问开关
// 其他:工具级权限(P3,角色白名单)
// 可选能力页:工具级权限(P3,角色白名单)
txtToolRoles.Lines = ToolRoleRulesToLines(_config.ToolRoleAllow);
// 数据库连接(P0):预存连接串(内存明文态)回填表格
......@@ -264,7 +264,7 @@ namespace Tools.MyAgent.Forms
foreach (var kv in _config.DbConnections.OrderBy(k => k.Key, StringComparer.OrdinalIgnoreCase))
dgvDbConn.Rows.Add(kv.Key, kv.Value);
// 其他:故障转移
// 故障转移页
chkFail.Checked = _config.EnableFailover;
txtBUrl.Text = _config.BackupBaseUrl;
txtBModel.Text = _config.BackupModel;
......@@ -562,10 +562,10 @@ namespace Tools.MyAgent.Forms
_config.SystemPromptEnabled = chkPromptEnabled.Checked;
_config.RoleTemplateId = (cmbRole.SelectedItem as RoleItem)?.Id ?? "";
_config.CustomSystemPrompt = txtCustomPrompt.Text.Trim();
// 其他:可选能力
// 可选能力页:可选工具开关
_config.EnableOptionalTools = chkOpt.Checked;
_config.EnableImageInput = chkImageInput.Checked; // v2.2 多模态:图片提问开关
// 其他:工具级权限(P3)
// 可选能力页:工具级权限(P3)
_config.ToolRoleAllow = ParseToolRoleRules(txtToolRoles.Text);
// 数据库连接(P0):表格 → 字典(ID 大小写不敏感,空格清理;空 ID 行忽略)
var conns = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
......@@ -577,7 +577,7 @@ namespace Tools.MyAgent.Forms
conns[id] = (r.Cells[1].Value?.ToString() ?? "").Trim();
}
_config.DbConnections = conns;
// 其他:故障转移
// 故障转移页
_config.EnableFailover = chkFail.Checked;
_config.BackupBaseUrl = txtBUrl.Text.Trim();
_config.BackupModel = string.IsNullOrEmpty(txtBModel.Text.Trim()) ? "qwen2.5" : txtBModel.Text.Trim();
......
This diff is collapsed.
......@@ -36,6 +36,7 @@ namespace Tools.MyAgent.Kb
private const int MaxScanFileSize = 4 * 1024 * 1024; // 内容检索跳过 > 4MB 的文件
private const int MaxToolOutput = 8000; // 工具返回文本上限(字符)
private const int MaxReadChars = 12000; // kb_read 单次返回上限(字符)
internal const long MaxReadFileSize = 30L * 1024 * 1024; // kb_read/file_read 单文件大小闸门:> 30MB 拒绝整读(防 OOM)
/// <summary>检索索引(SQLite,含 docx/xlsx 内容;未就绪时检索回退全盘扫描)</summary>
private KbIndex _index;
......@@ -1323,13 +1324,20 @@ namespace Tools.MyAgent.Kb
if (limit < 1) limit = 1;
if (limit > 500) limit = 500;
// 文件大小闸门:提取前先看大小,避免超大文件整读进内存(OOM/卡死)——
// 检索类已有 MaxScanFileSize 闸门,读取路径此前缺失(漏洞修复)
var fi = new FileInfo(fullPath);
if (fi.Length > MaxReadFileSize)
return $"错误:文件过大({fi.Length / 1024 / 1024}MB,上限 {MaxReadFileSize / 1024 / 1024}MB),已跳过整读。"
+ $"请改用 kb_grep 检索定位相关内容,或把文件拆分成小块后再读。";
string ext = Path.GetExtension(fullPath).ToLowerInvariant();
string content = null;
if (ext == ".ppt")
return $"暂不支持旧版 .ppt 二进制格式:{relPath}。可另存为 .pptx 后使用。";
else if (IsImageExtension(ext))
return $"图片文件:{relPath}(当前不支持直接读取图片内容,可描述图片或先查看文件名)。";
return $"图片文件:{relPath}(当前不支持直接读取图片内容;可改用 kb_view_image 把图片作为附图发送给视觉模型识别(图片提问),或启用「图片提问」后手动发送)";
else
{
// 统一走解析器注册表(X1):新格式只需注册 IFileParser,无需改本分支
......@@ -1338,11 +1346,11 @@ namespace Tools.MyAgent.Kb
}
if (content == null)
return $"二进制、扫描件(无文字层)或不可解析的文件:{relPath}。";
return $"二进制、扫描件(无文字层)或不可解析的文件:{relPath}。扫描件可改用 kb_view_image 把页面作为图片发送给视觉模型识别(图片提问,无需 OCR)。";
if (content.StartsWith("错误"))
return content; // 提取层的业务错误(如工作表不存在)直接透传
var lines = content.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n');
var lines = SplitLines(content);
if (offset > lines.Length) offset = lines.Length;
int start = offset;
int end = Math.Min(lines.Length, offset + limit - 1);
......@@ -1371,33 +1379,19 @@ namespace Tools.MyAgent.Kb
}
/// <summary>
/// 读取文本文件(自动识别 UTF-8/GB2312 等编码,兼容中文 Windows)
/// 读取文本文件(自动识别 UTF-8/UTF-16/UTF-32/GB18030/系统 ANSI 等编码,兼容中文 Windows;多编码兼容见 TextEncoding)
/// </summary>
internal static string ReadTextFile(string path)
{
try
{
byte[] bytes = File.ReadAllBytes(path);
if (bytes.Length == 0) return "";
if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
return new UTF8Encoding(false).GetString(bytes, 3, bytes.Length - 3);
if (bytes.Length >= 2 && bytes[0] == 0xFF && bytes[1] == 0xFE)
return Encoding.Unicode.GetString(bytes, 2, bytes.Length - 2);
if (bytes.Length >= 2 && bytes[0] == 0xFE && bytes[1] == 0xFF)
return Encoding.BigEndianUnicode.GetString(bytes, 2, bytes.Length - 2);
try
{
return new UTF8Encoding(false, true).GetString(bytes);
}
catch (DecoderFallbackException)
{
return Encoding.GetEncoding("GB2312").GetString(bytes);
return TextEncoding.ReadAllTextAuto(path);
}
}
catch
/// <summary>
/// 统一行切分:任意换行风格(CRLF/CR/LF)归一为 \n 后切行,供各读取工具(file_read/module_read/industry_read/kb_read)共用
/// </summary>
internal static string[] SplitLines(string content)
{
return null;
}
return (content ?? "").Replace("\r\n", "\n").Replace('\r', '\n').Split('\n');
}
/// <summary>提取 docx 文本(段落 + 表格单元格)</summary>
......@@ -1457,7 +1451,9 @@ namespace Tools.MyAgent.Kb
NPOI.SS.UserModel.ISheet sheetObj = ResolveSheet(wb, sheet);
if (sheetObj == null)
return $"错误:工作表不存在:{sheet ?? "0"}(本文件共 {wb.NumberOfSheets} 个工作表)";
return ReadSheet(sheetObj, maxRow: 500, maxCol: 30);
// P2 证据出处:输出头部标注工作表名(与索引的【表名】前缀一致,模型可据此引用)
string body = ReadSheet(sheetObj, maxRow: 500, maxCol: 30);
return $"【工作表:{sheetObj.SheetName}】\n" + body;
}
finally
{
......
This diff is collapsed.
......@@ -173,6 +173,8 @@
<Compile Include="MyAgent\Agent\Tools\ITool.cs" />
<Compile Include="MyAgent\Agent\Tools\KbTools.cs" />
<Compile Include="MyAgent\Agent\Tools\DbQueryTool.cs" />
<Compile Include="MyAgent\Agent\Tools\DbSchemaTool.cs" />
<Compile Include="MyAgent\Agent\Tools\DialectTools.cs" />
<Compile Include="MyAgent\Agent\Tools\DocExportTool.cs" />
<Compile Include="MyAgent\Agent\Tools\ImageSearchTool.cs" />
<Compile Include="MyAgent\Config\AgentConfig.cs" />
......@@ -194,6 +196,7 @@
<SubType>Form</SubType>
</Compile>
<Compile Include="MyAgent\Kb\KbConfig.cs" />
<Compile Include="MyAgent\Kb\DialectService.cs" />
<Compile Include="MyAgent\Kb\KbService.cs" />
<Compile Include="MyAgent\Kb\KbIndex.cs" />
<Compile Include="MyAgent\Kb\SynonymIndex.cs" />
......@@ -272,6 +275,7 @@
<Compile Include="MyUtils\SegPicture.cs" />
<Compile Include="MyUtils\TextBoxPlaceholder.cs" />
<Compile Include="MyUtils\TimeWatch.cs" />
<Compile Include="MyUtils\TextEncoding.cs" />
<Compile Include="UI\Popups\wEditEvaluation.cs">
<SubType>Form</SubType>
</Compile>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment