SmartDiagnosisEvidenceRegistry.cs 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252
  1. namespace Admin.NET.Plugin.AiDOP.SmartOps;
  2. public enum SmartDiagnosisEvidenceDomain
  3. {
  4. Delivery,
  5. Supply,
  6. Manufacturing,
  7. Quality,
  8. Exception
  9. }
  10. public sealed record SmartDiagnosisEvidenceFilterColumn(string QueryKey, string SqlColumn);
  11. public sealed record SmartDiagnosisEvidenceSource(
  12. string Key,
  13. SmartDiagnosisEvidenceDomain Domain,
  14. IReadOnlyList<string> Modules,
  15. string ObjectType,
  16. string DrillPath,
  17. string CountSql,
  18. string ItemSql,
  19. IReadOnlyList<SmartDiagnosisEvidenceFilterColumn> Filters)
  20. {
  21. public IReadOnlyList<string> MetricCodes { get; init; } = Array.Empty<string>();
  22. public string ContributionUnit { get; init; } = "qty";
  23. public string? DateColumn { get; init; }
  24. public string? DrillQueryKey { get; init; }
  25. }
  26. public static class SmartDiagnosisEvidenceRegistry
  27. {
  28. public const int DefaultLimit = 20;
  29. public const int MaxLimit = 50;
  30. private static readonly SmartDiagnosisEvidenceSource[] Sources =
  31. {
  32. new(
  33. "s1_contract_review_flow",
  34. SmartDiagnosisEvidenceDomain.Delivery,
  35. new[] { "S1" },
  36. "contract_review_flow",
  37. "/aidop/s1/order-mgmt/contract-review",
  38. """
  39. SELECT COUNT(*) FROM mdp_stg_so
  40. WHERE tenant_id=@tenantId
  41. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  42. AND (factory_id IS NULL OR factory_id<>@tenantId)
  43. AND source_table='ado_contract_review_flow'
  44. AND (
  45. (JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo')) =
  46. CASE
  47. WHEN @metricCode IN ('S1_L3_001','S1_L3_101') THEN '1'
  48. WHEN @metricCode IN ('S1_L3_002','S1_L3_102') THEN '2'
  49. WHEN @metricCode IN ('S1_L3_003','S1_L3_103') THEN '3'
  50. WHEN @metricCode IN ('S1_L3_004','S1_L3_104') THEN '4'
  51. WHEN @metricCode IN ('S1_L3_005','S1_L3_105') THEN '5'
  52. ELSE ''
  53. END)
  54. OR
  55. (JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo'))='1'
  56. AND CASE COALESCE(
  57. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.DeptNo')),''),
  58. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department'))
  59. )
  60. WHEN '法律事务部' THEN 'LAW'
  61. WHEN '技术售前组' THEN 'PRE_SALES'
  62. WHEN '综合主计划' THEN 'MPS'
  63. WHEN '试验站' THEN 'TEST'
  64. ELSE COALESCE(
  65. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.DeptNo')),''),
  66. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department'))
  67. )
  68. END =
  69. CASE
  70. WHEN @metricCode IN ('S1_L4_001','S1_L4_101') THEN 'LAW'
  71. WHEN @metricCode IN ('S1_L4_002','S1_L4_102') THEN 'PRE_SALES'
  72. WHEN @metricCode IN ('S1_L4_003','S1_L4_103') THEN 'MPS'
  73. WHEN @metricCode IN ('S1_L4_004','S1_L4_104') THEN 'TEST'
  74. ELSE ''
  75. END)
  76. )
  77. """,
  78. """
  79. SELECT
  80. COALESCE(
  81. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.FlowNo')),''),
  82. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ReviewNo')),''),
  83. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ContractNo')),''),
  84. NULLIF(source_biz_key,''),
  85. source_row_id
  86. ) AS ObjectCode,
  87. CONCAT(
  88. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department')),''),'评审环节'),
  89. ' / ',
  90. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageName')),''),'阶段 ',
  91. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo')))
  92. ) AS Title,
  93. COALESCE(
  94. TIMESTAMPDIFF(
  95. HOUR,
  96. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StartTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f'),
  97. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.CompleteTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f')
  98. ),
  99. CASE
  100. WHEN JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ActualDays')) REGEXP '^-?[0-9]+(\\.[0-9]+)?$'
  101. THEN CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ActualDays')) AS DECIMAL(18,6)) * 24
  102. END,
  103. 0
  104. ) AS Contribution,
  105. CASE
  106. WHEN JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Status')) IN ('逾期','超时','REJECTED','FAILED') THEN 'red'
  107. WHEN JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.CompleteTime')) IS NULL THEN 'yellow'
  108. ELSE 'green'
  109. END AS Status,
  110. COALESCE(
  111. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.CompleteTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f'),
  112. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StartTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f'),
  113. sync_time
  114. ) AS OccurredAt
  115. FROM mdp_stg_so
  116. WHERE tenant_id=@tenantId
  117. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  118. AND (factory_id IS NULL OR factory_id<>@tenantId)
  119. AND source_table='ado_contract_review_flow'
  120. AND (
  121. (JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo')) =
  122. CASE
  123. WHEN @metricCode IN ('S1_L3_001','S1_L3_101') THEN '1'
  124. WHEN @metricCode IN ('S1_L3_002','S1_L3_102') THEN '2'
  125. WHEN @metricCode IN ('S1_L3_003','S1_L3_103') THEN '3'
  126. WHEN @metricCode IN ('S1_L3_004','S1_L3_104') THEN '4'
  127. WHEN @metricCode IN ('S1_L3_005','S1_L3_105') THEN '5'
  128. ELSE ''
  129. END)
  130. OR
  131. (JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo'))='1'
  132. AND CASE COALESCE(
  133. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.DeptNo')),''),
  134. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department'))
  135. )
  136. WHEN '法律事务部' THEN 'LAW'
  137. WHEN '技术售前组' THEN 'PRE_SALES'
  138. WHEN '综合主计划' THEN 'MPS'
  139. WHEN '试验站' THEN 'TEST'
  140. ELSE COALESCE(
  141. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.DeptNo')),''),
  142. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department'))
  143. )
  144. END =
  145. CASE
  146. WHEN @metricCode IN ('S1_L4_001','S1_L4_101') THEN 'LAW'
  147. WHEN @metricCode IN ('S1_L4_002','S1_L4_102') THEN 'PRE_SALES'
  148. WHEN @metricCode IN ('S1_L4_003','S1_L4_103') THEN 'MPS'
  149. WHEN @metricCode IN ('S1_L4_004','S1_L4_104') THEN 'TEST'
  150. ELSE ''
  151. END)
  152. )
  153. ORDER BY Contribution DESC, OccurredAt DESC
  154. LIMIT @limit
  155. """,
  156. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  157. {
  158. ContributionUnit = "小时",
  159. MetricCodes = new[]
  160. {
  161. "S1_L3_001", "S1_L3_002", "S1_L3_003", "S1_L3_004", "S1_L3_005",
  162. "S1_L3_101", "S1_L3_102", "S1_L3_103", "S1_L3_104", "S1_L3_105",
  163. "S1_L4_001", "S1_L4_002", "S1_L4_003", "S1_L4_004",
  164. "S1_L4_101", "S1_L4_102", "S1_L4_103", "S1_L4_104",
  165. }
  166. },
  167. new(
  168. "order_schedule",
  169. SmartDiagnosisEvidenceDomain.Manufacturing,
  170. new[] { "S1", "S2", "S6" },
  171. "work_order",
  172. "/aidop/s2/work-order-scheduling",
  173. """
  174. SELECT COUNT(*) FROM dwd_order_schedule_trans
  175. WHERE tenant_id=@tenantId
  176. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  177. AND (factory_id IS NULL OR factory_id<>@tenantId)
  178. AND IFNULL(work_order,'')<>''
  179. """,
  180. """
  181. SELECT work_order AS ObjectCode,
  182. CONCAT(IFNULL(sales_order_no,''),' / ',IFNULL(work_order,''),' / ',IFNULL(item_code,'')) AS Title,
  183. GREATEST(IFNULL(qty_ordered,0)-IFNULL(qty_completed,0),0) AS Contribution,
  184. CASE
  185. WHEN IFNULL(schedule_satisfaction_flag,1)=0 OR (due_date IS NOT NULL AND due_date<CURDATE()) THEN 'red'
  186. WHEN IFNULL(wip_qty,0)>0 THEN 'yellow'
  187. ELSE 'green'
  188. END AS Status,
  189. COALESCE(due_date, stat_date) AS OccurredAt
  190. FROM dwd_order_schedule_trans
  191. WHERE tenant_id=@tenantId
  192. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  193. AND (factory_id IS NULL OR factory_id<>@tenantId)
  194. AND IFNULL(work_order,'')<>''
  195. ORDER BY Contribution DESC, OccurredAt
  196. LIMIT @limit
  197. """,
  198. new[]
  199. {
  200. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  201. new SmartDiagnosisEvidenceFilterColumn("orderNo", "sales_order_no"),
  202. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  203. new SmartDiagnosisEvidenceFilterColumn("productionLine", "prod_line"),
  204. }),
  205. new(
  206. "supplier_delivery",
  207. SmartDiagnosisEvidenceDomain.Supply,
  208. new[] { "S3", "S4" },
  209. "purchase_order",
  210. "/aidop/s4/purchase-execution",
  211. """
  212. SELECT COUNT(*) FROM dwd_supplier_delivery
  213. WHERE tenant_id=@tenantId
  214. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  215. AND (factory_id IS NULL OR factory_id<>@tenantId)
  216. AND IFNULL(po_no,'')<>''
  217. """,
  218. """
  219. SELECT po_no AS ObjectCode,
  220. CONCAT(IFNULL(supplier_name,supplier_code),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  221. GREATEST(IFNULL(remaining_qty,0),0) AS Contribution,
  222. CASE
  223. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED')
  224. OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE') THEN 'red'
  225. WHEN IFNULL(remaining_qty,0)>0 THEN 'yellow'
  226. ELSE 'green'
  227. END AS Status,
  228. COALESCE(due_date, stat_date) AS OccurredAt
  229. FROM dwd_supplier_delivery
  230. WHERE tenant_id=@tenantId
  231. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  232. AND (factory_id IS NULL OR factory_id<>@tenantId)
  233. AND IFNULL(po_no,'')<>''
  234. ORDER BY Contribution DESC, OccurredAt
  235. LIMIT @limit
  236. """,
  237. new[]
  238. {
  239. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  240. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  241. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  242. }),
  243. new(
  244. "material_readiness",
  245. SmartDiagnosisEvidenceDomain.Supply,
  246. new[] { "S3" },
  247. "work_order",
  248. "/aidop/s3/material-readiness",
  249. """
  250. SELECT COUNT(*) FROM dwd_material_readiness
  251. WHERE tenant_id=@tenantId
  252. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  253. AND (factory_id IS NULL OR factory_id<>@tenantId)
  254. AND IFNULL(shortage_qty,0)>0
  255. """,
  256. """
  257. SELECT work_order AS ObjectCode,
  258. CONCAT('缺料 ',IFNULL(work_order,''),' / ',IFNULL(supplier_code,'')) AS Title,
  259. IFNULL(shortage_qty,0) AS Contribution,
  260. 'red' AS Status,
  261. stat_date AS OccurredAt
  262. FROM dwd_material_readiness
  263. WHERE tenant_id=@tenantId
  264. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  265. AND (factory_id IS NULL OR factory_id<>@tenantId)
  266. AND IFNULL(shortage_qty,0)>0
  267. ORDER BY Contribution DESC, OccurredAt
  268. LIMIT @limit
  269. """,
  270. new[]
  271. {
  272. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  273. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  274. }),
  275. new(
  276. "s6_report",
  277. SmartDiagnosisEvidenceDomain.Manufacturing,
  278. new[] { "S6" },
  279. "work_order",
  280. "/aidop/s6/report-work",
  281. """
  282. SELECT COUNT(*) FROM mdp_std_s6_report
  283. WHERE tenant_id=@tenantId
  284. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  285. AND (factory_id IS NULL OR factory_id<>@tenantId)
  286. AND IFNULL(work_order_no,'')<>''
  287. """,
  288. """
  289. SELECT work_order_no AS ObjectCode,
  290. CONCAT('报工 ',IFNULL(work_order_no,'')) AS Title,
  291. IFNULL(report_qty,0) AS Contribution,
  292. 'yellow' AS Status,
  293. report_date AS OccurredAt
  294. FROM mdp_std_s6_report
  295. WHERE tenant_id=@tenantId
  296. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  297. AND (factory_id IS NULL OR factory_id<>@tenantId)
  298. AND IFNULL(work_order_no,'')<>''
  299. ORDER BY Contribution DESC, OccurredAt
  300. LIMIT @limit
  301. """,
  302. new[]
  303. {
  304. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order_no"),
  305. }),
  306. new(
  307. "iqc_bill",
  308. SmartDiagnosisEvidenceDomain.Quality,
  309. new[] { "S5" },
  310. "inspection_bill",
  311. "/aidop/s5/iqc",
  312. """
  313. SELECT COUNT(*) FROM qms_qcp_inspbill
  314. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  315. """,
  316. """
  317. SELECT FBILLNO AS ObjectCode,
  318. CONCAT('IQC ',IFNULL(FBILLNO,''),' / ',IFNULL(FBILLSTATUS,'')) AS Title,
  319. 1 AS Contribution,
  320. CASE WHEN UPPER(IFNULL(FBILLSTATUS,'')) IN ('NG','REJECT','UNQUALIFIED') THEN 'red' ELSE 'yellow' END AS Status,
  321. NULL AS OccurredAt
  322. FROM qms_qcp_inspbill
  323. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  324. ORDER BY id DESC
  325. LIMIT @limit
  326. """,
  327. Array.Empty<SmartDiagnosisEvidenceFilterColumn>()),
  328. new(
  329. "fqc_result",
  330. SmartDiagnosisEvidenceDomain.Quality,
  331. new[] { "S7" },
  332. "inspection_bill",
  333. "/aidop/s7/fqc",
  334. """
  335. SELECT COUNT(*) FROM mdp_std_fqc_result
  336. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  337. """,
  338. """
  339. SELECT bill_no AS ObjectCode,
  340. CONCAT('FQC ',IFNULL(bill_no,''),' / ',IFNULL(material_code,'')) AS Title,
  341. GREATEST(IFNULL(unqualified_qty,0),0) AS Contribution,
  342. CASE WHEN IFNULL(unqualified_qty,0)>0 OR UPPER(IFNULL(judgment,'')) IN ('NG','FAIL','UNQUALIFIED') THEN 'red' ELSE 'green' END AS Status,
  343. inspect_time AS OccurredAt
  344. FROM mdp_std_fqc_result
  345. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  346. ORDER BY Contribution DESC, OccurredAt
  347. LIMIT @limit
  348. """,
  349. new[]
  350. {
  351. new SmartDiagnosisEvidenceFilterColumn("material", "material_code"),
  352. new SmartDiagnosisEvidenceFilterColumn("workOrder", "sap_work_order_no"),
  353. }),
  354. new(
  355. "s2_order_schedule_metric",
  356. SmartDiagnosisEvidenceDomain.Manufacturing,
  357. new[] { "S2" },
  358. "work_order",
  359. "/aidop/s2/production-scheduling/work-order-scheduling",
  360. """
  361. SELECT COUNT(*) FROM dwd_order_schedule_trans
  362. WHERE tenant_id=@tenantId
  363. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  364. AND (factory_id IS NULL OR factory_id<>@tenantId)
  365. AND IFNULL(work_order,'')<>''
  366. AND @metricCode IN ('S2_L1_001','S2_L1_002','S2_L1_003','S2_L1_004','S2_L2_001','S2_L2_002','S2_L2_003')
  367. AND (
  368. (@metricCode IN ('S2_L1_001','S2_L2_001') AND schedule_cycle_days IS NOT NULL)
  369. OR (@metricCode IN ('S2_L1_002','S2_L2_002') AND (IFNULL(schedule_satisfaction_flag,1)=0 OR (due_date IS NOT NULL AND due_date<CURDATE())))
  370. OR (@metricCode IN ('S2_L1_003','S2_L2_003'))
  371. OR (@metricCode='S2_L1_004' AND IFNULL(wip_qty,0)>0)
  372. )
  373. """,
  374. """
  375. SELECT work_order AS ObjectCode,
  376. CONCAT(IFNULL(sales_order_no,''),' / ',IFNULL(work_order,''),' / ',IFNULL(item_code,'')) AS Title,
  377. CASE
  378. WHEN @metricCode IN ('S2_L1_001','S2_L2_001') THEN IFNULL(schedule_cycle_days,0)
  379. WHEN @metricCode='S2_L1_004' THEN GREATEST(IFNULL(wip_qty,0),0)
  380. WHEN @metricCode IN ('S2_L1_003','S2_L2_003') THEN 1
  381. ELSE GREATEST(IFNULL(qty_ordered,0)-IFNULL(qty_completed,0),0)
  382. END AS Contribution,
  383. CASE
  384. WHEN IFNULL(schedule_satisfaction_flag,1)=0 OR (due_date IS NOT NULL AND due_date<CURDATE()) THEN 'red'
  385. WHEN IFNULL(wip_qty,0)>0 THEN 'yellow'
  386. ELSE 'green'
  387. END AS Status,
  388. COALESCE(due_date, stat_date) AS OccurredAt
  389. FROM dwd_order_schedule_trans
  390. WHERE tenant_id=@tenantId
  391. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  392. AND (factory_id IS NULL OR factory_id<>@tenantId)
  393. AND IFNULL(work_order,'')<>''
  394. AND @metricCode IN ('S2_L1_001','S2_L1_002','S2_L1_003','S2_L1_004','S2_L2_001','S2_L2_002','S2_L2_003')
  395. AND (
  396. (@metricCode IN ('S2_L1_001','S2_L2_001') AND schedule_cycle_days IS NOT NULL)
  397. OR (@metricCode IN ('S2_L1_002','S2_L2_002') AND (IFNULL(schedule_satisfaction_flag,1)=0 OR (due_date IS NOT NULL AND due_date<CURDATE())))
  398. OR (@metricCode IN ('S2_L1_003','S2_L2_003'))
  399. OR (@metricCode='S2_L1_004' AND IFNULL(wip_qty,0)>0)
  400. )
  401. ORDER BY Contribution DESC, OccurredAt
  402. LIMIT @limit
  403. """,
  404. new[]
  405. {
  406. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  407. new SmartDiagnosisEvidenceFilterColumn("orderNo", "sales_order_no"),
  408. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  409. new SmartDiagnosisEvidenceFilterColumn("productionLine", "prod_line"),
  410. })
  411. {
  412. ContributionUnit = "贡献",
  413. DateColumn = "stat_date",
  414. DrillQueryKey = "workOrder",
  415. MetricCodes = new[] { "S2_L1_001", "S2_L1_002", "S2_L1_003", "S2_L1_004", "S2_L2_001", "S2_L2_002", "S2_L2_003" }
  416. },
  417. new(
  418. "s2_operation_schedule_metric",
  419. SmartDiagnosisEvidenceDomain.Manufacturing,
  420. new[] { "S2" },
  421. "operation",
  422. "/aidop/s2/operation-plan/executable-daily-plan",
  423. """
  424. SELECT COUNT(*) FROM mdp_std_operation_schedule
  425. WHERE tenant_id=@tenantId
  426. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  427. AND (factory_id IS NULL OR factory_id<>@tenantId)
  428. AND IFNULL(work_order,'')<>''
  429. AND @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003','S2_L3_004','S2_L3_005','S2_L3_006')
  430. AND (
  431. @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003')
  432. OR IFNULL(COALESCE(NULLIF(work_center,''), NULLIF(line_code,'')), '')<>''
  433. )
  434. """,
  435. """
  436. SELECT CONCAT(IFNULL(work_order,''),':',IFNULL(op_no,'')) AS ObjectCode,
  437. CONCAT(IFNULL(work_order,''),' / 工序 ',IFNULL(op_no,''),' / ',IFNULL(COALESCE(NULLIF(work_center,''), line_code),'')) AS Title,
  438. CASE
  439. WHEN @metricCode IN ('S2_L3_001','S2_L3_004') THEN COALESCE(
  440. TIMESTAMPDIFF(HOUR, start_time, end_time) / 24,
  441. ABS(TIMESTAMPDIFF(DAY, plan_date, prod_date)),
  442. 0)
  443. ELSE 1
  444. END AS Contribution,
  445. CASE
  446. WHEN plan_date IS NOT NULL AND prod_date IS NOT NULL AND prod_date < plan_date THEN 'red'
  447. WHEN prod_date IS NULL THEN 'yellow'
  448. ELSE 'green'
  449. END AS Status,
  450. COALESCE(prod_date, plan_date, sync_time) AS OccurredAt
  451. FROM mdp_std_operation_schedule
  452. WHERE tenant_id=@tenantId
  453. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  454. AND (factory_id IS NULL OR factory_id<>@tenantId)
  455. AND IFNULL(work_order,'')<>''
  456. AND @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003','S2_L3_004','S2_L3_005','S2_L3_006')
  457. AND (
  458. @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003')
  459. OR IFNULL(COALESCE(NULLIF(work_center,''), NULLIF(line_code,'')), '')<>''
  460. )
  461. ORDER BY Contribution DESC, OccurredAt
  462. LIMIT @limit
  463. """,
  464. new[]
  465. {
  466. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  467. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  468. new SmartDiagnosisEvidenceFilterColumn("productionLine", "line_code"),
  469. })
  470. {
  471. ContributionUnit = "贡献",
  472. DateColumn = "plan_date",
  473. DrillQueryKey = "workOrder",
  474. MetricCodes = new[] { "S2_L3_001", "S2_L3_002", "S2_L3_003", "S2_L3_004", "S2_L3_005", "S2_L3_006" }
  475. },
  476. new(
  477. "s3_supplier_delivery_metric",
  478. SmartDiagnosisEvidenceDomain.Supply,
  479. new[] { "S3" },
  480. "purchase_order",
  481. "/aidop/s3/procurement/purchase-order",
  482. """
  483. SELECT COUNT(*) FROM dwd_supplier_delivery
  484. WHERE tenant_id=@tenantId
  485. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  486. AND (factory_id IS NULL OR factory_id<>@tenantId)
  487. AND IFNULL(po_no,'')<>''
  488. AND @metricCode IN ('S3_L1_002','S3_L2_005','S3_L3_005')
  489. AND (IFNULL(remaining_qty,0)>0 OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE'))
  490. """,
  491. """
  492. SELECT po_no AS ObjectCode,
  493. CONCAT(IFNULL(supplier_name,supplier_code),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  494. GREATEST(IFNULL(remaining_qty,0),0) AS Contribution,
  495. CASE
  496. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED')
  497. OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE') THEN 'red'
  498. WHEN IFNULL(remaining_qty,0)>0 THEN 'yellow'
  499. ELSE 'green'
  500. END AS Status,
  501. COALESCE(due_date, stat_date) AS OccurredAt
  502. FROM dwd_supplier_delivery
  503. WHERE tenant_id=@tenantId
  504. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  505. AND (factory_id IS NULL OR factory_id<>@tenantId)
  506. AND IFNULL(po_no,'')<>''
  507. AND @metricCode IN ('S3_L1_002','S3_L2_005','S3_L3_005')
  508. AND (IFNULL(remaining_qty,0)>0 OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE'))
  509. ORDER BY Contribution DESC, OccurredAt
  510. LIMIT @limit
  511. """,
  512. new[]
  513. {
  514. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  515. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  516. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  517. })
  518. {
  519. ContributionUnit = "件",
  520. DateColumn = "stat_date",
  521. DrillQueryKey = "poNo",
  522. MetricCodes = new[] { "S3_L1_002", "S3_L2_005", "S3_L3_005" }
  523. },
  524. new(
  525. "s3_material_readiness_metric",
  526. SmartDiagnosisEvidenceDomain.Supply,
  527. new[] { "S3" },
  528. "work_order",
  529. "/aidop/s3/supply-kanban/work-order-material-readiness",
  530. """
  531. SELECT COUNT(*) FROM dwd_material_readiness
  532. WHERE tenant_id=@tenantId
  533. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  534. AND (factory_id IS NULL OR factory_id<>@tenantId)
  535. AND IFNULL(work_order,'')<>''
  536. AND @metricCode IN ('S3_L3_003','S3_L3_006')
  537. AND (
  538. (@metricCode='S3_L3_003' AND UPPER(IFNULL(ready_status,'')) NOT IN ('READY','SUFFICIENT','OK'))
  539. OR (@metricCode='S3_L3_006' AND IFNULL(shortage_qty,0)>0)
  540. )
  541. """,
  542. """
  543. SELECT work_order AS ObjectCode,
  544. CONCAT(IFNULL(work_order,''),' / ',IFNULL(component_item_code,parent_item_code),' / 缺料 ',IFNULL(shortage_qty,0)) AS Title,
  545. GREATEST(IFNULL(shortage_qty,0),1) AS Contribution,
  546. 'red' AS Status,
  547. COALESCE(need_date, stat_date) AS OccurredAt
  548. FROM dwd_material_readiness
  549. WHERE tenant_id=@tenantId
  550. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  551. AND (factory_id IS NULL OR factory_id<>@tenantId)
  552. AND IFNULL(work_order,'')<>''
  553. AND @metricCode IN ('S3_L3_003','S3_L3_006')
  554. AND (
  555. (@metricCode='S3_L3_003' AND UPPER(IFNULL(ready_status,'')) NOT IN ('READY','SUFFICIENT','OK'))
  556. OR (@metricCode='S3_L3_006' AND IFNULL(shortage_qty,0)>0)
  557. )
  558. ORDER BY Contribution DESC, OccurredAt
  559. LIMIT @limit
  560. """,
  561. new[]
  562. {
  563. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  564. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  565. new SmartDiagnosisEvidenceFilterColumn("material", "component_item_code"),
  566. })
  567. {
  568. ContributionUnit = "件",
  569. DateColumn = "stat_date",
  570. DrillQueryKey = "workOrder",
  571. MetricCodes = new[] { "S3_L3_003", "S3_L3_006" }
  572. },
  573. new(
  574. "s3_purchase_request_metric",
  575. SmartDiagnosisEvidenceDomain.Supply,
  576. new[] { "S3" },
  577. "purchase_request",
  578. "/aidop/s3/procurement/purchase-request",
  579. """
  580. SELECT COUNT(*) FROM mdp_std_purchase_request
  581. WHERE tenant_id=@tenantId
  582. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  583. AND (factory_id IS NULL OR factory_id<>@tenantId)
  584. AND IFNULL(pr_no,'')<>''
  585. AND @metricCode='S3_L3_001'
  586. """,
  587. """
  588. SELECT pr_no AS ObjectCode,
  589. CONCAT('PR ',IFNULL(pr_no,''),' / ',IFNULL(item_code,'')) AS Title,
  590. GREATEST(IFNULL(request_qty,0),0) AS Contribution,
  591. CASE WHEN send_date IS NULL THEN 'yellow' ELSE 'green' END AS Status,
  592. COALESCE(request_date, sync_time) AS OccurredAt
  593. FROM mdp_std_purchase_request
  594. WHERE tenant_id=@tenantId
  595. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  596. AND (factory_id IS NULL OR factory_id<>@tenantId)
  597. AND IFNULL(pr_no,'')<>''
  598. AND @metricCode='S3_L3_001'
  599. ORDER BY Contribution DESC, OccurredAt
  600. LIMIT @limit
  601. """,
  602. new[]
  603. {
  604. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  605. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  606. })
  607. {
  608. ContributionUnit = "件",
  609. DateColumn = "request_date",
  610. DrillQueryKey = "prNo",
  611. MetricCodes = new[] { "S3_L3_001" }
  612. },
  613. new(
  614. "s3_purchase_order_metric",
  615. SmartDiagnosisEvidenceDomain.Supply,
  616. new[] { "S3" },
  617. "purchase_order",
  618. "/aidop/s3/procurement/purchase-order",
  619. """
  620. SELECT COUNT(*) FROM mdp_std_purchase_order
  621. WHERE tenant_id=@tenantId
  622. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  623. AND (factory_id IS NULL OR factory_id<>@tenantId)
  624. AND IFNULL(po_no,'')<>''
  625. AND @metricCode='S3_L3_002'
  626. """,
  627. """
  628. SELECT po_no AS ObjectCode,
  629. CONCAT('PO ',IFNULL(po_no,''),' / ',IFNULL(item_code,'')) AS Title,
  630. GREATEST(IFNULL(order_qty,0),0) AS Contribution,
  631. CASE WHEN due_date IS NOT NULL AND due_date<CURDATE() AND IFNULL(received_qty,0)<IFNULL(order_qty,0) THEN 'red' ELSE 'yellow' END AS Status,
  632. COALESCE(order_date, due_date, sync_time) AS OccurredAt
  633. FROM mdp_std_purchase_order
  634. WHERE tenant_id=@tenantId
  635. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  636. AND (factory_id IS NULL OR factory_id<>@tenantId)
  637. AND IFNULL(po_no,'')<>''
  638. AND @metricCode='S3_L3_002'
  639. ORDER BY Contribution DESC, OccurredAt
  640. LIMIT @limit
  641. """,
  642. new[]
  643. {
  644. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  645. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  646. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  647. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  648. })
  649. {
  650. ContributionUnit = "件",
  651. DateColumn = "order_date",
  652. DrillQueryKey = "poNo",
  653. MetricCodes = new[] { "S3_L3_002" }
  654. },
  655. new(
  656. "s3_delivery_schedule_metric",
  657. SmartDiagnosisEvidenceDomain.Supply,
  658. new[] { "S3" },
  659. "delivery_schedule",
  660. "/aidop/s3/material-plan/delivery-schedule",
  661. """
  662. SELECT COUNT(*) FROM mdp_std_delivery_schedule
  663. WHERE tenant_id=@tenantId
  664. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  665. AND (factory_id IS NULL OR factory_id<>@tenantId)
  666. AND IFNULL(delivery_plan_no,'')<>''
  667. AND @metricCode IN ('S3_L1_001','S3_L2_004','S3_L3_004')
  668. """,
  669. """
  670. SELECT delivery_plan_no AS ObjectCode,
  671. CONCAT(IFNULL(delivery_plan_no,''),' / ',IFNULL(po_no,''),' / ',IFNULL(item_code,'')) AS Title,
  672. CASE
  673. WHEN @metricCode='S3_L3_004' THEN GREATEST(IFNULL(rest_qty,0),1)
  674. ELSE GREATEST(IFNULL(DATEDIFF(IFNULL(last_sent_date,need_date), request_date),0),0)
  675. END AS Contribution,
  676. CASE
  677. WHEN IFNULL(rest_qty,0)>0 AND need_date IS NOT NULL AND need_date<CURDATE() THEN 'red'
  678. WHEN IFNULL(rest_qty,0)>0 THEN 'yellow'
  679. ELSE 'green'
  680. END AS Status,
  681. COALESCE(need_date, request_date, sync_time) AS OccurredAt
  682. FROM mdp_std_delivery_schedule
  683. WHERE tenant_id=@tenantId
  684. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  685. AND (factory_id IS NULL OR factory_id<>@tenantId)
  686. AND IFNULL(delivery_plan_no,'')<>''
  687. AND @metricCode IN ('S3_L1_001','S3_L2_004','S3_L3_004')
  688. ORDER BY Contribution DESC, OccurredAt
  689. LIMIT @limit
  690. """,
  691. new[]
  692. {
  693. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  694. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  695. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  696. })
  697. {
  698. ContributionUnit = "贡献",
  699. DateColumn = "need_date",
  700. DrillQueryKey = "planNo",
  701. MetricCodes = new[] { "S3_L1_001", "S3_L2_004", "S3_L3_004" }
  702. },
  703. new(
  704. "s4_supplier_delivery_metric",
  705. SmartDiagnosisEvidenceDomain.Supply,
  706. new[] { "S4" },
  707. "purchase_order",
  708. "/aidop/s4/delivery/supplier-delivery-management",
  709. """
  710. SELECT COUNT(*) FROM dwd_supplier_delivery
  711. WHERE tenant_id=@tenantId
  712. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  713. AND (factory_id IS NULL OR factory_id<>@tenantId)
  714. AND IFNULL(po_no,'')<>''
  715. AND @metricCode IN ('S4_L1_002','S4_L2_002','S4_L3_002','S4_L1_004')
  716. AND IFNULL(remaining_qty,0)>0
  717. """,
  718. """
  719. SELECT po_no AS ObjectCode,
  720. CONCAT(IFNULL(supplier_name,supplier_code),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  721. GREATEST(IFNULL(remaining_qty,0),0) AS Contribution,
  722. CASE
  723. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED')
  724. OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE') THEN 'red'
  725. ELSE 'yellow'
  726. END AS Status,
  727. COALESCE(due_date, stat_date) AS OccurredAt
  728. FROM dwd_supplier_delivery
  729. WHERE tenant_id=@tenantId
  730. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  731. AND (factory_id IS NULL OR factory_id<>@tenantId)
  732. AND IFNULL(po_no,'')<>''
  733. AND @metricCode IN ('S4_L1_002','S4_L2_002','S4_L3_002','S4_L1_004')
  734. AND IFNULL(remaining_qty,0)>0
  735. ORDER BY Contribution DESC, OccurredAt
  736. LIMIT @limit
  737. """,
  738. new[]
  739. {
  740. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  741. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  742. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  743. })
  744. {
  745. ContributionUnit = "件",
  746. DateColumn = "stat_date",
  747. DrillQueryKey = "poNo",
  748. MetricCodes = new[] { "S4_L1_002", "S4_L2_002", "S4_L3_002", "S4_L1_004" }
  749. },
  750. new(
  751. "s4_delivery_cycle_metric",
  752. SmartDiagnosisEvidenceDomain.Supply,
  753. new[] { "S4" },
  754. "delivery_schedule",
  755. "/aidop/s4/delivery/supplier-shipment",
  756. """
  757. SELECT COUNT(*) FROM mdp_std_delivery_schedule
  758. WHERE tenant_id=@tenantId
  759. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  760. AND (factory_id IS NULL OR factory_id<>@tenantId)
  761. AND IFNULL(delivery_plan_no,'')<>''
  762. AND @metricCode IN ('S4_L1_001','S4_L2_001','S4_L3_001')
  763. """,
  764. """
  765. SELECT delivery_plan_no AS ObjectCode,
  766. CONCAT(IFNULL(delivery_plan_no,''),' / ',IFNULL(po_no,''),' / ',IFNULL(item_code,'')) AS Title,
  767. GREATEST(IFNULL(DATEDIFF(IFNULL(last_sent_date,need_date), request_date),0),0) AS Contribution,
  768. CASE
  769. WHEN need_date IS NOT NULL AND last_sent_date IS NOT NULL AND last_sent_date>need_date THEN 'red'
  770. WHEN last_sent_date IS NULL THEN 'yellow'
  771. ELSE 'green'
  772. END AS Status,
  773. COALESCE(last_sent_date, need_date, sync_time) AS OccurredAt
  774. FROM mdp_std_delivery_schedule
  775. WHERE tenant_id=@tenantId
  776. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  777. AND (factory_id IS NULL OR factory_id<>@tenantId)
  778. AND IFNULL(delivery_plan_no,'')<>''
  779. AND @metricCode IN ('S4_L1_001','S4_L2_001','S4_L3_001')
  780. ORDER BY Contribution DESC, OccurredAt
  781. LIMIT @limit
  782. """,
  783. new[]
  784. {
  785. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  786. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  787. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  788. })
  789. {
  790. ContributionUnit = "天",
  791. DateColumn = "need_date",
  792. DrillQueryKey = "planNo",
  793. MetricCodes = new[] { "S4_L1_001", "S4_L2_001", "S4_L3_001" }
  794. },
  795. new(
  796. "s4_purchase_execution_metric",
  797. SmartDiagnosisEvidenceDomain.Supply,
  798. new[] { "S4" },
  799. "purchase_order",
  800. "/aidop/s4/execution-kanban/supplier-shortage-kanban",
  801. """
  802. SELECT COUNT(*) FROM dwd_s4_purchase_execution
  803. WHERE tenant_id=@tenantId
  804. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  805. AND (factory_id IS NULL OR factory_id<>@tenantId)
  806. AND IFNULL(po_no,'')<>''
  807. AND @metricCode IN ('S4_L2_003','S4_L3_003','S4_L2_004','S4_L3_004')
  808. """,
  809. """
  810. SELECT po_no AS ObjectCode,
  811. CONCAT(IFNULL(supplier_code,''),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  812. CASE
  813. WHEN @metricCode IN ('S4_L2_004','S4_L3_004') THEN GREATEST(IFNULL(shortage_qty,0), GREATEST(IFNULL(order_qty,0)-IFNULL(received_qty,0),0))
  814. ELSE 1
  815. END AS Contribution,
  816. CASE
  817. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED') THEN 'red'
  818. WHEN IFNULL(shortage_qty,0)>0 THEN 'yellow'
  819. ELSE 'green'
  820. END AS Status,
  821. COALESCE(due_date, actual_arrival_date, stat_date) AS OccurredAt
  822. FROM dwd_s4_purchase_execution
  823. WHERE tenant_id=@tenantId
  824. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  825. AND (factory_id IS NULL OR factory_id<>@tenantId)
  826. AND IFNULL(po_no,'')<>''
  827. AND @metricCode IN ('S4_L2_003','S4_L3_003','S4_L2_004','S4_L3_004')
  828. ORDER BY Contribution DESC, OccurredAt
  829. LIMIT @limit
  830. """,
  831. new[]
  832. {
  833. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  834. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  835. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  836. })
  837. {
  838. ContributionUnit = "贡献",
  839. DateColumn = "stat_date",
  840. DrillQueryKey = "poNo",
  841. MetricCodes = new[] { "S4_L2_003", "S4_L3_003", "S4_L2_004", "S4_L3_004" }
  842. },
  843. new(
  844. "s5_material_online_cycle_metric",
  845. SmartDiagnosisEvidenceDomain.Supply,
  846. new[] { "S5" },
  847. "material",
  848. "/aidop/s5/inventory/inout-query",
  849. """
  850. SELECT COUNT(*) FROM dwd_t8_material_online_cycle
  851. WHERE tenant_id=@tenantId
  852. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  853. AND (factory_id IS NULL OR factory_id<>@tenantId)
  854. AND IFNULL(item_code,'')<>''
  855. AND @metricCode='S5_L1_001'
  856. AND cycle_days IS NOT NULL
  857. """,
  858. """
  859. SELECT item_code AS ObjectCode,
  860. CONCAT('物料上线周期 ',IFNULL(item_code,''),' / ',IFNULL(cycle_days,0),'天') AS Title,
  861. IFNULL(cycle_days,0) AS Contribution,
  862. CASE WHEN IFNULL(cycle_days,0)>7 THEN 'red' WHEN IFNULL(cycle_days,0)>3 THEN 'yellow' ELSE 'green' END AS Status,
  863. biz_date AS OccurredAt
  864. FROM dwd_t8_material_online_cycle
  865. WHERE tenant_id=@tenantId
  866. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  867. AND (factory_id IS NULL OR factory_id<>@tenantId)
  868. AND IFNULL(item_code,'')<>''
  869. AND @metricCode='S5_L1_001'
  870. AND cycle_days IS NOT NULL
  871. ORDER BY Contribution DESC, OccurredAt
  872. LIMIT @limit
  873. """,
  874. new[]
  875. {
  876. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  877. })
  878. {
  879. ContributionUnit = "天",
  880. DateColumn = "biz_date",
  881. DrillQueryKey = "material",
  882. MetricCodes = new[] { "S5_L1_001" }
  883. },
  884. new(
  885. "s5_material_online_fulfillment_metric",
  886. SmartDiagnosisEvidenceDomain.Supply,
  887. new[] { "S5" },
  888. "work_order",
  889. "/aidop/s5/warehouse/production-issue",
  890. """
  891. SELECT COUNT(*) FROM dwd_t8_material_online_fulfillment
  892. WHERE tenant_id=@tenantId
  893. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  894. AND (factory_id IS NULL OR factory_id<>@tenantId)
  895. AND IFNULL(work_order_no,'')<>''
  896. AND @metricCode='S5_L1_002'
  897. """,
  898. """
  899. SELECT work_order_no AS ObjectCode,
  900. CONCAT('工单 ',IFNULL(work_order_no,''),' / 上线 ',IFNULL(before_kgdate_rows,0),'/',IFNULL(total_rows,0)) AS Title,
  901. GREATEST(IFNULL(total_rows,0)-IFNULL(before_kgdate_rows,0),0) AS Contribution,
  902. CASE WHEN IFNULL(fulfillment_rate,1)<1 THEN 'red' ELSE 'green' END AS Status,
  903. biz_date AS OccurredAt
  904. FROM dwd_t8_material_online_fulfillment
  905. WHERE tenant_id=@tenantId
  906. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  907. AND (factory_id IS NULL OR factory_id<>@tenantId)
  908. AND IFNULL(work_order_no,'')<>''
  909. AND @metricCode='S5_L1_002'
  910. ORDER BY Contribution DESC, OccurredAt
  911. LIMIT @limit
  912. """,
  913. new[]
  914. {
  915. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order_no"),
  916. })
  917. {
  918. ContributionUnit = "行",
  919. DateColumn = "biz_date",
  920. DrillQueryKey = "workOrder",
  921. MetricCodes = new[] { "S5_L1_002" }
  922. },
  923. new(
  924. "s5_iqc_bill_metric",
  925. SmartDiagnosisEvidenceDomain.Quality,
  926. new[] { "S5" },
  927. "inspection_bill",
  928. "/aidop/s5/iqc/result-list",
  929. """
  930. SELECT COUNT(*) FROM qms_qcp_inspbill
  931. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  932. AND @metricCode='S5_L2_004'
  933. """,
  934. """
  935. SELECT FBILLNO AS ObjectCode,
  936. CONCAT('IQC ',IFNULL(FBILLNO,''),' / ',IFNULL(FBILLSTATUS,'')) AS Title,
  937. 1 AS Contribution,
  938. CASE WHEN UPPER(IFNULL(FBILLSTATUS,'')) IN ('NG','REJECT','UNQUALIFIED') THEN 'red' ELSE 'yellow' END AS Status,
  939. NULL AS OccurredAt
  940. FROM qms_qcp_inspbill
  941. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  942. AND @metricCode='S5_L2_004'
  943. ORDER BY id DESC
  944. LIMIT @limit
  945. """,
  946. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  947. {
  948. ContributionUnit = "单",
  949. DrillQueryKey = "billNo",
  950. MetricCodes = new[] { "S5_L2_004" }
  951. },
  952. new(
  953. "s6_work_order_fulfillment_metric",
  954. SmartDiagnosisEvidenceDomain.Manufacturing,
  955. new[] { "S6" },
  956. "work_order",
  957. "/aidop/s6/production-record/order-list",
  958. """
  959. SELECT COUNT(*) FROM dwd_t8_work_order_mfg_fulfillment
  960. WHERE tenant_id=@tenantId
  961. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  962. AND (factory_id IS NULL OR factory_id<>@tenantId)
  963. AND IFNULL(order_no,'')<>''
  964. AND @metricCode IN ('S6_L1_002','S6_L2_002')
  965. """,
  966. """
  967. SELECT COALESCE(NULLIF(task_no,''), order_no) AS ObjectCode,
  968. CONCAT(IFNULL(order_no,''),' / ',IFNULL(task_no,''),' / ',IFNULL(item_code,'')) AS Title,
  969. GREATEST(IFNULL(plan_qty,0)-IFNULL(done_qty_in_window,0),0) AS Contribution,
  970. CASE WHEN IFNULL(fulfillment_rate,1)<1 THEN 'red' ELSE 'green' END AS Status,
  971. biz_date AS OccurredAt
  972. FROM dwd_t8_work_order_mfg_fulfillment
  973. WHERE tenant_id=@tenantId
  974. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  975. AND (factory_id IS NULL OR factory_id<>@tenantId)
  976. AND IFNULL(order_no,'')<>''
  977. AND @metricCode IN ('S6_L1_002','S6_L2_002')
  978. ORDER BY Contribution DESC, OccurredAt
  979. LIMIT @limit
  980. """,
  981. new[]
  982. {
  983. new SmartDiagnosisEvidenceFilterColumn("orderNo", "order_no"),
  984. new SmartDiagnosisEvidenceFilterColumn("workOrder", "task_no"),
  985. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  986. })
  987. {
  988. ContributionUnit = "件",
  989. DateColumn = "biz_date",
  990. DrillQueryKey = "orderNo",
  991. MetricCodes = new[] { "S6_L1_002", "S6_L2_002" }
  992. },
  993. new(
  994. "s7_shipment_cycle_metric",
  995. SmartDiagnosisEvidenceDomain.Delivery,
  996. new[] { "S7" },
  997. "sales_order",
  998. "/aidop/s7/finished-outbound/sales-shipment-notice",
  999. """
  1000. SELECT COUNT(*) FROM dwd_t8_order_shipment_cycle
  1001. WHERE tenant_id=@tenantId
  1002. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1003. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1004. AND IFNULL(order_no,'')<>''
  1005. AND @metricCode='S7_L1_001'
  1006. AND cycle_days IS NOT NULL
  1007. """,
  1008. """
  1009. SELECT order_no AS ObjectCode,
  1010. CONCAT('发货周期 ',IFNULL(order_no,''),' / ',IFNULL(cycle_days,0),'天') AS Title,
  1011. IFNULL(cycle_days,0) AS Contribution,
  1012. CASE WHEN IFNULL(cycle_days,0)>7 THEN 'red' WHEN IFNULL(cycle_days,0)>3 THEN 'yellow' ELSE 'green' END AS Status,
  1013. biz_date AS OccurredAt
  1014. FROM dwd_t8_order_shipment_cycle
  1015. WHERE tenant_id=@tenantId
  1016. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1017. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1018. AND IFNULL(order_no,'')<>''
  1019. AND @metricCode='S7_L1_001'
  1020. AND cycle_days IS NOT NULL
  1021. ORDER BY Contribution DESC, OccurredAt
  1022. LIMIT @limit
  1023. """,
  1024. new[]
  1025. {
  1026. new SmartDiagnosisEvidenceFilterColumn("orderNo", "order_no"),
  1027. })
  1028. {
  1029. ContributionUnit = "天",
  1030. DateColumn = "biz_date",
  1031. DrillQueryKey = "orderNo",
  1032. MetricCodes = new[] { "S7_L1_001" }
  1033. },
  1034. new(
  1035. "s7_shipment_fulfillment_metric",
  1036. SmartDiagnosisEvidenceDomain.Delivery,
  1037. new[] { "S7" },
  1038. "sales_order",
  1039. "/aidop/s7/finished-outbound/sales-shipment-notice",
  1040. """
  1041. SELECT COUNT(*) FROM dwd_t8_order_shipment_fulfillment
  1042. WHERE tenant_id=@tenantId
  1043. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1044. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1045. AND IFNULL(order_no,'')<>''
  1046. AND @metricCode='S7_L1_002'
  1047. """,
  1048. """
  1049. SELECT order_no AS ObjectCode,
  1050. CONCAT('发货满足 ',IFNULL(order_no,''),' / ',IFNULL(in_window_rows,0),'/',IFNULL(total_rows,0)) AS Title,
  1051. GREATEST(IFNULL(total_rows,0)-IFNULL(in_window_rows,0),0) AS Contribution,
  1052. CASE WHEN IFNULL(fulfillment_rate,100)<100 THEN 'red' ELSE 'green' END AS Status,
  1053. biz_date AS OccurredAt
  1054. FROM dwd_t8_order_shipment_fulfillment
  1055. WHERE tenant_id=@tenantId
  1056. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1057. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1058. AND IFNULL(order_no,'')<>''
  1059. AND @metricCode='S7_L1_002'
  1060. ORDER BY Contribution DESC, OccurredAt
  1061. LIMIT @limit
  1062. """,
  1063. new[]
  1064. {
  1065. new SmartDiagnosisEvidenceFilterColumn("orderNo", "order_no"),
  1066. })
  1067. {
  1068. ContributionUnit = "行",
  1069. DateColumn = "biz_date",
  1070. DrillQueryKey = "orderNo",
  1071. MetricCodes = new[] { "S7_L1_002" }
  1072. },
  1073. new(
  1074. "s7_fqc_result_metric",
  1075. SmartDiagnosisEvidenceDomain.Quality,
  1076. new[] { "S7" },
  1077. "inspection_bill",
  1078. "/aidop/s7/fqc/result-list",
  1079. """
  1080. SELECT COUNT(*) FROM mdp_std_fqc_result
  1081. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  1082. AND @metricCode='S7_L2_002'
  1083. """,
  1084. """
  1085. SELECT bill_no AS ObjectCode,
  1086. CONCAT('FQC ',IFNULL(bill_no,''),' / ',IFNULL(material_code,'')) AS Title,
  1087. GREATEST(IFNULL(unqualified_qty,0),0) AS Contribution,
  1088. CASE WHEN IFNULL(unqualified_qty,0)>0 OR UPPER(IFNULL(judgment,'')) IN ('NG','FAIL','UNQUALIFIED') THEN 'red' ELSE 'green' END AS Status,
  1089. inspect_time AS OccurredAt
  1090. FROM mdp_std_fqc_result
  1091. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  1092. AND @metricCode='S7_L2_002'
  1093. ORDER BY Contribution DESC, OccurredAt
  1094. LIMIT @limit
  1095. """,
  1096. new[]
  1097. {
  1098. new SmartDiagnosisEvidenceFilterColumn("material", "material_code"),
  1099. new SmartDiagnosisEvidenceFilterColumn("workOrder", "sap_work_order_no"),
  1100. })
  1101. {
  1102. ContributionUnit = "件",
  1103. DateColumn = "inspect_time",
  1104. DrillQueryKey = "billNo",
  1105. MetricCodes = new[] { "S7_L2_002" }
  1106. },
  1107. new(
  1108. "s9_quality_return_txn_metric",
  1109. SmartDiagnosisEvidenceDomain.Quality,
  1110. new[] { "S9" },
  1111. "sales_return",
  1112. "/aidop/s7/finished-outbound/sales-shipment-notice",
  1113. """
  1114. SELECT COUNT(*)
  1115. FROM mdp_std_t8_kc_tz_head h
  1116. INNER JOIN mdp_std_t8_kc_tz_list l
  1117. ON l.tenant_id=h.tenant_id AND l.idid=h.src_id
  1118. WHERE h.tenant_id=@tenantId
  1119. AND h.hzyn=0 AND h.zfyn=0 AND h.shyn=1
  1120. AND h.lbs='销售退货'
  1121. AND @metricCode='S9_L1_001'
  1122. """,
  1123. """
  1124. SELECT COALESCE(NULLIF(h.source_biz_key,''), NULLIF(l.lynoid,''), l.code) AS ObjectCode,
  1125. CONCAT('销售退货 ',IFNULL(l.lynoid,h.source_biz_key),' / ',IFNULL(l.code,'')) AS Title,
  1126. ABS(IFNULL(l.slzx,0)) AS Contribution,
  1127. 'red' AS Status,
  1128. h.shtime AS OccurredAt
  1129. FROM mdp_std_t8_kc_tz_head h
  1130. INNER JOIN mdp_std_t8_kc_tz_list l
  1131. ON l.tenant_id=h.tenant_id AND l.idid=h.src_id
  1132. WHERE h.tenant_id=@tenantId
  1133. AND h.hzyn=0 AND h.zfyn=0 AND h.shyn=1
  1134. AND h.lbs='销售退货'
  1135. AND @metricCode='S9_L1_001'
  1136. ORDER BY Contribution DESC, OccurredAt
  1137. LIMIT @limit
  1138. """,
  1139. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  1140. {
  1141. ContributionUnit = "件",
  1142. DateColumn = "h.shtime",
  1143. DrillQueryKey = "orderNo",
  1144. MetricCodes = new[] { "S9_L1_001" }
  1145. },
  1146. new(
  1147. "s8_exception",
  1148. SmartDiagnosisEvidenceDomain.Exception,
  1149. new[] { "S8" },
  1150. "s8_exception",
  1151. "/aidop/s8/exceptions",
  1152. """
  1153. SELECT COUNT(*) FROM ado_s8_exception
  1154. WHERE tenant_id=@tenantId AND IFNULL(is_deleted,0)=0
  1155. AND IFNULL(exception_code,'')<>''
  1156. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId
  1157. OR (@factoryId IN (0,1) AND factory_id<>@tenantId))
  1158. """,
  1159. """
  1160. SELECT exception_code AS ObjectCode,
  1161. CONCAT(IFNULL(exception_code,''),' / ',IFNULL(title,'')) AS Title,
  1162. GREATEST(IFNULL(priority_score,0),0) AS Contribution,
  1163. CASE
  1164. WHEN UPPER(IFNULL(status,'')) IN ('CLOSED','CANCELLED','CANCELED') THEN 'green'
  1165. WHEN UPPER(IFNULL(severity,'')) IN ('SERIOUS','CRITICAL','HIGH') THEN 'red'
  1166. ELSE 'yellow'
  1167. END AS Status,
  1168. created_at AS OccurredAt
  1169. FROM ado_s8_exception
  1170. WHERE tenant_id=@tenantId AND IFNULL(is_deleted,0)=0
  1171. AND IFNULL(exception_code,'')<>''
  1172. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId
  1173. OR (@factoryId IN (0,1) AND factory_id<>@tenantId))
  1174. ORDER BY Contribution DESC, OccurredAt
  1175. LIMIT @limit
  1176. """,
  1177. new[]
  1178. {
  1179. new SmartDiagnosisEvidenceFilterColumn("orderNo", "related_object_code"),
  1180. }),
  1181. };
  1182. public static IReadOnlyList<SmartDiagnosisEvidenceSource> All => Sources;
  1183. public static IReadOnlyList<SmartDiagnosisEvidenceSource> Resolve(string moduleCode)
  1184. {
  1185. var mc = (moduleCode ?? "").Trim().ToUpperInvariant();
  1186. if (mc == "S9")
  1187. return Sources.Where(x => x.Key != "s8_exception" && x.MetricCodes.Count == 0).ToList();
  1188. return Sources
  1189. .Where(x => x.MetricCodes.Count == 0
  1190. && x.Modules.Contains(mc, StringComparer.OrdinalIgnoreCase))
  1191. .ToList();
  1192. }
  1193. public static IReadOnlyList<SmartDiagnosisEvidenceSource> ResolveMetric(
  1194. string moduleCode,
  1195. string metricCode)
  1196. {
  1197. var mc = (moduleCode ?? "").Trim().ToUpperInvariant();
  1198. var metric = (metricCode ?? "").Trim().ToUpperInvariant();
  1199. if (mc.Length == 0 || metric.Length == 0)
  1200. return Array.Empty<SmartDiagnosisEvidenceSource>();
  1201. return Sources
  1202. .Where(x => x.Modules.Contains(mc, StringComparer.OrdinalIgnoreCase)
  1203. && x.MetricCodes.Contains(metric, StringComparer.OrdinalIgnoreCase))
  1204. .ToList();
  1205. }
  1206. public static SmartDiagnosisEvidenceSource? Get(string key) =>
  1207. Sources.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
  1208. }
  1209. public sealed class SmartDiagnosisEvidenceItem
  1210. {
  1211. public string ObjectType { get; set; } = "";
  1212. public string ObjectCode { get; set; } = "";
  1213. public string Title { get; set; } = "";
  1214. public decimal? Contribution { get; set; }
  1215. public string ContributionUnit { get; set; } = "";
  1216. public string Status { get; set; } = "green";
  1217. public string? OccurredAt { get; set; }
  1218. public string? DrillPath { get; set; }
  1219. }
  1220. public sealed class SmartDiagnosisEvidenceResult
  1221. {
  1222. public string Scope { get; set; } = "no_data";
  1223. public string? MetricCode { get; set; }
  1224. public string MatchScope { get; set; } = "module";
  1225. public string? AsOf { get; set; }
  1226. public string Domain { get; set; } = "";
  1227. public int Total { get; set; }
  1228. public int Returned { get; set; }
  1229. public bool Truncated { get; set; }
  1230. public List<string> Sources { get; set; } = new();
  1231. public List<SmartDiagnosisEvidenceItem> Items { get; set; } = new();
  1232. }
  1233. internal sealed class SmartDiagnosisEvidenceSqlRow
  1234. {
  1235. public string? ObjectCode { get; set; }
  1236. public string? Title { get; set; }
  1237. public decimal? Contribution { get; set; }
  1238. public string? Status { get; set; }
  1239. public DateTime? OccurredAt { get; set; }
  1240. }