SmartDiagnosisEvidenceRegistry.cs 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450
  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. OR @metricCode IN ('S1_L1_001','S1_L2_004','S1_L4_202')
  77. )
  78. """,
  79. """
  80. SELECT
  81. COALESCE(
  82. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.FlowNo')),''),
  83. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ReviewNo')),''),
  84. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ContractNo')),''),
  85. NULLIF(source_biz_key,''),
  86. source_row_id
  87. ) AS ObjectCode,
  88. CONCAT(
  89. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department')),''),'评审环节'),
  90. ' / ',
  91. COALESCE(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageName')),''),'阶段 ',
  92. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo')))
  93. ) AS Title,
  94. COALESCE(
  95. TIMESTAMPDIFF(
  96. HOUR,
  97. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StartTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f'),
  98. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.CompleteTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f')
  99. ),
  100. CASE
  101. WHEN JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ActualDays')) REGEXP '^-?[0-9]+(\\.[0-9]+)?$'
  102. THEN CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ActualDays')) AS DECIMAL(18,6)) * 24
  103. END,
  104. 0
  105. ) AS Contribution,
  106. CASE
  107. WHEN JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Status')) IN ('逾期','超时','REJECTED','FAILED') THEN 'red'
  108. WHEN JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.CompleteTime')) IS NULL THEN 'yellow'
  109. ELSE 'green'
  110. END AS Status,
  111. COALESCE(
  112. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.CompleteTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f'),
  113. STR_TO_DATE(REPLACE(NULLIF(NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StartTime')),'null'),''),'T',' '), '%Y-%m-%d %H:%i:%s.%f'),
  114. sync_time
  115. ) AS OccurredAt
  116. FROM mdp_stg_so
  117. WHERE tenant_id=@tenantId
  118. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  119. AND (factory_id IS NULL OR factory_id<>@tenantId)
  120. AND source_table='ado_contract_review_flow'
  121. AND (
  122. (JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo')) =
  123. CASE
  124. WHEN @metricCode IN ('S1_L3_001','S1_L3_101') THEN '1'
  125. WHEN @metricCode IN ('S1_L3_002','S1_L3_102') THEN '2'
  126. WHEN @metricCode IN ('S1_L3_003','S1_L3_103') THEN '3'
  127. WHEN @metricCode IN ('S1_L3_004','S1_L3_104') THEN '4'
  128. WHEN @metricCode IN ('S1_L3_005','S1_L3_105') THEN '5'
  129. ELSE ''
  130. END)
  131. OR
  132. (JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.StageNo'))='1'
  133. AND CASE COALESCE(
  134. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.DeptNo')),''),
  135. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department'))
  136. )
  137. WHEN '法律事务部' THEN 'LAW'
  138. WHEN '技术售前组' THEN 'PRE_SALES'
  139. WHEN '综合主计划' THEN 'MPS'
  140. WHEN '试验站' THEN 'TEST'
  141. ELSE COALESCE(
  142. NULLIF(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.DeptNo')),''),
  143. JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.Department'))
  144. )
  145. END =
  146. CASE
  147. WHEN @metricCode IN ('S1_L4_001','S1_L4_101') THEN 'LAW'
  148. WHEN @metricCode IN ('S1_L4_002','S1_L4_102') THEN 'PRE_SALES'
  149. WHEN @metricCode IN ('S1_L4_003','S1_L4_103') THEN 'MPS'
  150. WHEN @metricCode IN ('S1_L4_004','S1_L4_104') THEN 'TEST'
  151. ELSE ''
  152. END)
  153. OR @metricCode IN ('S1_L1_001','S1_L2_004','S1_L4_202')
  154. )
  155. ORDER BY Contribution DESC, OccurredAt DESC
  156. LIMIT @limit
  157. """,
  158. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  159. {
  160. ContributionUnit = "小时",
  161. MetricCodes = new[]
  162. {
  163. "S1_L3_001", "S1_L3_002", "S1_L3_003", "S1_L3_004", "S1_L3_005",
  164. "S1_L3_101", "S1_L3_102", "S1_L3_103", "S1_L3_104", "S1_L3_105",
  165. "S1_L4_001", "S1_L4_002", "S1_L4_003", "S1_L4_004",
  166. "S1_L4_101", "S1_L4_102", "S1_L4_103", "S1_L4_104",
  167. "S1_L1_001", "S1_L2_004", "S1_L4_202",
  168. }
  169. },
  170. new(
  171. "order_schedule",
  172. SmartDiagnosisEvidenceDomain.Manufacturing,
  173. new[] { "S1", "S2", "S6" },
  174. "work_order",
  175. "/aidop/s2/work-order-scheduling",
  176. """
  177. SELECT COUNT(*) FROM dwd_order_schedule_trans
  178. WHERE tenant_id=@tenantId
  179. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  180. AND (factory_id IS NULL OR factory_id<>@tenantId)
  181. AND IFNULL(work_order,'')<>''
  182. """,
  183. """
  184. SELECT work_order AS ObjectCode,
  185. CONCAT(IFNULL(sales_order_no,''),' / ',IFNULL(work_order,''),' / ',IFNULL(item_code,'')) AS Title,
  186. GREATEST(IFNULL(qty_ordered,0)-IFNULL(qty_completed,0),0) AS Contribution,
  187. CASE
  188. WHEN IFNULL(schedule_satisfaction_flag,1)=0 OR (due_date IS NOT NULL AND due_date<CURDATE()) THEN 'red'
  189. WHEN IFNULL(wip_qty,0)>0 THEN 'yellow'
  190. ELSE 'green'
  191. END AS Status,
  192. COALESCE(due_date, stat_date) AS OccurredAt
  193. FROM dwd_order_schedule_trans
  194. WHERE tenant_id=@tenantId
  195. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  196. AND (factory_id IS NULL OR factory_id<>@tenantId)
  197. AND IFNULL(work_order,'')<>''
  198. ORDER BY Contribution DESC, OccurredAt
  199. LIMIT @limit
  200. """,
  201. new[]
  202. {
  203. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  204. new SmartDiagnosisEvidenceFilterColumn("orderNo", "sales_order_no"),
  205. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  206. new SmartDiagnosisEvidenceFilterColumn("productionLine", "prod_line"),
  207. }),
  208. new(
  209. "supplier_delivery",
  210. SmartDiagnosisEvidenceDomain.Supply,
  211. new[] { "S3", "S4" },
  212. "purchase_order",
  213. "/aidop/s4/purchase-execution",
  214. """
  215. SELECT COUNT(*) FROM dwd_supplier_delivery
  216. WHERE tenant_id=@tenantId
  217. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  218. AND (factory_id IS NULL OR factory_id<>@tenantId)
  219. AND IFNULL(po_no,'')<>''
  220. """,
  221. """
  222. SELECT po_no AS ObjectCode,
  223. CONCAT(IFNULL(supplier_name,supplier_code),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  224. GREATEST(IFNULL(remaining_qty,0),0) AS Contribution,
  225. CASE
  226. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED')
  227. OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE') THEN 'red'
  228. WHEN IFNULL(remaining_qty,0)>0 THEN 'yellow'
  229. ELSE 'green'
  230. END AS Status,
  231. COALESCE(due_date, stat_date) AS OccurredAt
  232. FROM dwd_supplier_delivery
  233. WHERE tenant_id=@tenantId
  234. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  235. AND (factory_id IS NULL OR factory_id<>@tenantId)
  236. AND IFNULL(po_no,'')<>''
  237. ORDER BY Contribution DESC, OccurredAt
  238. LIMIT @limit
  239. """,
  240. new[]
  241. {
  242. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  243. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  244. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  245. }),
  246. new(
  247. "material_readiness",
  248. SmartDiagnosisEvidenceDomain.Supply,
  249. new[] { "S3" },
  250. "work_order",
  251. "/aidop/s3/material-readiness",
  252. """
  253. SELECT COUNT(*) FROM dwd_material_readiness
  254. WHERE tenant_id=@tenantId
  255. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  256. AND (factory_id IS NULL OR factory_id<>@tenantId)
  257. AND IFNULL(shortage_qty,0)>0
  258. """,
  259. """
  260. SELECT work_order AS ObjectCode,
  261. CONCAT('缺料 ',IFNULL(work_order,''),' / ',IFNULL(supplier_code,'')) AS Title,
  262. IFNULL(shortage_qty,0) AS Contribution,
  263. 'red' AS Status,
  264. stat_date AS OccurredAt
  265. FROM dwd_material_readiness
  266. WHERE tenant_id=@tenantId
  267. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  268. AND (factory_id IS NULL OR factory_id<>@tenantId)
  269. AND IFNULL(shortage_qty,0)>0
  270. ORDER BY Contribution DESC, OccurredAt
  271. LIMIT @limit
  272. """,
  273. new[]
  274. {
  275. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  276. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  277. }),
  278. new(
  279. "s6_report",
  280. SmartDiagnosisEvidenceDomain.Manufacturing,
  281. new[] { "S6" },
  282. "work_order",
  283. "/aidop/s6/report-work",
  284. """
  285. SELECT COUNT(*) FROM mdp_std_s6_report
  286. WHERE tenant_id=@tenantId
  287. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  288. AND (factory_id IS NULL OR factory_id<>@tenantId)
  289. AND IFNULL(source_system,'')<>''
  290. AND IFNULL(work_order_no,'')<>''
  291. AND report_qty IS NOT NULL
  292. """,
  293. """
  294. SELECT work_order_no AS ObjectCode,
  295. CONCAT('报工 ',IFNULL(work_order_no,'')) AS Title,
  296. IFNULL(report_qty,0) AS Contribution,
  297. 'yellow' AS Status,
  298. report_date AS OccurredAt
  299. FROM mdp_std_s6_report
  300. WHERE tenant_id=@tenantId
  301. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  302. AND (factory_id IS NULL OR factory_id<>@tenantId)
  303. AND IFNULL(source_system,'')<>''
  304. AND IFNULL(work_order_no,'')<>''
  305. AND report_qty IS NOT NULL
  306. ORDER BY Contribution DESC, OccurredAt
  307. LIMIT @limit
  308. """,
  309. new[]
  310. {
  311. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order_no"),
  312. }),
  313. new(
  314. "iqc_bill",
  315. SmartDiagnosisEvidenceDomain.Quality,
  316. new[] { "S5" },
  317. "inspection_bill",
  318. "/aidop/s5/iqc",
  319. """
  320. SELECT COUNT(*) FROM qms_qcp_inspbill
  321. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  322. """,
  323. """
  324. SELECT FBILLNO AS ObjectCode,
  325. CONCAT('IQC ',IFNULL(FBILLNO,''),' / ',IFNULL(FBILLSTATUS,'')) AS Title,
  326. 1 AS Contribution,
  327. CASE WHEN UPPER(IFNULL(FBILLSTATUS,'')) IN ('NG','REJECT','UNQUALIFIED') THEN 'red' ELSE 'yellow' END AS Status,
  328. NULL AS OccurredAt
  329. FROM qms_qcp_inspbill
  330. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  331. ORDER BY id DESC
  332. LIMIT @limit
  333. """,
  334. Array.Empty<SmartDiagnosisEvidenceFilterColumn>()),
  335. new(
  336. "fqc_result",
  337. SmartDiagnosisEvidenceDomain.Quality,
  338. new[] { "S7" },
  339. "inspection_bill",
  340. "/aidop/s7/fqc",
  341. """
  342. SELECT COUNT(*) FROM mdp_std_fqc_result
  343. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  344. """,
  345. """
  346. SELECT bill_no AS ObjectCode,
  347. CONCAT('FQC ',IFNULL(bill_no,''),' / ',IFNULL(material_code,'')) AS Title,
  348. GREATEST(IFNULL(unqualified_qty,0),0) AS Contribution,
  349. CASE WHEN IFNULL(unqualified_qty,0)>0 OR UPPER(IFNULL(judgment,'')) IN ('NG','FAIL','UNQUALIFIED') THEN 'red' ELSE 'green' END AS Status,
  350. inspect_time AS OccurredAt
  351. FROM mdp_std_fqc_result
  352. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  353. ORDER BY Contribution DESC, OccurredAt
  354. LIMIT @limit
  355. """,
  356. new[]
  357. {
  358. new SmartDiagnosisEvidenceFilterColumn("material", "material_code"),
  359. new SmartDiagnosisEvidenceFilterColumn("workOrder", "sap_work_order_no"),
  360. }),
  361. new(
  362. "s2_order_schedule_metric",
  363. SmartDiagnosisEvidenceDomain.Manufacturing,
  364. new[] { "S2" },
  365. "work_order",
  366. "/aidop/s2/production-scheduling/work-order-scheduling",
  367. """
  368. SELECT COUNT(*) FROM dwd_order_schedule_trans
  369. WHERE tenant_id=@tenantId
  370. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  371. AND (factory_id IS NULL OR factory_id<>@tenantId)
  372. AND IFNULL(work_order,'')<>''
  373. AND @metricCode IN ('S2_L1_001','S2_L1_002','S2_L1_003','S2_L1_004','S2_L2_001','S2_L2_002','S2_L2_003')
  374. AND (
  375. (@metricCode IN ('S2_L1_001','S2_L2_001') AND schedule_cycle_days IS NOT NULL)
  376. 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())))
  377. OR (@metricCode IN ('S2_L1_003','S2_L2_003'))
  378. OR (@metricCode='S2_L1_004' AND IFNULL(wip_qty,0)>0)
  379. )
  380. """,
  381. """
  382. SELECT work_order AS ObjectCode,
  383. CONCAT(IFNULL(sales_order_no,''),' / ',IFNULL(work_order,''),' / ',IFNULL(item_code,'')) AS Title,
  384. CASE
  385. WHEN @metricCode IN ('S2_L1_001','S2_L2_001') THEN IFNULL(schedule_cycle_days,0)
  386. WHEN @metricCode='S2_L1_004' THEN GREATEST(IFNULL(wip_qty,0),0)
  387. WHEN @metricCode IN ('S2_L1_003','S2_L2_003') THEN 1
  388. ELSE GREATEST(IFNULL(qty_ordered,0)-IFNULL(qty_completed,0),0)
  389. END AS Contribution,
  390. CASE
  391. WHEN IFNULL(schedule_satisfaction_flag,1)=0 OR (due_date IS NOT NULL AND due_date<CURDATE()) THEN 'red'
  392. WHEN IFNULL(wip_qty,0)>0 THEN 'yellow'
  393. ELSE 'green'
  394. END AS Status,
  395. COALESCE(due_date, stat_date) AS OccurredAt
  396. FROM dwd_order_schedule_trans
  397. WHERE tenant_id=@tenantId
  398. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  399. AND (factory_id IS NULL OR factory_id<>@tenantId)
  400. AND IFNULL(work_order,'')<>''
  401. AND @metricCode IN ('S2_L1_001','S2_L1_002','S2_L1_003','S2_L1_004','S2_L2_001','S2_L2_002','S2_L2_003')
  402. AND (
  403. (@metricCode IN ('S2_L1_001','S2_L2_001') AND schedule_cycle_days IS NOT NULL)
  404. 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())))
  405. OR (@metricCode IN ('S2_L1_003','S2_L2_003'))
  406. OR (@metricCode='S2_L1_004' AND IFNULL(wip_qty,0)>0)
  407. )
  408. ORDER BY Contribution DESC, OccurredAt
  409. LIMIT @limit
  410. """,
  411. new[]
  412. {
  413. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  414. new SmartDiagnosisEvidenceFilterColumn("orderNo", "sales_order_no"),
  415. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  416. new SmartDiagnosisEvidenceFilterColumn("productionLine", "prod_line"),
  417. })
  418. {
  419. ContributionUnit = "贡献",
  420. DateColumn = "stat_date",
  421. DrillQueryKey = "workOrder",
  422. MetricCodes = new[] { "S2_L1_001", "S2_L1_002", "S2_L1_003", "S2_L1_004", "S2_L2_001", "S2_L2_002", "S2_L2_003" }
  423. },
  424. new(
  425. "s2_operation_schedule_metric",
  426. SmartDiagnosisEvidenceDomain.Manufacturing,
  427. new[] { "S2" },
  428. "operation",
  429. "/aidop/s2/operation-plan/executable-daily-plan",
  430. """
  431. SELECT COUNT(*) FROM mdp_std_operation_schedule
  432. WHERE tenant_id=@tenantId
  433. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  434. AND (factory_id IS NULL OR factory_id<>@tenantId)
  435. AND IFNULL(work_order,'')<>''
  436. AND @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003','S2_L3_004','S2_L3_005','S2_L3_006')
  437. AND (
  438. @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003')
  439. OR IFNULL(COALESCE(NULLIF(work_center,''), NULLIF(line_code,'')), '')<>''
  440. )
  441. """,
  442. """
  443. SELECT CONCAT(IFNULL(work_order,''),':',IFNULL(op_no,'')) AS ObjectCode,
  444. CONCAT(IFNULL(work_order,''),' / 工序 ',IFNULL(op_no,''),' / ',IFNULL(COALESCE(NULLIF(work_center,''), line_code),'')) AS Title,
  445. CASE
  446. WHEN @metricCode IN ('S2_L3_001','S2_L3_004') THEN COALESCE(
  447. TIMESTAMPDIFF(HOUR, start_time, end_time) / 24,
  448. ABS(TIMESTAMPDIFF(DAY, plan_date, prod_date)),
  449. 0)
  450. ELSE 1
  451. END AS Contribution,
  452. CASE
  453. WHEN plan_date IS NOT NULL AND prod_date IS NOT NULL AND prod_date < plan_date THEN 'red'
  454. WHEN prod_date IS NULL THEN 'yellow'
  455. ELSE 'green'
  456. END AS Status,
  457. COALESCE(prod_date, plan_date, sync_time) AS OccurredAt
  458. FROM mdp_std_operation_schedule
  459. WHERE tenant_id=@tenantId
  460. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  461. AND (factory_id IS NULL OR factory_id<>@tenantId)
  462. AND IFNULL(work_order,'')<>''
  463. AND @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003','S2_L3_004','S2_L3_005','S2_L3_006')
  464. AND (
  465. @metricCode IN ('S2_L3_001','S2_L3_002','S2_L3_003')
  466. OR IFNULL(COALESCE(NULLIF(work_center,''), NULLIF(line_code,'')), '')<>''
  467. )
  468. ORDER BY Contribution DESC, OccurredAt
  469. LIMIT @limit
  470. """,
  471. new[]
  472. {
  473. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  474. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  475. new SmartDiagnosisEvidenceFilterColumn("productionLine", "line_code"),
  476. })
  477. {
  478. ContributionUnit = "贡献",
  479. DateColumn = "plan_date",
  480. DrillQueryKey = "workOrder",
  481. MetricCodes = new[] { "S2_L3_001", "S2_L3_002", "S2_L3_003", "S2_L3_004", "S2_L3_005", "S2_L3_006" }
  482. },
  483. new(
  484. "s3_supplier_delivery_metric",
  485. SmartDiagnosisEvidenceDomain.Supply,
  486. new[] { "S3" },
  487. "purchase_order",
  488. "/aidop/s3/procurement/purchase-order",
  489. """
  490. SELECT COUNT(*) FROM dwd_supplier_delivery
  491. WHERE tenant_id=@tenantId
  492. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  493. AND (factory_id IS NULL OR factory_id<>@tenantId)
  494. AND IFNULL(po_no,'')<>''
  495. AND @metricCode IN ('S3_L1_002','S3_L2_005','S3_L3_005')
  496. AND (IFNULL(remaining_qty,0)>0 OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE'))
  497. """,
  498. """
  499. SELECT po_no AS ObjectCode,
  500. CONCAT(IFNULL(supplier_name,supplier_code),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  501. GREATEST(IFNULL(remaining_qty,0),0) AS Contribution,
  502. CASE
  503. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED')
  504. OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE') THEN 'red'
  505. WHEN IFNULL(remaining_qty,0)>0 THEN 'yellow'
  506. ELSE 'green'
  507. END AS Status,
  508. COALESCE(due_date, stat_date) AS OccurredAt
  509. FROM dwd_supplier_delivery
  510. WHERE tenant_id=@tenantId
  511. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  512. AND (factory_id IS NULL OR factory_id<>@tenantId)
  513. AND IFNULL(po_no,'')<>''
  514. AND @metricCode IN ('S3_L1_002','S3_L2_005','S3_L3_005')
  515. AND (IFNULL(remaining_qty,0)>0 OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE'))
  516. ORDER BY Contribution DESC, OccurredAt
  517. LIMIT @limit
  518. """,
  519. new[]
  520. {
  521. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  522. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  523. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  524. })
  525. {
  526. ContributionUnit = "件",
  527. DateColumn = "stat_date",
  528. DrillQueryKey = "poNo",
  529. MetricCodes = new[] { "S3_L1_002", "S3_L2_005", "S3_L3_005" }
  530. },
  531. new(
  532. "s3_material_readiness_metric",
  533. SmartDiagnosisEvidenceDomain.Supply,
  534. new[] { "S3" },
  535. "work_order",
  536. "/aidop/s3/supply-kanban/work-order-material-readiness",
  537. """
  538. SELECT COUNT(*) FROM dwd_material_readiness
  539. WHERE tenant_id=@tenantId
  540. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  541. AND (factory_id IS NULL OR factory_id<>@tenantId)
  542. AND IFNULL(work_order,'')<>''
  543. AND @metricCode IN ('S3_L3_003','S3_L3_006')
  544. AND (
  545. (@metricCode='S3_L3_003' AND UPPER(IFNULL(ready_status,'')) NOT IN ('READY','SUFFICIENT','OK'))
  546. OR (@metricCode='S3_L3_006' AND IFNULL(shortage_qty,0)>0)
  547. )
  548. """,
  549. """
  550. SELECT work_order AS ObjectCode,
  551. CONCAT(IFNULL(work_order,''),' / ',IFNULL(component_item_code,parent_item_code),' / 缺料 ',IFNULL(shortage_qty,0)) AS Title,
  552. GREATEST(IFNULL(shortage_qty,0),1) AS Contribution,
  553. 'red' AS Status,
  554. COALESCE(need_date, stat_date) AS OccurredAt
  555. FROM dwd_material_readiness
  556. WHERE tenant_id=@tenantId
  557. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  558. AND (factory_id IS NULL OR factory_id<>@tenantId)
  559. AND IFNULL(work_order,'')<>''
  560. AND @metricCode IN ('S3_L3_003','S3_L3_006')
  561. AND (
  562. (@metricCode='S3_L3_003' AND UPPER(IFNULL(ready_status,'')) NOT IN ('READY','SUFFICIENT','OK'))
  563. OR (@metricCode='S3_L3_006' AND IFNULL(shortage_qty,0)>0)
  564. )
  565. ORDER BY Contribution DESC, OccurredAt
  566. LIMIT @limit
  567. """,
  568. new[]
  569. {
  570. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  571. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  572. new SmartDiagnosisEvidenceFilterColumn("material", "component_item_code"),
  573. })
  574. {
  575. ContributionUnit = "件",
  576. DateColumn = "stat_date",
  577. DrillQueryKey = "workOrder",
  578. MetricCodes = new[] { "S3_L3_003", "S3_L3_006" }
  579. },
  580. new(
  581. "s3_purchase_request_metric",
  582. SmartDiagnosisEvidenceDomain.Supply,
  583. new[] { "S3" },
  584. "purchase_request",
  585. "/aidop/s3/procurement/purchase-request",
  586. """
  587. SELECT COUNT(*) FROM mdp_std_purchase_request
  588. WHERE tenant_id=@tenantId
  589. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  590. AND (factory_id IS NULL OR factory_id<>@tenantId)
  591. AND IFNULL(pr_no,'')<>''
  592. AND @metricCode='S3_L3_001'
  593. """,
  594. """
  595. SELECT pr_no AS ObjectCode,
  596. CONCAT('PR ',IFNULL(pr_no,''),' / ',IFNULL(item_code,'')) AS Title,
  597. GREATEST(IFNULL(request_qty,0),0) AS Contribution,
  598. CASE WHEN send_date IS NULL THEN 'yellow' ELSE 'green' END AS Status,
  599. COALESCE(request_date, sync_time) AS OccurredAt
  600. FROM mdp_std_purchase_request
  601. WHERE tenant_id=@tenantId
  602. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  603. AND (factory_id IS NULL OR factory_id<>@tenantId)
  604. AND IFNULL(pr_no,'')<>''
  605. AND @metricCode='S3_L3_001'
  606. ORDER BY Contribution DESC, OccurredAt
  607. LIMIT @limit
  608. """,
  609. new[]
  610. {
  611. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  612. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  613. })
  614. {
  615. ContributionUnit = "件",
  616. DateColumn = "request_date",
  617. DrillQueryKey = "prNo",
  618. MetricCodes = new[] { "S3_L3_001" }
  619. },
  620. new(
  621. "s3_purchase_order_metric",
  622. SmartDiagnosisEvidenceDomain.Supply,
  623. new[] { "S3" },
  624. "purchase_order",
  625. "/aidop/s3/procurement/purchase-order",
  626. """
  627. SELECT COUNT(*) FROM mdp_std_purchase_order
  628. WHERE tenant_id=@tenantId
  629. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  630. AND (factory_id IS NULL OR factory_id<>@tenantId)
  631. AND IFNULL(po_no,'')<>''
  632. AND @metricCode='S3_L3_002'
  633. """,
  634. """
  635. SELECT po_no AS ObjectCode,
  636. CONCAT('PO ',IFNULL(po_no,''),' / ',IFNULL(item_code,'')) AS Title,
  637. GREATEST(IFNULL(order_qty,0),0) AS Contribution,
  638. 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,
  639. COALESCE(order_date, due_date, sync_time) AS OccurredAt
  640. FROM mdp_std_purchase_order
  641. WHERE tenant_id=@tenantId
  642. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  643. AND (factory_id IS NULL OR factory_id<>@tenantId)
  644. AND IFNULL(po_no,'')<>''
  645. AND @metricCode='S3_L3_002'
  646. ORDER BY Contribution DESC, OccurredAt
  647. LIMIT @limit
  648. """,
  649. new[]
  650. {
  651. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  652. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  653. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  654. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order"),
  655. })
  656. {
  657. ContributionUnit = "件",
  658. DateColumn = "order_date",
  659. DrillQueryKey = "poNo",
  660. MetricCodes = new[] { "S3_L3_002" }
  661. },
  662. new(
  663. "s3_delivery_schedule_metric",
  664. SmartDiagnosisEvidenceDomain.Supply,
  665. new[] { "S3" },
  666. "delivery_schedule",
  667. "/aidop/s3/material-plan/delivery-schedule",
  668. """
  669. SELECT COUNT(*) FROM mdp_std_delivery_schedule
  670. WHERE tenant_id=@tenantId
  671. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  672. AND (factory_id IS NULL OR factory_id<>@tenantId)
  673. AND IFNULL(delivery_plan_no,'')<>''
  674. AND @metricCode IN ('S3_L1_001','S3_L2_004','S3_L3_004')
  675. """,
  676. """
  677. SELECT delivery_plan_no AS ObjectCode,
  678. CONCAT(IFNULL(delivery_plan_no,''),' / ',IFNULL(po_no,''),' / ',IFNULL(item_code,'')) AS Title,
  679. CASE
  680. WHEN @metricCode='S3_L3_004' THEN GREATEST(IFNULL(rest_qty,0),1)
  681. ELSE GREATEST(IFNULL(DATEDIFF(IFNULL(last_sent_date,need_date), request_date),0),0)
  682. END AS Contribution,
  683. CASE
  684. WHEN IFNULL(rest_qty,0)>0 AND need_date IS NOT NULL AND need_date<CURDATE() THEN 'red'
  685. WHEN IFNULL(rest_qty,0)>0 THEN 'yellow'
  686. ELSE 'green'
  687. END AS Status,
  688. COALESCE(need_date, request_date, sync_time) AS OccurredAt
  689. FROM mdp_std_delivery_schedule
  690. WHERE tenant_id=@tenantId
  691. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  692. AND (factory_id IS NULL OR factory_id<>@tenantId)
  693. AND IFNULL(delivery_plan_no,'')<>''
  694. AND @metricCode IN ('S3_L1_001','S3_L2_004','S3_L3_004')
  695. ORDER BY Contribution DESC, OccurredAt
  696. LIMIT @limit
  697. """,
  698. new[]
  699. {
  700. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  701. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  702. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  703. })
  704. {
  705. ContributionUnit = "贡献",
  706. DateColumn = "need_date",
  707. DrillQueryKey = "planNo",
  708. MetricCodes = new[] { "S3_L1_001", "S3_L2_004", "S3_L3_004" }
  709. },
  710. new(
  711. "s4_supplier_delivery_metric",
  712. SmartDiagnosisEvidenceDomain.Supply,
  713. new[] { "S4" },
  714. "purchase_order",
  715. "/aidop/s4/delivery/supplier-delivery-management",
  716. """
  717. SELECT COUNT(*) FROM dwd_supplier_delivery
  718. WHERE tenant_id=@tenantId
  719. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  720. AND (factory_id IS NULL OR factory_id<>@tenantId)
  721. AND IFNULL(po_no,'')<>''
  722. AND @metricCode IN ('S4_L1_002','S4_L2_002','S4_L3_002','S4_L1_004')
  723. AND IFNULL(remaining_qty,0)>0
  724. """,
  725. """
  726. SELECT po_no AS ObjectCode,
  727. CONCAT(IFNULL(supplier_name,supplier_code),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  728. GREATEST(IFNULL(remaining_qty,0),0) AS Contribution,
  729. CASE
  730. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED')
  731. OR UPPER(IFNULL(delivery_status,'')) IN ('OVERDUE','DELAYED','LATE') THEN 'red'
  732. ELSE 'yellow'
  733. END AS Status,
  734. COALESCE(due_date, stat_date) AS OccurredAt
  735. FROM dwd_supplier_delivery
  736. WHERE tenant_id=@tenantId
  737. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  738. AND (factory_id IS NULL OR factory_id<>@tenantId)
  739. AND IFNULL(po_no,'')<>''
  740. AND @metricCode IN ('S4_L1_002','S4_L2_002','S4_L3_002','S4_L1_004')
  741. AND IFNULL(remaining_qty,0)>0
  742. ORDER BY Contribution DESC, OccurredAt
  743. LIMIT @limit
  744. """,
  745. new[]
  746. {
  747. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  748. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  749. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  750. })
  751. {
  752. ContributionUnit = "件",
  753. DateColumn = "stat_date",
  754. DrillQueryKey = "poNo",
  755. MetricCodes = new[] { "S4_L1_002", "S4_L2_002", "S4_L3_002", "S4_L1_004" }
  756. },
  757. new(
  758. "s4_delivery_cycle_metric",
  759. SmartDiagnosisEvidenceDomain.Supply,
  760. new[] { "S4" },
  761. "delivery_schedule",
  762. "/aidop/s4/delivery/supplier-shipment",
  763. """
  764. SELECT COUNT(*) FROM mdp_std_delivery_schedule
  765. WHERE tenant_id=@tenantId
  766. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  767. AND (factory_id IS NULL OR factory_id<>@tenantId)
  768. AND IFNULL(delivery_plan_no,'')<>''
  769. AND @metricCode IN ('S4_L1_001','S4_L2_001','S4_L3_001')
  770. """,
  771. """
  772. SELECT delivery_plan_no AS ObjectCode,
  773. CONCAT(IFNULL(delivery_plan_no,''),' / ',IFNULL(po_no,''),' / ',IFNULL(item_code,'')) AS Title,
  774. GREATEST(IFNULL(DATEDIFF(IFNULL(last_sent_date,need_date), request_date),0),0) AS Contribution,
  775. CASE
  776. WHEN need_date IS NOT NULL AND last_sent_date IS NOT NULL AND last_sent_date>need_date THEN 'red'
  777. WHEN last_sent_date IS NULL THEN 'yellow'
  778. ELSE 'green'
  779. END AS Status,
  780. COALESCE(last_sent_date, need_date, sync_time) AS OccurredAt
  781. FROM mdp_std_delivery_schedule
  782. WHERE tenant_id=@tenantId
  783. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  784. AND (factory_id IS NULL OR factory_id<>@tenantId)
  785. AND IFNULL(delivery_plan_no,'')<>''
  786. AND @metricCode IN ('S4_L1_001','S4_L2_001','S4_L3_001')
  787. ORDER BY Contribution DESC, OccurredAt
  788. LIMIT @limit
  789. """,
  790. new[]
  791. {
  792. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  793. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  794. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  795. })
  796. {
  797. ContributionUnit = "天",
  798. DateColumn = "need_date",
  799. DrillQueryKey = "planNo",
  800. MetricCodes = new[] { "S4_L1_001", "S4_L2_001", "S4_L3_001" }
  801. },
  802. new(
  803. "s4_purchase_execution_metric",
  804. SmartDiagnosisEvidenceDomain.Supply,
  805. new[] { "S4" },
  806. "purchase_order",
  807. "/aidop/s4/execution-kanban/supplier-shortage-kanban",
  808. """
  809. SELECT COUNT(*) FROM dwd_s4_purchase_execution
  810. WHERE tenant_id=@tenantId
  811. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  812. AND (factory_id IS NULL OR factory_id<>@tenantId)
  813. AND IFNULL(po_no,'')<>''
  814. AND @metricCode IN ('S4_L2_003','S4_L3_003','S4_L2_004','S4_L3_004')
  815. """,
  816. """
  817. SELECT po_no AS ObjectCode,
  818. CONCAT(IFNULL(supplier_code,''),' / ',IFNULL(item_code,''),' / ',IFNULL(po_no,'')) AS Title,
  819. CASE
  820. 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))
  821. ELSE 1
  822. END AS Contribution,
  823. CASE
  824. WHEN UPPER(IFNULL(risk_level,'')) IN ('HIGH','RED') THEN 'red'
  825. WHEN IFNULL(shortage_qty,0)>0 THEN 'yellow'
  826. ELSE 'green'
  827. END AS Status,
  828. COALESCE(due_date, actual_arrival_date, stat_date) AS OccurredAt
  829. FROM dwd_s4_purchase_execution
  830. WHERE tenant_id=@tenantId
  831. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  832. AND (factory_id IS NULL OR factory_id<>@tenantId)
  833. AND IFNULL(po_no,'')<>''
  834. AND @metricCode IN ('S4_L2_003','S4_L3_003','S4_L2_004','S4_L3_004')
  835. ORDER BY Contribution DESC, OccurredAt
  836. LIMIT @limit
  837. """,
  838. new[]
  839. {
  840. new SmartDiagnosisEvidenceFilterColumn("poNo", "po_no"),
  841. new SmartDiagnosisEvidenceFilterColumn("supplier", "supplier_code"),
  842. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  843. })
  844. {
  845. ContributionUnit = "贡献",
  846. DateColumn = "stat_date",
  847. DrillQueryKey = "poNo",
  848. MetricCodes = new[] { "S4_L2_003", "S4_L3_003", "S4_L2_004", "S4_L3_004" }
  849. },
  850. new(
  851. "s5_material_online_cycle_metric",
  852. SmartDiagnosisEvidenceDomain.Supply,
  853. new[] { "S5" },
  854. "material",
  855. "/aidop/s5/inventory/inout-query",
  856. """
  857. SELECT COUNT(*) FROM dwd_material_online_cycle
  858. WHERE tenant_id=@tenantId
  859. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  860. AND (factory_id IS NULL OR factory_id<>@tenantId)
  861. AND IFNULL(item_code,'')<>''
  862. AND @metricCode='S5_L1_001'
  863. AND cycle_days IS NOT NULL
  864. """,
  865. """
  866. SELECT item_code AS ObjectCode,
  867. CONCAT('物料上线周期 ',IFNULL(item_code,''),' / ',IFNULL(cycle_days,0),'天') AS Title,
  868. IFNULL(cycle_days,0) AS Contribution,
  869. CASE WHEN IFNULL(cycle_days,0)>7 THEN 'red' WHEN IFNULL(cycle_days,0)>3 THEN 'yellow' ELSE 'green' END AS Status,
  870. biz_date AS OccurredAt
  871. FROM dwd_material_online_cycle
  872. WHERE tenant_id=@tenantId
  873. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  874. AND (factory_id IS NULL OR factory_id<>@tenantId)
  875. AND IFNULL(item_code,'')<>''
  876. AND @metricCode='S5_L1_001'
  877. AND cycle_days IS NOT NULL
  878. ORDER BY Contribution DESC, OccurredAt
  879. LIMIT @limit
  880. """,
  881. new[]
  882. {
  883. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  884. })
  885. {
  886. ContributionUnit = "天",
  887. DateColumn = "biz_date",
  888. DrillQueryKey = "material",
  889. MetricCodes = new[] { "S5_L1_001" }
  890. },
  891. new(
  892. "s5_material_online_fulfillment_metric",
  893. SmartDiagnosisEvidenceDomain.Supply,
  894. new[] { "S5" },
  895. "work_order",
  896. "/aidop/s5/warehouse/production-issue",
  897. """
  898. SELECT COUNT(*) FROM dwd_material_online_fulfillment
  899. WHERE tenant_id=@tenantId
  900. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  901. AND (factory_id IS NULL OR factory_id<>@tenantId)
  902. AND IFNULL(work_order_no,'')<>''
  903. AND @metricCode='S5_L1_002'
  904. """,
  905. """
  906. SELECT work_order_no AS ObjectCode,
  907. CONCAT('工单 ',IFNULL(work_order_no,''),' / 上线 ',IFNULL(before_kgdate_rows,0),'/',IFNULL(total_rows,0)) AS Title,
  908. GREATEST(IFNULL(total_rows,0)-IFNULL(before_kgdate_rows,0),0) AS Contribution,
  909. CASE WHEN IFNULL(fulfillment_rate,1)<1 THEN 'red' ELSE 'green' END AS Status,
  910. biz_date AS OccurredAt
  911. FROM dwd_material_online_fulfillment
  912. WHERE tenant_id=@tenantId
  913. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  914. AND (factory_id IS NULL OR factory_id<>@tenantId)
  915. AND IFNULL(work_order_no,'')<>''
  916. AND @metricCode='S5_L1_002'
  917. ORDER BY Contribution DESC, OccurredAt
  918. LIMIT @limit
  919. """,
  920. new[]
  921. {
  922. new SmartDiagnosisEvidenceFilterColumn("workOrder", "work_order_no"),
  923. })
  924. {
  925. ContributionUnit = "行",
  926. DateColumn = "biz_date",
  927. DrillQueryKey = "workOrder",
  928. MetricCodes = new[] { "S5_L1_002" }
  929. },
  930. new(
  931. "s5_iqc_bill_metric",
  932. SmartDiagnosisEvidenceDomain.Quality,
  933. new[] { "S5" },
  934. "inspection_bill",
  935. "/aidop/s5/iqc/result-list",
  936. """
  937. SELECT COUNT(*) FROM qms_qcp_inspbill
  938. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  939. AND @metricCode='S5_L2_004'
  940. """,
  941. """
  942. SELECT FBILLNO AS ObjectCode,
  943. CONCAT('IQC ',IFNULL(FBILLNO,''),' / ',IFNULL(FBILLSTATUS,'')) AS Title,
  944. 1 AS Contribution,
  945. CASE WHEN UPPER(IFNULL(FBILLSTATUS,'')) IN ('NG','REJECT','UNQUALIFIED') THEN 'red' ELSE 'yellow' END AS Status,
  946. NULL AS OccurredAt
  947. FROM qms_qcp_inspbill
  948. WHERE tenant_id=@tenantId AND IFNULL(FBILLNO,'')<>''
  949. AND @metricCode='S5_L2_004'
  950. ORDER BY id DESC
  951. LIMIT @limit
  952. """,
  953. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  954. {
  955. ContributionUnit = "单",
  956. DrillQueryKey = "billNo",
  957. MetricCodes = new[] { "S5_L2_004" }
  958. },
  959. new(
  960. "s6_work_order_fulfillment_metric",
  961. SmartDiagnosisEvidenceDomain.Manufacturing,
  962. new[] { "S6" },
  963. "work_order",
  964. "/aidop/s6/production-record/order-list",
  965. """
  966. SELECT COUNT(*) FROM dwd_work_order_mfg_fulfillment
  967. WHERE tenant_id=@tenantId
  968. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  969. AND (factory_id IS NULL OR factory_id<>@tenantId)
  970. AND IFNULL(order_no,'')<>''
  971. AND @metricCode IN ('S6_L1_002','S6_L2_002')
  972. """,
  973. """
  974. SELECT COALESCE(NULLIF(task_no,''), order_no) AS ObjectCode,
  975. CONCAT(IFNULL(order_no,''),' / ',IFNULL(task_no,''),' / ',IFNULL(item_code,'')) AS Title,
  976. GREATEST(IFNULL(plan_qty,0)-IFNULL(done_qty_in_window,0),0) AS Contribution,
  977. CASE WHEN IFNULL(fulfillment_rate,1)<1 THEN 'red' ELSE 'green' END AS Status,
  978. biz_date AS OccurredAt
  979. FROM dwd_work_order_mfg_fulfillment
  980. WHERE tenant_id=@tenantId
  981. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  982. AND (factory_id IS NULL OR factory_id<>@tenantId)
  983. AND IFNULL(order_no,'')<>''
  984. AND @metricCode IN ('S6_L1_002','S6_L2_002')
  985. ORDER BY Contribution DESC, OccurredAt
  986. LIMIT @limit
  987. """,
  988. new[]
  989. {
  990. new SmartDiagnosisEvidenceFilterColumn("orderNo", "order_no"),
  991. new SmartDiagnosisEvidenceFilterColumn("workOrder", "task_no"),
  992. new SmartDiagnosisEvidenceFilterColumn("material", "item_code"),
  993. })
  994. {
  995. ContributionUnit = "件",
  996. DateColumn = "biz_date",
  997. DrillQueryKey = "orderNo",
  998. MetricCodes = new[] { "S6_L1_002", "S6_L2_002" }
  999. },
  1000. new(
  1001. "s7_shipment_cycle_metric",
  1002. SmartDiagnosisEvidenceDomain.Delivery,
  1003. new[] { "S7" },
  1004. "sales_order",
  1005. "/aidop/s7/finished-outbound/sales-shipment-notice",
  1006. """
  1007. SELECT COUNT(*) FROM dwd_order_shipment_cycle
  1008. WHERE tenant_id=@tenantId
  1009. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1010. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1011. AND IFNULL(order_no,'')<>''
  1012. AND @metricCode='S7_L1_001'
  1013. AND cycle_days IS NOT NULL
  1014. """,
  1015. """
  1016. SELECT order_no AS ObjectCode,
  1017. CONCAT('发货周期 ',IFNULL(order_no,''),' / ',IFNULL(cycle_days,0),'天') AS Title,
  1018. IFNULL(cycle_days,0) AS Contribution,
  1019. CASE WHEN IFNULL(cycle_days,0)>7 THEN 'red' WHEN IFNULL(cycle_days,0)>3 THEN 'yellow' ELSE 'green' END AS Status,
  1020. biz_date AS OccurredAt
  1021. FROM dwd_order_shipment_cycle
  1022. WHERE tenant_id=@tenantId
  1023. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1024. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1025. AND IFNULL(order_no,'')<>''
  1026. AND @metricCode='S7_L1_001'
  1027. AND cycle_days IS NOT NULL
  1028. ORDER BY Contribution DESC, OccurredAt
  1029. LIMIT @limit
  1030. """,
  1031. new[]
  1032. {
  1033. new SmartDiagnosisEvidenceFilterColumn("orderNo", "order_no"),
  1034. })
  1035. {
  1036. ContributionUnit = "天",
  1037. DateColumn = "biz_date",
  1038. DrillQueryKey = "orderNo",
  1039. MetricCodes = new[] { "S7_L1_001" }
  1040. },
  1041. new(
  1042. "s7_shipment_fulfillment_metric",
  1043. SmartDiagnosisEvidenceDomain.Delivery,
  1044. new[] { "S7" },
  1045. "sales_order",
  1046. "/aidop/s7/finished-outbound/sales-shipment-notice",
  1047. """
  1048. SELECT COUNT(*) FROM dwd_order_shipment_fulfillment
  1049. WHERE tenant_id=@tenantId
  1050. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1051. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1052. AND IFNULL(order_no,'')<>''
  1053. AND @metricCode='S7_L1_002'
  1054. """,
  1055. """
  1056. SELECT order_no AS ObjectCode,
  1057. CONCAT('发货满足 ',IFNULL(order_no,''),' / ',IFNULL(in_window_rows,0),'/',IFNULL(total_rows,0)) AS Title,
  1058. GREATEST(IFNULL(total_rows,0)-IFNULL(in_window_rows,0),0) AS Contribution,
  1059. CASE WHEN IFNULL(fulfillment_rate,100)<100 THEN 'red' ELSE 'green' END AS Status,
  1060. biz_date AS OccurredAt
  1061. FROM dwd_order_shipment_fulfillment
  1062. WHERE tenant_id=@tenantId
  1063. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId)
  1064. AND (factory_id IS NULL OR factory_id<>@tenantId)
  1065. AND IFNULL(order_no,'')<>''
  1066. AND @metricCode='S7_L1_002'
  1067. ORDER BY Contribution DESC, OccurredAt
  1068. LIMIT @limit
  1069. """,
  1070. new[]
  1071. {
  1072. new SmartDiagnosisEvidenceFilterColumn("orderNo", "order_no"),
  1073. })
  1074. {
  1075. ContributionUnit = "行",
  1076. DateColumn = "biz_date",
  1077. DrillQueryKey = "orderNo",
  1078. MetricCodes = new[] { "S7_L1_002" }
  1079. },
  1080. new(
  1081. "s7_fqc_result_metric",
  1082. SmartDiagnosisEvidenceDomain.Quality,
  1083. new[] { "S7" },
  1084. "inspection_bill",
  1085. "/aidop/s7/fqc/result-list",
  1086. """
  1087. SELECT COUNT(*) FROM mdp_std_fqc_result
  1088. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  1089. AND @metricCode='S7_L2_002'
  1090. """,
  1091. """
  1092. SELECT bill_no AS ObjectCode,
  1093. CONCAT('FQC ',IFNULL(bill_no,''),' / ',IFNULL(material_code,'')) AS Title,
  1094. GREATEST(IFNULL(unqualified_qty,0),0) AS Contribution,
  1095. CASE WHEN IFNULL(unqualified_qty,0)>0 OR UPPER(IFNULL(judgment,'')) IN ('NG','FAIL','UNQUALIFIED') THEN 'red' ELSE 'green' END AS Status,
  1096. inspect_time AS OccurredAt
  1097. FROM mdp_std_fqc_result
  1098. WHERE tenant_id=@tenantId AND IFNULL(bill_no,'')<>''
  1099. AND @metricCode='S7_L2_002'
  1100. ORDER BY Contribution DESC, OccurredAt
  1101. LIMIT @limit
  1102. """,
  1103. new[]
  1104. {
  1105. new SmartDiagnosisEvidenceFilterColumn("material", "material_code"),
  1106. new SmartDiagnosisEvidenceFilterColumn("workOrder", "sap_work_order_no"),
  1107. })
  1108. {
  1109. ContributionUnit = "件",
  1110. DateColumn = "inspect_time",
  1111. DrillQueryKey = "billNo",
  1112. MetricCodes = new[] { "S7_L2_002" }
  1113. },
  1114. new(
  1115. "s9_quality_return_txn_metric",
  1116. SmartDiagnosisEvidenceDomain.Quality,
  1117. new[] { "S9" },
  1118. "sales_return",
  1119. "/aidop/s7/finished-outbound/sales-shipment-notice",
  1120. """
  1121. SELECT COUNT(*)
  1122. FROM mdp_std_inv_trans
  1123. WHERE tenant_id=@tenantId
  1124. AND summary_flag=0 AND void_flag=0 AND approved_flag=1
  1125. AND biz_doc_type='SALES_RETURN'
  1126. AND @metricCode='S9_L1_001'
  1127. """,
  1128. """
  1129. SELECT COALESCE(NULLIF(ref_task_no,''), item_num, src_rec_id) AS ObjectCode,
  1130. CONCAT('退货 ',IFNULL(ref_task_no,src_rec_id),' / ',IFNULL(item_num,'')) AS Title,
  1131. ABS(IFNULL(qty_change,0)) AS Contribution,
  1132. 'red' AS Status,
  1133. approved_time AS OccurredAt
  1134. FROM mdp_std_inv_trans
  1135. WHERE tenant_id=@tenantId
  1136. AND summary_flag=0 AND void_flag=0 AND approved_flag=1
  1137. AND biz_doc_type='SALES_RETURN'
  1138. AND @metricCode='S9_L1_001'
  1139. ORDER BY Contribution DESC, OccurredAt
  1140. LIMIT @limit
  1141. """,
  1142. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  1143. {
  1144. ContributionUnit = "件",
  1145. DateColumn = "approved_time",
  1146. DrillQueryKey = "orderNo",
  1147. MetricCodes = new[] { "S9_L1_001" }
  1148. },
  1149. new(
  1150. "s9_order_delivery_cycle_metric",
  1151. SmartDiagnosisEvidenceDomain.Delivery,
  1152. new[] { "S9" },
  1153. "segment_cycle",
  1154. "/aidop/smart-ops/grid",
  1155. """
  1156. SELECT COUNT(*)
  1157. FROM ado_s9_kpi_value_l1_day
  1158. WHERE tenant_id=@tenantId AND is_deleted=0 AND metric_value IS NOT NULL
  1159. AND metric_code IN ('S1_L1_001','S2_L1_001','S3_L1_001','S5_L1_001','S6_L1_001','S7_L1_001')
  1160. AND @metricCode='S9_L1_002'
  1161. """,
  1162. """
  1163. SELECT metric_code AS ObjectCode,
  1164. metric_code AS Title,
  1165. metric_value AS Contribution,
  1166. 'blue' AS Status,
  1167. biz_date AS OccurredAt
  1168. FROM ado_s9_kpi_value_l1_day
  1169. WHERE tenant_id=@tenantId AND is_deleted=0 AND metric_value IS NOT NULL
  1170. AND metric_code IN ('S1_L1_001','S2_L1_001','S3_L1_001','S5_L1_001','S6_L1_001','S7_L1_001')
  1171. AND @metricCode='S9_L1_002'
  1172. ORDER BY metric_code
  1173. LIMIT @limit
  1174. """,
  1175. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  1176. {
  1177. ContributionUnit = "天",
  1178. DateColumn = "biz_date",
  1179. DrillQueryKey = "metricCode",
  1180. MetricCodes = new[] { "S9_L1_002" }
  1181. },
  1182. new(
  1183. "s9_order_delivery_fulfillment_metric",
  1184. SmartDiagnosisEvidenceDomain.Delivery,
  1185. new[] { "S9" },
  1186. "sales_order_line",
  1187. "/aidop/smart-ops/grid",
  1188. """
  1189. SELECT COUNT(*)
  1190. FROM mdp_std_so
  1191. WHERE tenant_id=@tenantId AND deleted_flag=0
  1192. AND IFNULL(order_qty,0) > 0
  1193. AND IFNULL(delivered_qty,0) >= order_qty
  1194. AND @metricCode='S9_L1_003'
  1195. """,
  1196. """
  1197. SELECT CONCAT(order_no, ':', IFNULL(order_line,'')) AS ObjectCode,
  1198. CONCAT(order_no, ' / ', IFNULL(item_code,'')) AS Title,
  1199. delivered_qty AS Contribution,
  1200. 'blue' AS Status,
  1201. order_date AS OccurredAt
  1202. FROM mdp_std_so
  1203. WHERE tenant_id=@tenantId AND deleted_flag=0
  1204. AND IFNULL(order_qty,0) > 0
  1205. AND IFNULL(delivered_qty,0) >= order_qty
  1206. AND @metricCode='S9_L1_003'
  1207. ORDER BY order_date DESC
  1208. LIMIT @limit
  1209. """,
  1210. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  1211. {
  1212. ContributionUnit = "件",
  1213. DateColumn = "order_date",
  1214. DrillQueryKey = "orderNo",
  1215. MetricCodes = new[] { "S9_L1_003" }
  1216. },
  1217. new(
  1218. "s9_production_efficiency_metric",
  1219. SmartDiagnosisEvidenceDomain.Manufacturing,
  1220. new[] { "S9" },
  1221. "line_status",
  1222. "/aidop/smart-ops/grid",
  1223. """
  1224. SELECT COUNT(*)
  1225. FROM mdp_stg_line_status
  1226. WHERE tenant_id=@tenantId
  1227. AND (JSON_EXTRACT(raw_data,'$.RestTime') IS NOT NULL
  1228. OR JSON_EXTRACT(raw_data,'$.ProdDownTime') IS NOT NULL)
  1229. AND @metricCode='S9_L1_004'
  1230. """,
  1231. """
  1232. SELECT source_row_id AS ObjectCode,
  1233. source_biz_key AS Title,
  1234. CAST(JSON_UNQUOTE(JSON_EXTRACT(raw_data,'$.ProdTime')) AS DECIMAL(18,4)) AS Contribution,
  1235. 'blue' AS Status,
  1236. sync_time AS OccurredAt
  1237. FROM mdp_stg_line_status
  1238. WHERE tenant_id=@tenantId
  1239. AND (JSON_EXTRACT(raw_data,'$.RestTime') IS NOT NULL
  1240. OR JSON_EXTRACT(raw_data,'$.ProdDownTime') IS NOT NULL)
  1241. AND @metricCode='S9_L1_004'
  1242. ORDER BY sync_time DESC
  1243. LIMIT @limit
  1244. """,
  1245. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  1246. {
  1247. ContributionUnit = "小时",
  1248. DateColumn = "sync_time",
  1249. DrillQueryKey = "sourceRowId",
  1250. MetricCodes = new[] { "S9_L1_004" }
  1251. },
  1252. new(
  1253. "s9_inventory_turnover_metric",
  1254. SmartDiagnosisEvidenceDomain.Supply,
  1255. new[] { "S9" },
  1256. "turnover_segment",
  1257. "/aidop/smart-ops/grid",
  1258. """
  1259. SELECT COUNT(*)
  1260. FROM ado_s9_kpi_value_l1_day
  1261. WHERE tenant_id=@tenantId AND is_deleted=0 AND metric_value IS NOT NULL
  1262. AND metric_code IN ('S1_L1_004','S2_L1_004','S3_L1_004')
  1263. AND @metricCode='S9_L1_005'
  1264. """,
  1265. """
  1266. SELECT metric_code AS ObjectCode,
  1267. metric_code AS Title,
  1268. metric_value AS Contribution,
  1269. 'blue' AS Status,
  1270. biz_date AS OccurredAt
  1271. FROM ado_s9_kpi_value_l1_day
  1272. WHERE tenant_id=@tenantId AND is_deleted=0 AND metric_value IS NOT NULL
  1273. AND metric_code IN ('S1_L1_004','S2_L1_004','S3_L1_004')
  1274. AND @metricCode='S9_L1_005'
  1275. ORDER BY metric_code
  1276. LIMIT @limit
  1277. """,
  1278. Array.Empty<SmartDiagnosisEvidenceFilterColumn>())
  1279. {
  1280. ContributionUnit = "天",
  1281. DateColumn = "biz_date",
  1282. DrillQueryKey = "metricCode",
  1283. MetricCodes = new[] { "S9_L1_005" }
  1284. },
  1285. new(
  1286. "s8_exception",
  1287. SmartDiagnosisEvidenceDomain.Exception,
  1288. new[] { "S8" },
  1289. "s8_exception",
  1290. "/aidop/s8/exceptions",
  1291. """
  1292. SELECT COUNT(*) FROM ado_s8_exception
  1293. WHERE tenant_id=@tenantId AND IFNULL(is_deleted,0)=0
  1294. AND IFNULL(exception_code,'')<>''
  1295. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId
  1296. OR (@factoryId IN (0,1) AND factory_id<>@tenantId))
  1297. """,
  1298. """
  1299. SELECT exception_code AS ObjectCode,
  1300. CONCAT(IFNULL(exception_code,''),' / ',IFNULL(title,'')) AS Title,
  1301. GREATEST(IFNULL(priority_score,0),0) AS Contribution,
  1302. CASE
  1303. WHEN UPPER(IFNULL(status,'')) IN ('CLOSED','CANCELLED','CANCELED') THEN 'green'
  1304. WHEN UPPER(IFNULL(severity,'')) IN ('SERIOUS','CRITICAL','HIGH') THEN 'red'
  1305. ELSE 'yellow'
  1306. END AS Status,
  1307. created_at AS OccurredAt
  1308. FROM ado_s8_exception
  1309. WHERE tenant_id=@tenantId AND IFNULL(is_deleted,0)=0
  1310. AND IFNULL(exception_code,'')<>''
  1311. AND (factory_id IS NULL OR factory_id=0 OR factory_id=1 OR factory_id=@factoryId
  1312. OR (@factoryId IN (0,1) AND factory_id<>@tenantId))
  1313. ORDER BY Contribution DESC, OccurredAt
  1314. LIMIT @limit
  1315. """,
  1316. new[]
  1317. {
  1318. new SmartDiagnosisEvidenceFilterColumn("orderNo", "related_object_code"),
  1319. }),
  1320. Evidence("s3_planner_efficiency_metric", SmartDiagnosisEvidenceDomain.Supply, "S3", "purchase_request",
  1321. "/aidop/s3/procurement/purchase-request", "mdp_std_purchase_request", "pr_no", "request_qty", "request_date",
  1322. new[] { "S3_L1_003", "S3_L2_001", "S3_L2_002", "S3_L2_003", "S3_L2_006" }, "item_code"),
  1323. Evidence("s3_material_turnover_metric", SmartDiagnosisEvidenceDomain.Supply, "S3", "item",
  1324. "/aidop/s5/inventory/inout-query", "mdp_std_inv_trans", "item_num", "qty_change", "approved_time",
  1325. new[] { "S3_L1_004" }, "item_num"),
  1326. Evidence("s4_purchase_efficiency_metric", SmartDiagnosisEvidenceDomain.Supply, "S4", "purchase_order",
  1327. "/aidop/s3/procurement/purchase-order", "mdp_std_purchase_order", "po_no", "order_qty", "sync_time",
  1328. new[] { "S4_L1_003" }, "item_code"),
  1329. Evidence("s5_warehouse_efficiency_metric", SmartDiagnosisEvidenceDomain.Supply, "S5", "item",
  1330. "/aidop/s5/warehouse/production-issue", "mdp_std_inv_trans", "item_num", "qty_change", "approved_time",
  1331. new[] { "S5_L1_003", "S5_L2_003", "S5_L2_006", "S5_L3_001", "S5_L3_003" }, "item_num"),
  1332. Evidence("s5_balance_turnover_metric", SmartDiagnosisEvidenceDomain.Supply, "S5", "item",
  1333. "/aidop/s5/warehouse-kanban/turnover-report", "mdp_std_inventory_balance_monthly", "item_code", "avg_balance_amount", "period_ym",
  1334. new[] { "S5_L1_004" }, "item_code"),
  1335. Evidence("s6_manufacture_cycle_metric", SmartDiagnosisEvidenceDomain.Manufacturing, "S6", "work_order",
  1336. "/aidop/s6/production-record/order-list", "mdp_std_work_order_line", "task_no", "qty_planned", "release_time",
  1337. new[] { "S6_L1_001", "S6_L2_004" }, "item_code"),
  1338. Evidence("s6_report_metric", SmartDiagnosisEvidenceDomain.Manufacturing, "S6", "work_order",
  1339. "/aidop/s6/production-record/order-list", "mdp_std_s6_report", "work_order_no", "report_qty", "report_date",
  1340. new[] { "S6_L1_003", "S6_L2_003", "S6_L3_007" }, "work_order_no"),
  1341. Evidence("s7_fqc_metric", SmartDiagnosisEvidenceDomain.Quality, "S7", "fqc_task",
  1342. "/aidop/s7/fqc/task-list", "mdp_std_fqc_task", "bill_no", "qty", "inspect_start_time",
  1343. new[] { "S7_L2_001", "S7_L2_003" }, "material_code"),
  1344. Evidence("s7_ship_recon_metric", SmartDiagnosisEvidenceDomain.Delivery, "S7", "sales_order",
  1345. "/aidop/s7/finished-outbound/sales-shipment-notice", "mdp_ship_recon_diff", "ord_nbr", "diff_qty", "biz_date",
  1346. new[] { "S7_L1_003", "S7_L2_004" }, "ord_nbr"),
  1347. };
  1348. private static SmartDiagnosisEvidenceSource Evidence(
  1349. string key, SmartDiagnosisEvidenceDomain domain, string module, string objectType, string drillPath,
  1350. string table, string objectColumn, string qtyColumn, string dateColumn,
  1351. string[] metricCodes, string filterColumn)
  1352. {
  1353. var list = string.Join(",", metricCodes.Select(c => $"'{c}'"));
  1354. var where = $"""
  1355. WHERE tenant_id=@tenantId
  1356. AND @metricCode IN ({list})
  1357. """;
  1358. return new SmartDiagnosisEvidenceSource(
  1359. key, domain, new[] { module }, objectType, drillPath,
  1360. $"SELECT COUNT(*) FROM {table}\n{where}",
  1361. $"""
  1362. SELECT {objectColumn} AS ObjectCode,
  1363. {objectColumn} AS Title,
  1364. IFNULL({qtyColumn},0) AS Contribution,
  1365. 'blue' AS Status,
  1366. {dateColumn} AS OccurredAt
  1367. FROM {table}
  1368. {where}
  1369. ORDER BY Contribution DESC, OccurredAt
  1370. LIMIT @limit
  1371. """,
  1372. new[] { new SmartDiagnosisEvidenceFilterColumn("material", filterColumn) })
  1373. {
  1374. MetricCodes = metricCodes,
  1375. DateColumn = dateColumn,
  1376. DrillQueryKey = "material"
  1377. };
  1378. }
  1379. public static IReadOnlyList<SmartDiagnosisEvidenceSource> All => Sources;
  1380. public static IReadOnlyList<SmartDiagnosisEvidenceSource> Resolve(string moduleCode)
  1381. {
  1382. var mc = (moduleCode ?? "").Trim().ToUpperInvariant();
  1383. if (mc == "S9")
  1384. return Sources.Where(x => x.Key != "s8_exception" && x.MetricCodes.Count == 0).ToList();
  1385. return Sources
  1386. .Where(x => x.MetricCodes.Count == 0
  1387. && x.Modules.Contains(mc, StringComparer.OrdinalIgnoreCase))
  1388. .ToList();
  1389. }
  1390. public static IReadOnlyList<SmartDiagnosisEvidenceSource> ResolveMetric(
  1391. string moduleCode,
  1392. string metricCode)
  1393. {
  1394. var mc = (moduleCode ?? "").Trim().ToUpperInvariant();
  1395. var metric = (metricCode ?? "").Trim().ToUpperInvariant();
  1396. if (mc.Length == 0 || metric.Length == 0)
  1397. return Array.Empty<SmartDiagnosisEvidenceSource>();
  1398. return Sources
  1399. .Where(x => x.Modules.Contains(mc, StringComparer.OrdinalIgnoreCase)
  1400. && x.MetricCodes.Contains(metric, StringComparer.OrdinalIgnoreCase))
  1401. .ToList();
  1402. }
  1403. public static SmartDiagnosisEvidenceSource? Get(string key) =>
  1404. Sources.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
  1405. }
  1406. public sealed class SmartDiagnosisEvidenceItem
  1407. {
  1408. public string ObjectType { get; set; } = "";
  1409. public string ObjectCode { get; set; } = "";
  1410. public string Title { get; set; } = "";
  1411. public decimal? Contribution { get; set; }
  1412. public string ContributionUnit { get; set; } = "";
  1413. public string Status { get; set; } = "green";
  1414. public string? OccurredAt { get; set; }
  1415. public string? DrillPath { get; set; }
  1416. }
  1417. public sealed class SmartDiagnosisEvidenceResult
  1418. {
  1419. public string Scope { get; set; } = "no_data";
  1420. public string? MetricCode { get; set; }
  1421. public string MatchScope { get; set; } = "module";
  1422. public string? AsOf { get; set; }
  1423. public string Domain { get; set; } = "";
  1424. public int Total { get; set; }
  1425. public int Returned { get; set; }
  1426. public bool Truncated { get; set; }
  1427. public List<string> Sources { get; set; } = new();
  1428. public List<SmartDiagnosisEvidenceItem> Items { get; set; } = new();
  1429. }
  1430. internal sealed class SmartDiagnosisEvidenceSqlRow
  1431. {
  1432. public string? ObjectCode { get; set; }
  1433. public string? Title { get; set; }
  1434. public decimal? Contribution { get; set; }
  1435. public string? Status { get; set; }
  1436. public DateTime? OccurredAt { get; set; }
  1437. }