云
5 天以前 9bad721754fe8bbe2e5f459d0706e0fefac569f3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MOM 工厂数字化平台 · 项目业务全景</title>
<style>
:root{
  --bg:#0b1220; --bg2:#101a2e; --panel:#131f36; --panel2:#182742;
  --line:#24344f; --text:#dbe4f0; --muted:#8fa1b8;
  --c-base:#8a94a6; --c-sale:#4f9cff; --c-sup:#c9a86a; --c-erp:#5fc79e;
  --c-prod:#e0b34f; --c-wm:#7e6bd6; --c-qc:#e06c6c; --c-dv:#59a8b8;
  --c-as:#c78bd6; --c-hrm:#9db85a; --c-bpm:#e6a23c; --c-ai:#56c8d8; --c-fin:#3ec9a7;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{background:var(--bg);color:var(--text);font-family:"Segoe UI","Microsoft YaHei","PingFang SC",sans-serif;font-size:14px;line-height:1.6}
header{position:fixed;top:0;left:0;right:0;height:64px;background:linear-gradient(180deg,#0e1728,#0b1220);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:24px;padding:0 24px;z-index:50}
header .logo{width:30px;height:30px;border-radius:6px;background:linear-gradient(135deg,#2c5cff,#19c2d8);display:flex;align-items:center;justify-content:center;font-weight:700;color:#fff;font-size:13px}
header h1{font-size:17px;font-weight:600;letter-spacing:.5px}
header .sub{color:var(--muted);font-size:12px}
#globalSearchWrap{margin-left:auto;position:relative;width:280px}
#globalSearch{width:100%;background:var(--bg2);border:1px solid var(--line);color:var(--text);border-radius:6px;padding:7px 12px;font-size:13px;outline:none}
#globalSearch:focus{border-color:#2c5cff}
#searchResult{position:absolute;top:38px;right:0;width:430px;max-height:60vh;overflow:auto;background:var(--panel);border:1px solid var(--line);border-radius:8px;display:none;box-shadow:0 12px 40px rgba(0,0,0,.5)}
#searchResult .sr-item{padding:10px 14px;border-bottom:1px solid var(--line);cursor:pointer}
#searchResult .sr-item:hover{background:var(--panel2)}
#searchResult .sr-type{font-size:11px;color:var(--muted)}
#searchResult .sr-meta{font-size:12px;color:var(--muted);margin-top:2px}
nav{position:fixed;top:64px;left:0;bottom:0;width:210px;background:var(--bg2);border-right:1px solid var(--line);padding:14px 0;overflow:auto;z-index:40}
nav .group{color:#5f7188;font-size:11px;padding:12px 18px 4px;letter-spacing:1px}
nav a{display:flex;align-items:center;gap:8px;padding:8px 18px;color:var(--muted);text-decoration:none;font-size:13px;border-left:3px solid transparent;cursor:pointer}
nav a:hover{color:var(--text);background:#152238}
nav a.active{color:#fff;background:#16294a;border-left-color:#2c5cff}
nav a .dot{width:8px;height:8px;border-radius:2px;flex:none}
main{margin:64px 0 0 210px;padding:26px 32px 80px;max-width:1500px}
section.page{display:none}
section.page.on{display:block}
h2.pt{font-size:20px;font-weight:600;margin-bottom:4px}
p.desc{color:var(--muted);margin-bottom:18px;max-width:980px}
.grid{display:grid;gap:14px}
.stats{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}
.stat{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px 16px}
.stat b{display:block;font-size:24px;font-weight:700;color:#fff}
.stat span{color:var(--muted);font-size:12px}
.cards{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}
.card{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acc,#2c5cff);border-radius:10px;padding:16px 18px;cursor:pointer;transition:border-color .15s,transform .15s}
.card:hover{transform:translateY(-2px);border-color:#3a5a8f}
.card h3{font-size:15px;color:#fff;margin-bottom:2px}
.card h3 .tag{font-size:10px;color:var(--acc,#2c5cff);border:1px solid currentColor;padding:1px 6px;border-radius:10px;margin-left:8px;vertical-align:2px}
.card p{color:var(--muted);font-size:12.5px;margin:6px 0}
.card .objs{font-size:12px;color:#a9b8cc}
.pill{display:inline-block;background:#1b2c4a;border:1px solid var(--line);color:#bcd0ea;border-radius:12px;padding:2px 10px;font-size:12px;margin:3px 4px 0 0;cursor:pointer}
.pill:hover{border-color:#3a5a8f;background:#22375c}
.banner{background:linear-gradient(90deg,#12213c,#0f1a2e);border:1px solid var(--line);border-radius:10px;padding:14px 18px;margin-bottom:18px}
.banner .chain{font-size:13.5px;color:#cfe0f5}
.banner .chain b{color:var(--c-prod)}
.fig{background:var(--panel);border:1px solid var(--line);border-radius:10px;margin:14px 0;overflow:hidden}
.fig .bar{display:flex;align-items:center;gap:8px;padding:8px 14px;border-bottom:1px solid var(--line);background:#101c31}
.fig .bar .name{font-size:13px;color:#cfe0f5;font-weight:600}
.fig .bar .btns{margin-left:auto;display:flex;gap:6px}
.fig .bar button{background:#1a2a46;border:1px solid var(--line);color:#9fb2ca;font-size:12px;border-radius:5px;padding:3px 10px;cursor:pointer}
.fig .bar button:hover{color:#fff;border-color:#3a5a8f}
.fig .canvas{overflow:auto;padding:16px;background:var(--panel)}
.fig .canvas .stage{transform-origin:top left;transition:transform .15s}
.fig:fullscreen{width:100vw;height:100vh;border-radius:0;background:var(--bg)}
.fig:fullscreen .canvas{height:calc(100vh - 45px)}
.mermaid-wrap svg{max-width:100%}
table.steps{width:100%;border-collapse:collapse;margin:10px 0}
table.steps th{font-size:12px;color:var(--muted);text-align:left;font-weight:600;padding:7px 10px;border-bottom:1px solid var(--line);background:#101c31}
table.steps td{padding:8px 10px;border-bottom:1px solid #1b2a44;vertical-align:top;font-size:13px}
table.steps td.stage{white-space:nowrap;color:var(--acc,#7ea6e8);font-weight:600}
table.steps td.role{white-space:nowrap;color:var(--muted);font-size:12px}
table.data{width:100%;border-collapse:collapse;background:var(--panel);border:1px solid var(--line);border-radius:10px;overflow:hidden}
table.data th{font-size:12px;color:var(--muted);text-align:left;padding:9px 12px;background:#101c31;border-bottom:1px solid var(--line)}
table.data td{padding:9px 12px;border-bottom:1px solid #1a2942;font-size:13px;vertical-align:top}
table.data tr:hover td{background:#16243c;cursor:pointer}
.detail{background:var(--panel2);border:1px solid #2c4468;border-radius:10px;padding:16px 20px;margin:12px 0}
.detail h4{color:#fff;margin-bottom:8px}
.detail .kv{margin:4px 0;font-size:13px}
.detail .kv b{color:var(--muted);font-weight:600;margin-right:8px}
.muted{color:var(--muted)} .small{font-size:12px}
#objDetail:empty{display:none}
h3.sec{font-size:15px;color:#cfe0f5;margin:26px 0 10px;padding-left:10px;border-left:3px solid #2c5cff}
footer{position:fixed;bottom:0;left:210px;right:0;background:#0d1526ee;border-top:1px solid var(--line);padding:8px 32px;color:#5f7188;font-size:12px;z-index:30}
.warn li{margin-left:18px;padding:3px 0;font-size:13px;color:#d9c4a0}
@media (max-width:1100px){nav{width:170px}main,footer{margin-left:0}}
</style>
</head>
<body>
<header>
  <div class="logo">MOM</div>
  <div>
    <h1 id="hProject">项目业务全景</h1>
    <div class="sub" id="hSub"></div>
  </div>
  <div id="globalSearchWrap">
    <input id="globalSearch" placeholder="搜索业务:销售订单 / 工单 / IQC / 库存 / 回款…" autocomplete="off">
    <div id="searchResult"></div>
  </div>
</header>
 
<nav id="nav">
  <div class="group">总览</div>
  <a data-t="overview" class="active"><span class="dot" style="background:#2c5cff"></span>项目概览</a>
  <a data-t="panorama"><span class="dot" style="background:#56c8d8"></span>业务全景图</a>
  <div class="group">核心业务流程</div>
  <a data-t="flow-sales"><span class="dot" style="background:var(--c-sale)"></span>销售流程</a>
  <a data-t="flow-purchase"><span class="dot" style="background:var(--c-erp)"></span>采购流程</a>
  <a data-t="flow-production"><span class="dot" style="background:var(--c-prod)"></span>生产流程</a>
  <a data-t="flow-quality"><span class="dot" style="background:var(--c-qc)"></span>质量流程</a>
  <a data-t="flow-warehouse"><span class="dot" style="background:var(--c-wm)"></span>仓储流程</a>
  <a data-t="flow-aftersales"><span class="dot" style="background:var(--c-as)"></span>售后流程</a>
  <div class="group">结构与数据</div>
  <a data-t="relation"><span class="dot" style="background:var(--c-bpm)"></span>系统关系</a>
  <a data-t="dataflow"><span class="dot" style="background:var(--c-fin)"></span>数据流</a>
  <a data-t="objects"><span class="dot" style="background:var(--c-base)"></span>业务对象</a>
  <a data-t="roles"><span class="dot" style="background:var(--c-hrm)"></span>角色权限</a>
  <div class="group">扩展</div>
  <a data-t="ai"><span class="dot" style="background:var(--c-ai)"></span>AI 业务</a>
  <a data-t="pending"><span class="dot" style="background:var(--c-sup)"></span>待确认事项</a>
</nav>
 
<main>
<section class="page on" id="overview"></section>
<section class="page" id="panorama">
  <h2 class="pt">业务全景图</h2>
  <p class="desc">按业务意义(而非代码包结构)归类的模块-能力思维导图。</p>
  <div class="fig" data-fig="01-business-mindmap">
    <div class="bar"><span class="name">业务全景思维导图</span><div class="btns"><button data-z="-">-</button><button data-z="+">+</button><button data-z="0">重置</button><button data-fs>全屏</button></div></div>
    <div class="canvas"><div class="stage mermaid-wrap"><pre class="mermaid" data-mmd="01-business-mindmap"></pre></div></div>
  </div>
</section>
<section class="page" id="flow-sales"></section>
<section class="page" id="flow-purchase"></section>
<section class="page" id="flow-production"></section>
<section class="page" id="flow-quality"></section>
<section class="page" id="flow-warehouse"></section>
<section class="page" id="flow-aftersales"></section>
<section class="page" id="relation">
  <h2 class="pt">系统关系</h2>
  <p class="desc">模块之间的调用与数据依赖:实线=单据/数据流向,虚线=审批回调与辅助能力。</p>
  <div class="fig" data-fig="08-module-relation">
    <div class="bar"><span class="name">模块系统关系</span><div class="btns"><button data-z="-">-</button><button data-z="+">+</button><button data-z="0">重置</button><button data-fs>全屏</button></div></div>
    <div class="canvas"><div class="stage mermaid-wrap"><pre class="mermaid" data-mmd="08-module-relation"></pre></div></div>
  </div>
</section>
<section class="page" id="dataflow">
  <h2 class="pt">数据流</h2>
  <p class="desc">跨模块单据的生成与回写关系(字段带入、数量状态回写、事件通知)。</p>
  <div class="fig" data-fig="09-data-flow">
    <div class="bar"><span class="name">跨模块数据流</span><div class="btns"><button data-z="-">-</button><button data-z="+">+</button><button data-z="0">重置</button><button data-fs>全屏</button></div></div>
    <div class="canvas"><div class="stage mermaid-wrap"><pre class="mermaid" data-mmd="09-data-flow"></pre></div></div>
  </div>
</section>
<section class="page" id="objects">
  <h2 class="pt">核心业务对象</h2>
  <p class="desc">点击对象行查看作用、上游、下游与数据表。对象关系见文末 ER 图(仅核心业务对象)。</p>
  <div class="grid" id="objGrid" style="grid-template-columns:1fr"></div>
  <div id="objDetail" class="detail"></div>
  <h3 class="sec">对象关系图(ER)</h3>
  <div class="fig" data-fig="10-business-object">
    <div class="bar"><span class="name">核心业务对象关系</span><div class="btns"><button data-z="-">-</button><button data-z="+">+</button><button data-z="0">重置</button><button data-fs>全屏</button></div></div>
    <div class="canvas"><div class="stage mermaid-wrap"><pre class="mermaid" data-mmd="10-business-object"></pre></div></div>
  </div>
</section>
<section class="page" id="roles"></section>
<section class="page" id="ai">
  <h2 class="pt">AI 业务</h2>
  <p class="desc">项目 AI 统一采用「业务侧组装 Prompt → 模型 → 结构化 JSON → 人工确认」模式,无 Function Calling;AI 不可用时各功能回退人工。</p>
  <div class="grid cards" id="aiGrid"></div>
</section>
<section class="page" id="pending">
  <h2 class="pt">待确认事项</h2>
  <p class="desc">源码走读中发现与文档/预期不一致、疑似未完成或需业务确认的点,均标注了出处行为。</p>
  <ul class="warn" id="pendingList"></ul>
</section>
</main>
<footer id="footer"></footer>
 
<script type="application/json" id="data-business">{
  "project": {
    "name": "MOM 工厂数字化平台(mom-pro2)",
    "type": "混合系统",
    "mainSystem": "MOM 制造运营管理系统",
    "subSystems": [
      "MES(生产·仓储·质量·设备)",
      "ERP(进销存·财务)",
      "CRM(客户关系)",
      "SRM(供应商关系)",
      "HRM(人力资源)",
      "BPM(Flowable 协同审批)",
      "AI(通义千问 + Milvus RAG)",
      "BI(SQL 配置式大屏)"
    ],
    "description": "基于 yudao(ruoyi-vue-pro)二次开发的制造业一体化数字工厂平台,覆盖『销售接单 → 采购/生产 → 质检 → 仓储 → 发货 → 回款 → 售后』全链路,内置审批流、主数据、附件、AI 辅助与 BI 驾驶舱。",
    "businessPositioning": "让工厂的订单、物料、生产、库存、质量、人员、资金在一个系统内闭环流转,管理层可通过 BI 大屏掌握全局。",
    "coreChain": "CRM 商机/合同 → ERP 销售订单 → MES 主生产计划/工单/报工 → MES 质检与仓储 → 销售出库发货 → 开票回款 → 售后闭环",
    "techBase": "Spring Boot + MyBatis + Flowable + Redis + Quartz/RocketMQ/Kafka + Milvus 向量库 + 通义千问",
    "database": "MySQL 8.4,413 张表(含 system_*、bpm_*、act_* 底座表与 mes_*/erp_*/crm_*/srm_*/hrm_*/mdm_*/ai_* 业务表),多租户已关闭",
    "frontend": "mom-pro2-before(Vue3 管理后台,同仓库存放,只读参考)"
  },
  "stats": {
    "businessModules": 13,
    "coreObjects": 48,
    "documentFlows": 6,
    "approvalListeners": 13,
    "aiCapabilities": 8,
    "wmBillTypes": 15
  },
  "businessAnswers": [
    [
      "项目解决什么问题",
      "离散制造工厂的产供销人财物一体化管理:从客户订单到生产交付、库存资金全链路数字化闭环"
    ],
    [
      "核心业务",
      "销售订单履约(合同→订单→生产→质检→入库→发货→回款)与采购供应(申请→订单→到货→IQC→入库→付款)"
    ],
    [
      "业务主线",
      "CRM 合同 → ERP 销售订单 → MES MPS/工单 → 报工/IPQC → 完工入库 → 发货通知 → 销售出库(OQC) → 开票 → 回款"
    ],
    [
      "销售如何影响生产",
      "销售订单审批通过后,需生产明细自动创建 MES 主生产计划(MPS),MPS 下发驱动工单与任务"
    ],
    [
      "采购如何影响库存",
      "采购订单『确认收货』生成 MES 到货通知 → IQC 合格/特采 → 采购入库单完成 → 库存台账 IN 事务+N"
    ],
    [
      "生产如何产生库存",
      "报工审批通过后自动生成产品产出单入库(质检工序先待检、IPQC 后拆行入库);倒冲工序按 BOM 扣线边库"
    ],
    [
      "质量在哪里介入",
      "四道闸口:IQC(到货/外协入库)、IPQC(报工质检工序)、OQC(销售出库前)、RQC(退料/退货),不合格走 NCR 处置"
    ],
    [
      "售后如何闭环",
      "工单判定退货 → 退货申请审核 → 自动建 MES 销售退货单 → RQC 质检/入库回调 → 退款回调 → 工单完结关闭"
    ],
    [
      "AI 在哪里参与",
      "发票/报价 OCR 预填、质检结果建议、缺料/时长/风险/交付四类预测;均为『业务组装 Prompt→模型→JSON→人工确认』模式"
    ],
    [
      "模块间数据关系",
      "MDM 主数据统一下发;CRM↔ERP 合同生单;ERP↔MES 单据互建与数量回写;BPM 事件回调解锁状态;HRM 交接扩展数据可见性"
    ]
  ],
  "aiCapabilities": [
    {
      "name": "采购发票 OCR",
      "flow": "上传 blobId → 图片走 chatWithImage 视觉模型 / PDF·文本走 chat → 解析发票号·抬头·供应商·价税合计·税率 → 预填采购来票表单",
      "callsApis": [
        "SystemStorageBlobService"
      ]
    },
    {
      "name": "报价单 OCR",
      "flow": "PDF/Word/Excel/图片 → POI/PDFBox/视觉模型 → 报价头+产品明细 JSON → 预填报价单",
      "callsApis": [
        "SystemStorageBlobService"
      ]
    },
    {
      "name": "质检结果智能判定",
      "flow": "质检单+指标结果+缺陷记录 组装 Prompt → chat → 建议{合格/特采/退货/报废+理由}",
      "callsApis": [
        "MdmItemApi",
        "SrmSupplierApi",
        "CrmCustomerApi"
      ]
    },
    {
      "name": "物料短缺预测",
      "flow": "工单 BOM 需求 vs 库存(在库-冻结-占用) vs 已投料 → chat → 风险等级+缺口清单",
      "callsApis": [
        "MdmItemApi"
      ]
    },
    {
      "name": "生产时长预测",
      "flow": "工序标准工时+设备小时产量+传送倍率 → chat → 预测总时长+工序分解",
      "callsApis": [
        "MdmItemApi"
      ]
    },
    {
      "name": "生产风险预测",
      "flow": "IPQC 缺陷率+设备保养点检+物料可用率<20%+关键工序 → chat → 综合风险+因素",
      "callsApis": [
        "MdmItemApi"
      ]
    },
    {
      "name": "交付预测",
      "flow": "进度+剩余天数+任务完成状态+客户交期 → chat → 能否按时+置信度+延误因素",
      "callsApis": [
        "MdmItemApi",
        "CrmCustomerApi"
      ]
    },
    {
      "name": "RAG 知识库",
      "flow": "文档 → POI/Tika 提文本 → 切片(800token) → 向量化入 Milvus → 检索接口(topK3,阈值0.7)【当前无业务模块消费,预留能力】",
      "callsApis": []
    }
  ],
  "pendingConfirm": [
    "仓库类型/合格仓改造:需求称仓库应有 type 字段(原料/成品/半成品/线边/合格仓),但 MesWmWarehouseDO 当前无 type 字段,仅硬编码虚拟线边库,改造似未完成【待确认】",
    "HrmUserHandoverApi.expandUserIds 接口已实现,但 CRM/ERP/MES 查询『我的数据』处均未实际调用,交接可见性功能未真正生效【与项目规则文档存在落差】",
    "回款(crm_receivable)未接 BPM,创建即审批中(10)靠手动更新;合同/开票均已接【待确认是否有意简化】",
    "MES 任务暂停 pauseTask 仅允许草稿状态停工,疑似校验逻辑反转 bug",
    "付款单 BPM 驳回回退到 PROCESS(10) 而非 REJECT(35),与其他单据不一致",
    "财务勾稽断裂:updatePurchasePrice/updateSalePrice 方法体为空,入库/出库金额不会自动回写收付款",
    "生产入库单(ProductReceipt) 与报工产出(ProductProduce) 并存,存在重复入库风险需业务确认",
    "AI 模型工厂仅实现通义千问,DeepSeek/OpenAI/Ollama 枚举预留未实现",
    "售后退货单 AUDITING(10) 状态无写入代码,疑似预留未启用",
    "BI 图表 querySql 以字符串拼接参数执行(仅单引号转义),存在 SQL 注入风险面",
    "MesWmSnDO 新增的 uuid 字段生成/消费逻辑未在核心 Service 中确认",
    "转正申请(hrm_regularize_application)、培训证书等仅有 SQL 与菜单初始化,Java 侧 Service/Controller 未实现",
    "NCR 处置结果(返工/退货)未回写触发源单据,仅台账记录",
    "MPS 状态枚举独立编号(0/1/2/3),与通用单据常量(0/1/4/5)不一致"
  ],
  "generatedAt": "2026-09-10",
  "analysisBasis": "基于 dev_business 分支 87bf4a99 源码,6 组并行源码走读(MES 生产质量 / MES 仓储 / ERP / CRM+SRM / 售后+HRM / AI+BI+MDM+BPM+底座)"
}</script>
<script type="application/json" id="data-modules">{
  "modules": [
    {"key": "mdm", "name": "基础主数据", "color": "#8a94a6", "tag": "MDM", "flow": null,
     "positioning": "全系统统一口径的主数据权威源",
     "problem": "物料、单位、仓库在 MES/ERP/CRM 多处重复定义导致数据打架",
     "features": ["物料与SKU(含批次属性配置12开关)", "物料分类树", "计量单位与换算", "品牌", "仓库主数据(含type字段)", "MES 物料经 MdmItemSyncApi 反向同步"],
     "objects": ["物料", "SKU", "计量单位", "仓库"],
     "roles": ["主数据管理员"],
     "upstream": [], "downstream": ["生产", "进销存", "销售", "采购"],
     "coreTables": ["mdm_item", "mdm_item_sku", "mdm_item_category", "mdm_unit_measure", "mdm_brand", "mdm_warehouse"]},
    {"key": "crm", "name": "销售管理(客户关系)", "color": "#4f9cff", "tag": "CRM", "flow": "sales",
     "positioning": "销售前端:从线索到回款的客户经营",
     "problem": "客户资产沉淀、商机转化、合同审批与开票回款管控",
     "features": ["线索转化客户", "公海池与领取上限", "联系人", "商机自定义阶段", "跟进记录", "报价单(AI OCR)", "合同(BPM审批→生成销售订单)", "开票(BPM)→回款(先开票校验)", "回款计划", "销售目标", "数据权限三级(负责人/只读/读写)"],
     "objects": ["线索", "客户", "联系人", "商机", "报价单", "合同", "发票", "回款", "销售目标"],
     "roles": ["销售内勤", "销售经理", "财务(开票回款)"],
     "upstream": ["主数据(物料)"], "downstream": ["进销存(销售订单)", "售后(客户)", "AI(报价OCR)"],
     "coreTables": ["crm_clue", "crm_customer", "crm_contact", "crm_business", "crm_sale_quotation", "crm_contract", "crm_invoice", "crm_receivable", "crm_receivable_plan", "crm_permission"]},
    {"key": "srm", "name": "供应商管理", "color": "#c9a86a", "tag": "SRM", "flow": "purchase",
     "positioning": "供应商全生命周期:准入-资质-寻源-绩效",
     "problem": "供应商合规准入、阳光寻源(招标/比价)与绩效量化",
     "features": ["供应商档案与分类", "准入申请(BPM 采购/质量/财务会签)", "资质证书有效期", "招标:公开/邀请/竞谈完整版+比价简易版", "投标·报价·开标·评标·定标", "定标自动生成采购订单", "四维绩效(质量/交付/价格/服务)"],
     "objects": ["供应商", "准入申请", "资质证书", "招标项目", "投标", "定标", "绩效评价"],
     "roles": ["采购开发", "供应商管理员", "评审专家"],
     "upstream": ["主数据(物料)"], "downstream": ["进销存(采购订单)"],
     "coreTables": ["srm_supplier", "srm_supplier_apply", "srm_supplier_certificate", "srm_tender_project", "srm_tender_bid", "srm_bid_award", "srm_supplier_evaluation"]},
    {"key": "erp", "name": "进销存与财务", "color": "#5fc79e", "tag": "ERP", "flow": "purchase",
     "positioning": "商贸与资金单据中枢,向 MES 发起实物收发",
     "problem": "采购销售单据审批、来票付款控制、订单执行进度回写",
     "features": ["采购申请(BPM)→订单(自动/手动生成)", "确认收货→MES到货通知", "入库/退货数量状态回写", "采购来票(金额≤订单)", "付款单(必须关联来票·BPM)", "销售订单(BPM·审批通过自动建MPS)", "出库状态回写", "收款单(关联CRM客户)", "结算账户", "AI发票OCR"],
     "objects": ["采购申请", "采购订单", "采购来票", "付款单", "销售订单", "收款单", "结算账户"],
     "roles": ["采购员", "销售员", "出纳", "会计"],
     "upstream": ["CRM(合同)", "SRM(定标)", "主数据"], "downstream": ["生产(MPS)", "仓储(收发)"],
     "coreTables": ["erp_purchase_request", "erp_purchase_order", "erp_purchase_invoice", "erp_finance_payment", "erp_sale_order", "erp_finance_receipt", "erp_account"]},
    {"key": "pro", "name": "生产管理", "color": "#e0b34f", "tag": "MES-PRO", "flow": "production",
     "positioning": "生产执行核心:计划-工单-任务-报工",
     "problem": "订单到车间执行的逐层拆解与过程可控",
     "features": ["MPS主生产计划(可由销售订单自动创建·合并下发)", "工单(按工艺路线自动生成工序任务)", "报工(按工序顺序控制·BPM审批)", "倒冲扣线边库/产出入库", "安灯", "工艺路线·工序·工单BOM", "研发设计项目(PD·审批归档)", "AI 四类预测"],
     "objects": ["MPS", "生产工单", "生产任务", "报工单", "工艺路线", "工单BOM", "设计项目"],
     "roles": ["计划员", "车间主任", "操作工", "工艺员"],
     "upstream": ["进销存(销售订单)"], "downstream": ["仓储(领料/入库)", "质量(IPQC)"],
     "coreTables": ["mes_pro_mps", "mes_pro_work_order", "mes_pro_task", "mes_pro_feedback", "mes_pro_route", "mes_pro_process", "mes_pro_work_order_bom", "mes_pd_project"]},
    {"key": "wm", "name": "仓储管理", "color": "#7e6bd6", "tag": "MES-WM", "flow": "warehouse",
     "positioning": "厂内 WMS:单据驱动的库存账实一致",
     "problem": "多来源出入库、批次/SN 追溯、库存精确到库位",
     "features": ["15种出入库单据", "库存台账(物料×仓库×库区×库位×批次×供应商)", "事务流水只读留痕", "调拨成对事务", "盘点(静态/动态·盲盘·盘盈盘亏调整)", "批次/SN/条码/装箱嵌套", "虚拟线边库(允许负库存)", "库存占用(5类)", "四级冻结", "WMS审批配置+BPM", "对外 WmsStockApi/WmsTransactionApi"],
     "objects": ["到货通知", "采购入库", "领料", "完工入库", "销售出库", "发货通知", "销售退货", "供应商退货", "调拨", "盘点", "库存台账", "批次", "SN"],
     "roles": ["仓管员", "拣货员", "盘点员"],
     "upstream": ["采购(收货)", "生产(领退料)", "销售(发货)", "售后(退货)"], "downstream": ["进销存(数量回写)", "财务(成本基础)"],
     "coreTables": ["mes_wm_warehouse", "mes_wm_material_stock", "mes_wm_transaction", "mes_wm_item_receipt", "mes_wm_product_issue", "mes_wm_product_receipt", "mes_wm_product_sales", "mes_wm_return_sales", "mes_wm_transfer", "mes_wm_stock_taking_task", "mes_wm_batch", "mes_wm_sn", "mes_wm_stock_reserve"]},
    {"key": "qc", "name": "质量管理", "color": "#e06c6c", "tag": "MES-QC", "flow": "quality",
     "positioning": "四道检验闸口 + 不合格品闭环处置",
     "problem": "来料/过程/出货/退货检验标准化,不合格可追溯处置",
     "features": ["IQC 来料(到货/外协)", "IPQC 过程(联动报工)", "OQC 出货(联动销售出库)", "RQC 退货(联动退料/售后)", "质检方案·指标·缺陷库", "检测结果:合格/特采/退货/报废", "NCR:评审→处置(退货/报废/返工/让步/降级)→关闭", "AI 判定建议"],
     "objects": ["IQC", "IPQC", "OQC", "RQC", "质检方案", "NCR", "缺陷记录"],
     "roles": ["质检员(IQC/IPQC/OQC)", "质量工程师"],
     "upstream": ["仓储(到货)", "生产(报工)", "销售(出库)", "售后(退货)"], "downstream": ["仓储(合格入库/报废出库)", "生产(NCR返工)"],
     "coreTables": ["mes_qc_iqc", "mes_qc_ipqc", "mes_qc_oqc", "mes_qc_rqc", "mes_qc_template", "mes_qc_indicator", "mes_qc_defect", "mes_qc_ncr"]},
    {"key": "qcreport", "name": "智能质检报告", "color": "#b06ce0", "tag": "QC-REPORT", "flow": "quality",
     "positioning": "可视化设计报告模板 → 一键出件并冻结历史报告",
     "problem": "各行业质检报告格式各异,排版硬编码改一次发一次版;且历史报告必须可复现、不随业务数据变化",
     "features": ["GrapesJS 可视化设计器(质检组件走注册机制,不硬编码进编辑器)", "模板 + 多版本:草稿0/已发布1/已停用2,已发布版本内容不可覆盖", "组件数据绑定与独立判定规则引擎(禁用 eval / ScriptEngine)", "与前端逐字对齐的 Java 渲染引擎,出站 HTML 剥离 on* 事件属性与 javascript:/vbscript:/data: 协议", "出件接口:preview 只渲染不落库不消耗编号 / generate 渲染+落库+冻结 data_snapshot / regenerate 用冻结快照与同一版本重渲", "报告编号 QR+yyyyMMdd+4位流水,按天独立,可显式指定(撞号会报出具体编号)", "缺口清单只在 preview/generate/regenerate 响应里返回,不落库", "PDF(Playwright) 归档与 MES 四种质检单归一化对接待后续轮次"],
     "objects": ["报告模板", "报告实例"],
     "roles": ["报告设计员", "质检员(出件)"],
     "upstream": ["质量(质检单上下文,本轮由调用方传入)"], "downstream": ["附件中心(PDF 归档·后续轮次)", "BI"],
     "coreTables": ["qc_report_template", "qc_report_template_version", "qc_report_instance", "qc_report_data_source", "qc_report_rule", "qc_report_render_record"]},
    {"key": "dv", "name": "设备与工装排班", "color": "#59a8b8", "tag": "MES-DV/TM/CAL", "flow": null,
     "positioning": "设备资产健康与生产资源保障",
     "problem": "设备点检保养维修可执行、工装状态可控、班组排班有依据",
     "features": ["设备台账(停机/生产中/保养中)", "点检·保养方案与记录", "维修工单(草稿→维修→待验收→已确认)", "计量器具检定", "工装夹具(在库/领用/维修/报废)", "班组·班次·排班计划·节假日"],
     "objects": ["设备", "点检记录", "维修工单", "工装", "排班计划"],
     "roles": ["设备员", "维修工", "工装管理员", "排班员"],
     "upstream": [], "downstream": ["生产(AI 风险预测消费设备数据)", "薪酬(排班工时)"],
     "coreTables": ["mes_dv_machinery", "mes_dv_check_plan", "mes_dv_check_record", "mes_dv_repair", "mes_tm_tool", "mes_cal_plan", "mes_cal_team", "mes_cal_shift"]},
    {"key": "aftersales", "name": "售后服务", "color": "#c78bd6", "tag": "AFTER", "flow": "aftersales",
     "positioning": "客户反馈到退货/维修/退款闭环",
     "problem": "售后工单流转、退货与质检入库退款的跨系统联动",
     "features": ["工单六态(草稿→处理中→待入库→待退款→完结→关闭)", "问题判定(一般/维修/退货)", "维修(现场/返厂/远程)", "退货申请→自动建 MES 销售退货单", "质检结论/入库/退款三重回调", "行级数据权限四视图"],
     "objects": ["售后工单", "维修记录", "退货申请"],
     "roles": ["客服", "维修工程师", "售后管理员"],
     "upstream": ["CRM(客户)", "ERP(销售订单)"], "downstream": ["仓储(销售退货)", "质量(RQC)", "财务(退款)"],
     "coreTables": ["after_sale_ticket", "after_sale_ticket_item", "after_sale_repair", "after_sale_return", "after_sale_permission"]},
    {"key": "hrm", "name": "人力资源", "color": "#9db85a", "tag": "HRM", "flow": null,
     "positioning": "员工入转调离与考勤薪酬",
     "problem": "人事流程审批化、离职数据不丢(交接)、算薪自动化",
     "features": ["员工档案(入职自动建系统账号)", "请假/加班/调岗/离职 BPM 审批", "离职交接映射 expandUserIds", "考勤(打卡·规则·排班·补卡审批·月度汇总)", "薪酬(应发-社保公积金-个税-请假扣款·1.5/2/3倍加班费·发放台账)", "培训证书(SQL先行待实现)"],
     "objects": ["员工", "请假单", "离职申请", "交接映射", "考勤记录", "薪酬核算"],
     "roles": ["HR", "部门主管", "员工本人"],
     "upstream": [], "downstream": ["各模块(数据可见性扩展)", "system(账号)"],
     "coreTables": ["hrm_employee", "hrm_leave_application", "hrm_resignation_application", "hrm_user_handover", "hrm_attendance_record", "hrm_salary_calculation", "hrm_salary_payment"]},
    {"key": "bpm", "name": "协同审批", "color": "#e6a23c", "tag": "BPM", "flow": null,
     "positioning": "全系统单据审批中枢(Flowable)",
     "problem": "多模块单据需要灵活可配的多级审批",
     "features": ["BPMN+钉钉风格双设计器", "流程定义部署", "审批事件统一回调(BpmProcessInstanceStatusEvent)", "13个业务监听器", "表单·用户组·抄送·加签"],
     "objects": ["流程模型", "流程实例", "审批任务"],
     "roles": ["审批人(按流程配置)", "流程管理员"],
     "upstream": ["各业务提交审批"], "downstream": ["回调更新各业务单据状态"],
     "coreTables": ["bpm_process_definition_info", "bpm_process_instance", "bpm_task", "act_*", "flowable_*"]},
    {"key": "ai", "name": "AI 智能", "color": "#56c8d8", "tag": "AI", "flow": "ai",
     "positioning": "单据录入提效与生产决策辅助",
     "problem": "人工录发票/报价慢、质检与排产依赖经验",
     "features": ["chat/chatWithImage 双通道", "OCR 预填(发票/报价)", "质检判定建议", "缺料/时长/风险/交付四类预测", "RAG 知识库(Milvus)", "AI不可用时 fallback 人工"],
     "objects": ["知识库", "AI模型配置", "对话记录"],
     "roles": ["采购员", "销售", "质检员", "计划员"],
     "upstream": ["各业务提供上下文数据"], "downstream": ["结构化JSON建议返回业务侧"],
     "coreTables": ["ai_chat_conversation", "ai_chat_message", "ai_model", "ai_knowledge", "ai_knowledge_document", "ai_knowledge_segment"]}
  ],
  "platform": {
    "name": "系统底座",
    "capabilities": ["JWT+OAuth2 认证·滑块验证码", "RBAC 角色-菜单-数据范围(全部/部门/本部门及下级/仅本人/自定义)", "字典", "附件中心(storage-blob 文件 + storage-attachment 按 recordType+recordId 多态关联,全模块强制使用)", "编码规则(各业务自实现 Redis 前缀+日期+流水)", "Quartz 定时任务·RocketMQ/Kafka/Redis Stream MQ·WebSocket", "多租户已关闭", "实际 system_role 仅 4 个:超级管理员/普通角色/CRM管理员/租户管理员,业务分工靠数据权限而非多角色"],
    "unused": ["im 模块(IM/RTC,业务未消费)", "member 模块(C端会员,遗留)"]
  }
}</script>
<script type="application/json" id="data-objects">{
  "objects": [
    {"name": "物料", "module": "基础主数据", "table": "mdm_item", "doc": "MDM 权威物料/产品/半成品档案,含 SKU、批次属性、价格、安全库存", "upstream": ["MES 物料反向同步"], "downstream": ["报价单", "销售订单", "采购订单", "工单BOM", "库存台账"], "keywords": "物料 产品 原材料 item"},
    {"name": "仓库", "module": "基础主数据", "table": "mdm_warehouse", "doc": "仓库主数据,type: 1原料/2成品/3半成品/4线边;MES 自有 mes_wm_warehouse 承载库区库位", "upstream": [], "downstream": ["库存台账", "出入库单据"], "keywords": "仓库 warehouse 原料仓 成品仓 线边仓"},
    {"name": "客户", "module": "销售管理", "table": "crm_customer", "doc": "客户主档,公海池/锁定/成交状态,负责人数据权限", "upstream": ["线索"], "downstream": ["联系人", "商机", "报价单", "合同", "售后工单", "收款单"], "keywords": "客户 customer 公海"},
    {"name": "线索", "module": "销售管理", "table": "crm_clue", "doc": "原始销售线索,仅一次转化为客户", "upstream": [], "downstream": ["客户"], "keywords": "线索 clue"},
    {"name": "联系人", "module": "销售管理", "table": "crm_contact", "doc": "客户下联系人,与商机多对多", "upstream": ["客户"], "downstream": ["商机"], "keywords": "联系人 contact"},
    {"name": "商机", "module": "销售管理", "table": "crm_business", "doc": "销售机会,DB 配置式阶段推进,结束态: 赢/输/无效", "upstream": ["客户"], "downstream": ["报价单", "合同"], "keywords": "商机 business 赢单 输单 阶段"},
    {"name": "报价单", "module": "销售管理", "table": "crm_sale_quotation", "doc": "QT编号,选 MDM 物料报价,AI OCR 录入,草稿→已转合同", "upstream": ["商机"], "downstream": ["合同"], "keywords": "报价 quotation QT"},
    {"name": "合同", "module": "销售管理", "table": "crm_contract", "doc": "HT编号,BPM 审批(0草稿/10审批中/20通过/30驳回/40取消/50作废),通过后可生成销售订单", "upstream": ["报价单"], "downstream": ["销售订单", "回款计划", "开票"], "keywords": "合同 contract 审批"},
    {"name": "发票", "module": "销售管理", "table": "crm_invoice", "doc": "KP编号,BPM 审批,累计开票≤合同额,附件必传", "upstream": ["合同"], "downstream": ["回款"], "keywords": "开票 发票 invoice"},
    {"name": "回款", "module": "销售管理", "table": "crm_receivable", "doc": "HK编号,创建即审批中(手动审核),强制先开票,金额双校验", "upstream": ["合同", "发票"], "downstream": ["收款单(关联)"], "keywords": "回款 收款计划 receivable"},
    {"name": "销售目标", "module": "销售管理", "table": "crm_sales_target", "doc": "年/季/月×个人/部门/产品维度的合同回款等目标", "upstream": [], "downstream": ["业绩统计"], "keywords": "目标 target 业绩"},
    {"name": "供应商", "module": "供应商管理", "table": "srm_supplier", "doc": "供应商档案:执照/税号/银行/联系人,ERP 与 MES 共用", "upstream": ["准入申请"], "downstream": ["采购订单", "到货通知", "供应商退货", "绩效评价"], "keywords": "供应商 supplier vendor"},
    {"name": "准入申请", "module": "供应商管理", "table": "srm_supplier_apply", "doc": "AP编号,BPM 审批(采购/质量/财务),通过自动建供应商档案", "upstream": [], "downstream": ["供应商"], "keywords": "准入 供应商申请 apply"},
    {"name": "招标项目", "module": "供应商管理", "table": "srm_tender_project", "doc": "完整版(发布→投标→开标→评标→定标)与简易比价两种模式", "upstream": [], "downstream": ["定标→采购订单"], "keywords": "招标 投标 比价 定标 tender 寻源"},
    {"name": "采购申请", "module": "进销存", "table": "erp_purchase_request", "doc": "CGSQ编号,BPM 审批,通过后有供应商自动生成订单", "upstream": ["生产缺口(人工)"], "downstream": ["采购订单"], "keywords": "采购申请 请购 request"},
    {"name": "采购订单", "module": "进销存", "table": "erp_purchase_order", "doc": "CGDD编号,BPM 审批(15审批中/20已审核),入库状态:未0部分1全部2", "upstream": ["采购申请", "定标"], "downstream": ["到货通知", "采购来票", "供应商退货(约束物料)"], "keywords": "采购订单 purchase"},
    {"name": "采购来票", "module": "进销存", "table": "erp_purchase_invoice", "doc": "FPD编号,AI OCR 预填,累计≤订单总价,付款单的前置", "upstream": ["采购订单"], "downstream": ["付款单"], "keywords": "来票 发票 采购发票"},
    {"name": "付款单", "module": "财务", "table": "erp_finance_payment", "doc": "FKD编号,必须关联来票+附件,累计≤来票金额,BPM 审批", "upstream": ["采购来票"], "downstream": ["结算账户"], "keywords": "付款 应付 payment"},
    {"name": "收款单", "module": "财务", "table": "erp_finance_receipt", "doc": "SKD编号,关联 CRM 客户校验,无 BPM(手动审核)", "upstream": ["销售(弱关联)"], "downstream": ["结算账户"], "keywords": "收款 应收 receipt"},
    {"name": "销售订单", "module": "进销存", "table": "erp_sale_order", "doc": "XSDD编号,BPM 审批,需生产行自动建 MPS,出库状态:未0已预留1部分2全部3,生产完成事件回写", "upstream": ["合同"], "downstream": ["MPS", "发货通知", "销售出库", "售后工单"], "keywords": "销售订单 sale"},
    {"name": "主生产计划", "module": "生产", "table": "mes_pro_mps", "doc": "MPS计划,草稿0→已下发1→完成2/取消3,可合并下发", "upstream": ["销售订单"], "downstream": ["生产工单"], "keywords": "MPS 主计划 生产计划"},
    {"name": "生产工单", "module": "生产", "table": "mes_pro_work_order", "doc": "草稿0→已确认1→完成2/取消3,确认时按工艺路线生成任务,最后一道工序报工回写已生产数量", "upstream": ["MPS"], "downstream": ["生产任务", "领料", "完工入库"], "keywords": "工单 生产工单 work order"},
    {"name": "生产任务", "module": "生产", "table": "mes_pro_task", "doc": "工序粒度,预备0→生产中1→部分2→完成4,可暂停9取消5", "upstream": ["生产工单"], "downstream": ["报工"], "keywords": "任务 task 工序"},
    {"name": "报工单", "module": "生产", "table": "mes_pro_feedback", "doc": "草稿0→审批中2→待检3/完成4,按工序顺序校验(上道工序报满才可报),联动倒冲消耗/产出入库/IPQC", "upstream": ["生产任务"], "downstream": ["产品产出", "物料消耗", "IPQC"], "keywords": "报工 feedback"},
    {"name": "工艺路线", "module": "生产", "table": "mes_pro_route", "doc": "工序顺序+质检/关键/倒冲标记,驱动工单任务与报工规则", "upstream": [], "downstream": ["生产工单"], "keywords": "工艺 路线 route 工序"},
    {"name": "到货通知单", "module": "仓储", "table": "mes_wm_arrival_notice", "doc": "采购订单确认收货生成,草稿0→待质检2→待入库3→完成4", "upstream": ["采购订单"], "downstream": ["IQC", "采购入库"], "keywords": "到货 收货 arrival"},
    {"name": "采购入库单", "module": "仓储", "table": "mes_wm_item_receipt", "doc": "草稿0→待上架2→待执行3→完成4,完成后库存+并回写 ERP inCount/inStatus", "upstream": ["到货通知"], "downstream": ["库存台账", "采购订单(回写)"], "keywords": "采购入库 收货入库 receipt"},
    {"name": "生产领料单", "module": "仓储", "table": "mes_wm_product_issue", "doc": "草稿0→待拣货2→待执行3→完成4,库存-", "upstream": ["生产工单"], "downstream": ["库存台账"], "keywords": "领料 issue"},
    {"name": "销售出库单", "module": "仓储", "table": "mes_wm_product_sales", "doc": "发货通知审核后生成,提交→OQC检测→拣货→发运10→待执行3→完成4,回写销售订单出库数与状态", "upstream": ["发货通知", "销售订单"], "downstream": ["库存台账", "OQC"], "keywords": "销售出库 发货 出库单 sales"},
    {"name": "销售退货单", "module": "仓储", "table": "mes_wm_return_sales", "doc": "草稿→待检验(RQC)→待上架→待入库→完成,售后与手工两来源", "upstream": ["售后退货申请"], "downstream": ["库存台账", "RQC"], "keywords": "销售退货 退货入库"},
    {"name": "供应商退货单", "module": "仓储", "table": "mes_wm_return_vendor", "doc": "IQC 不合格退货发起,待拣货→待执行→完成,库存-", "upstream": ["IQC"], "downstream": ["库存台账", "采购订单(returnCount)"], "keywords": "供应商退货 退料 退货 vendor"},
    {"name": "调拨单", "module": "仓储", "table": "mes_wm_transfer", "doc": "内部/外部调拨,成对 MOVE_OUT+MOVE_IN 事务,在途数量", "upstream": [], "downstream": ["库存台账"], "keywords": "调拨 移库 transfer"},
    {"name": "盘点任务", "module": "仓储", "table": "mes_wm_stock_taking_task", "doc": "静态/动态盘点,行结果:正常/盘盈(ADJUST_IN)/盘亏(ADJUST_OUT),可冻结库存、盲盘", "upstream": ["库存台账"], "downstream": ["库存台账(调整)"], "keywords": "盘点 盘盈 盘亏 stock taking"},
    {"name": "库存台账", "module": "仓储", "table": "mes_wm_material_stock", "doc": "物料×仓库×库区×库位×批次×供应商六元组,数量/冻结/占用/在途四量", "upstream": ["全部入库单"], "downstream": ["全部出库单", "事务流水"], "keywords": "库存 台账 stock 可用量"},
    {"name": "批次", "module": "仓储", "table": "mes_wm_batch", "doc": "关联物料/工单/供应商/客户/质量状态;SN 码含批次 uuid;条码支持18种业务对象", "upstream": ["入库单据"], "downstream": ["库存台账"], "keywords": "批次 batch SN 条码 追溯"},
    {"name": "IQC来料检验", "module": "质量", "table": "mes_qc_iqc", "doc": "到货通知/外协入库触发,草稿0→完成4,结论回写来源单据;行操作「出报告」仅在已完成时可见", "upstream": ["到货通知", "外协入库"], "downstream": ["采购入库", "供应商退货", "NCR", "报告实例(出报告)"], "keywords": "IQC 来料检验 出报告"},
    {"name": "IPQC过程检验", "module": "质量", "table": "mes_qc_ipqc", "doc": "报工质检工序产出行触发,完成回调推进报工与产出入库;行操作「出报告」仅在已完成时可见", "upstream": ["报工"], "downstream": ["产出入库", "NCR", "报告实例(出报告)"], "keywords": "IPQC 过程检验 巡检 出报告"},
    {"name": "OQC出货检验", "module": "质量", "table": "mes_qc_oqc", "doc": "销售出库提交触发,完成推进出库单待拣货;行操作「出报告」仅在已完成时可见", "upstream": ["销售出库单"], "downstream": ["销售出库单(推进)", "报告实例(出报告)"], "keywords": "OQC 出货检验 出厂检验 出报告"},
    {"name": "RQC退货检验", "module": "质量", "table": "mes_qc_rqc", "doc": "生产退料/销售退货/售后退货触发,结论回调售后;行操作「出报告」仅在已完成时可见。措辞已统一为「退货检验」(原菜单父项与 mes_qc_type 字典写「退料检验」,与后端枚举/表注释/菜单权限子项不一致;RQC 三者都覆盖,故取「退货检验」)", "upstream": ["退料", "退货"], "downstream": ["退货入库", "售后回调", "报告实例(出报告)"], "keywords": "RQC 退货检验 退料检验 出报告"},
    {"name": "NCR不合格品", "module": "质量", "table": "mes_qc_ncr", "doc": "待评审0→已评审6→已处置7→已关闭8,处置:退货/报废/返工/让步接收/降级", "upstream": ["IQC/IPQC/OQC/RQC"], "downstream": ["退货/报废/返工(台账)"], "keywords": "NCR 不合格 处置 特采 报废"},
    {"name": "设备", "module": "设备", "table": "mes_dv_machinery", "doc": "台账状态:停机/生产中/保养中;点检·保养·维修工单;AI 风险预测消费其数据", "upstream": [], "downstream": ["点检", "维修", "生产风险预测"], "keywords": "设备 点检 保养 维修 machinery"},
    {"name": "售后工单", "module": "售后", "table": "after_sale_ticket", "doc": "草稿0→处理中10→待入库30→待退款40→完结50→关闭60/取消99,判定:一般/维修/退货", "upstream": ["客户反馈(人工录入)"], "downstream": ["维修记录", "退货申请"], "keywords": "售后 工单 ticket 维修"},
    {"name": "退货申请", "module": "售后", "table": "after_sale_return", "doc": "草稿0→已审核20(自动建MES退货单)→已质检40→已入库50→已退款60→关闭70;类型:退款退货/换货/仅退款", "upstream": ["售后工单"], "downstream": ["销售退货单", "退款"], "keywords": "售后退货 return"},
    {"name": "员工", "module": "人力", "table": "hrm_employee", "doc": "在职1/试用2/离职3,入职自动建系统账号", "upstream": [], "downstream": ["交接映射", "考勤", "薪酬"], "keywords": "员工 入职 employee"},
    {"name": "离职交接", "module": "人力", "table": "hrm_user_handover", "doc": "from→to 映射,已完成20 后 expandUserIds 扩展交接人可见数据(当前各业务模块尚未实际接入调用)", "upstream": ["离职申请"], "downstream": ["各模块我的数据查询"], "keywords": "交接 离职 handover expandUserIds"},
    {"name": "排班计划", "module": "设备", "table": "mes_cal_plan", "doc": "班组×班次×日期排班,供生产与考勤引用", "upstream": [], "downstream": ["生产任务", "考勤"], "keywords": "排班 班组 班次 日历"},
    {"name": "报告模板", "module": "质检报告", "table": "qc_report_template", "doc": "智能质检报告模板,启用0/停用1;画布内容存在 qc_report_template_version(草稿0/已发布1/已停用2,已发布不可覆盖),currentVersion 指向当前已发布版本;源文件经 AI 导入识别成草稿后由人工确认才成为版本;同一模板重复导入按【替换】处理——先删旧附件(连带 blob 行与磁盘文件)再绑新的,不留孤儿文件;删除模板会连带清附件", "upstream": ["人工设计(GrapesJS 设计器)", "AI 导入草稿(qc-report/ai-import/draft)"], "downstream": ["模板版本", "报告实例"], "keywords": "报告模板 质检报告 template 设计器 版本 AI导入 识别 草稿 源文件替换"},
    {"name": "报告实例", "module": "质检报告", "table": "qc_report_instance", "doc": "出件产物,编号 QR+yyyyMMdd+4位流水按天独立且业务唯一,可显式指定覆盖(注意 uk_report_no 不区分软删除,删掉的号不回收);两条出件入口:通用 generate(调用方自带 context)与 generate-from-qc(数据从 MES 质检单取,权限码 qc-report:instance:generate 已入 system_menu id=1075416,五道校验按业务优先级只报第一处:105_000 类型非法 / 105_001 单据不存在 / 105_002 未完成 / 105_003 未判定 / 105_005 模板类型不符 / 105_006 无可用检验项;四张质检单列表的行操作「出报告」仅在 status=已完成时可见,弹窗只列 reportType 一致、模板启用、且 currentVersion 指向的版本已发布的模板(后端 /qc-report/template/selectable 判定——停用版本不清空 currentVersion,前端拿分页结果自己推导会漏),结果就地展示并跳本页列表);冻结 data_snapshot(判定后数据,含后端算好的 PASS/FAIL 与合格率)与 render_html;regenerate 只重渲排版、数据与编号不变;business_id/business_type 存 MES 表名(mes_qc_iqc 等)与单据 ID,可反查、一单可出多份;报告头另带单据原判定 qcResult(数)/qcResultText(中文,合格/特采/不合格退货/不合格报废),与引擎三态判定并存互不覆盖;响应带 undecidableCount=快照中 result 为空串的项数与 warnings(分组标题跳过/指标已删/未录实测值/样品超3),两者都不落库、事后看不到", "upstream": ["报告模板版本", "质检单上下文(通用 generate 由调用方传入)", "MES 质检单 IQC/IPQC/OQC/RQC(generate-from-qc 经 MesQcReportApi 取数)"], "downstream": ["前端实例页 /qc/report-instance(列表·iframe预览·快照页签·导出PDF)", "PDF归档(system_storage_attachment recordType=qc_report_instance)"], "keywords": "报告实例 出件 QR编号 快照 复现 regenerate PDF归档 报告实例页 导出PDF generate-from-qc 质检单出报告 出报告弹窗 qcResult undecidableCount warnings 待判定 反查 业务单据筛选"}
  ]
}</script>
<script type="application/json" id="data-flows">{
  "flows": [
    {"id": "sales", "name": "销售流程", "mermaid": "mermaid/02-sales-flow.mmd", "color": "#4f9cff",
     "summary": "线索转化客户 → 商机推进 → 报价(可AI识别) → 合同 BPM 审批 → 生成 ERP 销售订单并审批 → 需生产行自动建 MPS → 发货通知 → 销售出库(OQC)回写 → 开票(BPM) → 回款(先开票校验)。",
     "steps": [
       {"stage": "获客", "action": "线索转化客户、建联系人、立项商机", "roles": ["销售内勤"]},
       {"stage": "报价", "action": "商机赢单后建报价单(AI OCR 预填),转合同", "roles": ["销售内勤"]},
       {"stage": "签约", "action": "合同提交 BPM 审批(可选流程定义),通过=20", "roles": ["销售", "审批人"]},
       {"stage": "接单", "action": "合同一键生成销售订单(XSDD),销售订单再走 BPM;审批通过自动为 needProduction 明细创建 MPS", "roles": ["销售", "计划员"]},
       {"stage": "交付", "action": "发货通知审核(占用)→ 销售出库 OQC → 发运 → 出库回写部分/全部出库", "roles": ["仓管", "质检"]},
       {"stage": "回款", "action": "开票 BPM(累计≤合同额) → 回款强制先开票(累计≤合同剩余与开票剩余)", "roles": ["财务", "销售"]}]},
    {"id": "purchase", "name": "采购流程", "mermaid": "mermaid/03-purchase-flow.mmd", "color": "#5fc79e",
     "summary": "SRM 准入/定标供源 → 采购申请 BPM → 采购订单 BPM → 确认收货生成 MES 到货通知 → IQC(合格/特采入库·退货/报废) → 采购入库回写订单与申请 → 来票(AI OCR) → 付款单 BPM。",
     "steps": [
       {"stage": "寻源", "action": "供应商准入(BPM)建档;招标完整版或简易比价,定标审批通过自动生成采购订单", "roles": ["采购开发"]},
       {"stage": "申请", "action": "采购申请(CGSQ)提交 BPM,驳回可重置回草稿;通过且有供应商自动生成订单", "roles": ["采购员", "审批人"]},
       {"stage": "下单", "action": "采购订单(CGDD)自动提交 BPM(15→20)", "roles": ["采购员"]},
       {"stage": "收货", "action": "确认收货生成到货通知(0→待质检2/待入库3→4);需检物料自动创建 IQC", "roles": ["仓管", "IQC 质检员"]},
       {"stage": "入库", "action": "IQC 合格/特采→采购入库(待上架→待执行→完成)库存+,回写订单 inCount/inStatus 与申请明细", "roles": ["仓管"]},
       {"stage": "退货", "action": "IQC 不合格退货→供应商退货出库(选料锁定到订单行);报废走 NCR", "roles": ["仓管"]},
       {"stage": "付款", "action": "采购来票(FPD, AI OCR, ≤订单总价) → 付款单(FKD 关联来票+附件, ≤来票金额) BPM 审批", "roles": ["财务", "审批人"]}]},
    {"id": "production", "name": "生产流程", "mermaid": "mermaid/04-production-flow.mmd", "color": "#e0b34f",
     "summary": "销售订单驱动 MPS → 下发工单 → 按工艺路线拆工序任务 → 领料/线边备料 → 报工(工序顺序硬校验+BPM) → 倒冲消耗/产出入库/IPQC → 末道工序回写进度 → 自动完工 → ProductionFinishedEvent 回写销售订单。",
     "steps": [
       {"stage": "计划", "action": "MPS 创建(手工或销售订单自动)→下发或合并下发为工单", "roles": ["计划员"]},
       {"stage": "派工", "action": "工单确认按工艺路线逐工序生成任务,可指派/暂停/取消", "roles": ["车间主任"]},
       {"stage": "备料", "action": "生产领料单出库或线边虚拟库备料", "roles": ["仓管"]},
       {"stage": "报工", "action": "提交报工:上一道工序未报满直接拦截;启用 BPM 走审批", "roles": ["操作工"]},
       {"stage": "联动", "action": "审批通过按工序标记: 倒冲→自动物料消耗扣线边库(允许负库存);质检→产出待检行等 IPQC;关键非检→直接产出入库", "roles": ["系统自动"]},
       {"stage": "完工", "action": "仅末道工序回写工单已生产数量,达标自动完成;MPS 累计判断完成并发事件给销售订单", "roles": ["系统自动"]}]},
    {"id": "quality", "name": "质量流程", "mermaid": "mermaid/05-quality-flow.mmd", "color": "#e06c6c",
     "summary": "四道检验闸口(IQC/IPQC/OQC/RQC,二态 0→4) + 判定四果(合格/特采/退货/报废) + NCR 评审处置关闭;AI 提供判定建议;NCR 当前仅台账不触发返工单;检验单可由智能质检报告平台一键出件(generate-from-qc:数据从 MES 取,五道校验后渲染落库)。",
     "steps": [
       {"stage": "来料", "action": "到货通知/外协入库→IQC,结论回写推进待入库或触发退货", "roles": ["IQC 质检员"]},
       {"stage": "过程", "action": "报工质检工序产出行→IPQC,合格拆行入库、不合格生成 NCR", "roles": ["IPQC 质检员"]},
       {"stage": "出货", "action": "销售出库提交→OQC,完成后出库单进入待拣货", "roles": ["OQC 质检员"]},
       {"stage": "退货", "action": "退料/销售退货/售后退货→RQC,结论回调单据与售后", "roles": ["RQC 质检员"]},
       {"stage": "不合格", "action": "NCR: 待评审→评审→处置(退货/报废/返工/让步接收/降级)→关闭", "roles": ["质量工程师"]},
       {"stage": "出件", "action": "两条出件入口:①通用 generate/preview(调用方自带上下文) 渲染 HTML 并冻结数据快照,编号 QR+日期+4位流水按天独立,preview 只渲染不落库不消耗编号,regenerate 用冻结快照重渲且数据与编号不变并作废已归档 PDF,导出 PDF 由后端调 Chromium 打印实例已存的 HTML 后归档附件中心;②generate-from-qc 由质检单直接出件(数据经 MesQcReportApi 从 MES 取,前端不拼上下文),出件前五道校验按业务优先级只报第一处:类型非法/单据不存在/未完成检验/未填判定/模板类型不符/无可用检验项,报告头另带单据原判定 qcResult+qcResultText 与引擎判定并存,响应回 undecidableCount 待判定项数与 warnings(分组标题跳过/指标已删/未录实测值/样品超3),同一张单据可反复出多份", "roles": ["质检员"]},
       {"stage": "建模板", "action": "AI 导入:上传既有检验报告文件(扫描件/照片、电子版 PDF、Word/Excel) → 识别成模板草稿(不落库) → 人工在设计器确认调整后保存为版本;.doc/.xls 旧格式不支持", "roles": ["质检员", "质量工程师"]}]},
    {"id": "warehouse", "name": "仓储流程", "mermaid": "mermaid/06-warehouse-flow.mmd", "color": "#7e6bd6",
     "summary": "15 类单据驱动库存台账(六元组、四量)变动,全部经事务流水留痕;支持调拨在途、盘点调整、批次/SN 追溯、库存占用与四级冻结、线边虚拟库负库存;对外 WmsStockApi 供 ERP 收发。",
     "steps": [
       {"stage": "入库", "action": "采购入库/生产入库/产出入库/退货入库/外协入库/杂项入库 → IN 事务,批次混放校验、四级冻结校验", "roles": ["仓管"]},
       {"stage": "出库", "action": "销售出库/领料/消耗/外协发料/供应商退货/杂项出库 → OUT 事务,checkFlag 控制可否负库存", "roles": ["仓管", "系统自动"]},
       {"stage": "移库", "action": "内部/外部调拨成对 MOVE 事务,在途数量跟踪", "roles": ["仓管"]},
       {"stage": "盘点", "action": "方案→任务→明细行→结果,盘盈 ADJUST_IN、盘亏 ADJUST_OUT,可冻结与盲盘", "roles": ["盘点员"]},
       {"stage": "追溯", "action": "批次/SN(uuid)/条码(18类)/装箱嵌套支撑正反向追溯", "roles": ["质量", "售后"]}]},
    {"id": "aftersales", "name": "售后流程", "mermaid": "mermaid/07-after-sales-flow.mmd", "color": "#c78bd6",
     "summary": "工单(六态+问题判定) → 维修三类型或退货申请 → 审核自动建 MES 销售退货单 → RQC 质检/入库/退款三回调逐级推进 → 工单完结关闭。",
     "steps": [
       {"stage": "受理", "action": "人工录入工单(关联客户/订单/合同),分配处理人进入处理中", "roles": ["客服"]},
       {"stage": "判定", "action": "问题判定: 一般/维修/退货,严重度 0-3", "roles": ["售后工程师"]},
       {"stage": "维修", "action": "现场/返厂/远程维修,费用与结果记录,完成联动工单完结", "roles": ["维修工程师"]},
       {"stage": "退货", "action": "退货申请审核→自动建 MES 销售退货单(RQC)→质检/入库回调→退款回调→关闭", "roles": ["售后", "质检", "财务"]}]},
    {"id": "ai", "name": "AI 业务流程", "mermaid": "mermaid/11-ai-business-flow.mmd", "color": "#56c8d8",
     "summary": "统一模式:业务侧收集上下文(必要时调 MDM/SRM/CRM API 取名称)→组装 Prompt→chat/chatWithImage→解析 JSON→前端预填或建议;无 Function Calling;RAG 知识库已建成但暂无业务消费。",
     "steps": [
       {"stage": "录入提效", "action": "发票 OCR(图片多模态/PDF文本)、报价单 OCR → 结构化预填", "roles": ["采购员", "销售"]},
       {"stage": "辅助判定", "action": "质检单+指标+缺陷 → 建议合格/特采/退货/报废+理由", "roles": ["质检员"]},
       {"stage": "决策预测", "action": "缺料/生产时长/生产风险/交付四类预测供计划排产参考", "roles": ["计划员"]},
       {"stage": "模板识别", "action": "上传既有检验报告文件(扫描件/照片、电子版 PDF、Word/Excel) → 分通道抽取(有文本层走文本、扫描版逐页转图) → 大模型按前端上传的组件清单产出扁平组件草稿 → 人工在设计器确认后保存为模板版本", "roles": ["质检员", "质量工程师"]},
       {"stage": "知识检索", "action": "文档→切片→Milvus 向量→检索接口(预留)", "roles": ["—"]}]}
  ]
}</script>
<script type="application/json" id="data-roles">{
  "note": "实际 system_role 仅 4 个有效角色(超级管理员/普通角色/CRM管理员/租户管理员)+1 测试角色;业务分工主要通过『菜单权限 + 数据权限(负责人制)』实现,而非细分角色。以下业务角色由各模块功能与数据权限模型推导。",
  "systemRoles": [
    {"name": "超级管理员", "code": "super_admin", "desc": "代码直返全部菜单"},
    {"name": "普通角色", "code": "common", "desc": "依赖 system_role_menu 配权"},
    {"name": "CRM 管理员", "code": "crm_admin", "desc": "CRM 查看全部数据"},
    {"name": "租户管理员", "code": "tenant_admin", "desc": "多租户已关闭,遗留"}
  ],
  "businessRoles": [
    {"role": "销售内勤/销售", "modules": ["CRM", "ERP"], "operations": ["线索客户商机维护", "报价与合同", "销售订单", "跟进记录"], "data": ["crm_*", "erp_sale_order"], "scope": "负责人(owner)+数据权限三级:只读/读写/负责人;公海池可领取;交接人应可通过 expandUserIds 看到离职人数据(接口已备、待接入)"},
    {"role": "销售经理", "modules": ["CRM"], "operations": ["商机/合同审批参与", "销售目标制定", "业绩排名漏斗分析"], "data": ["团队数据(下属用户)"], "scope": "AdminUserApi 下级用户扩展"},
    {"role": "采购员", "modules": ["ERP", "SRM"], "operations": ["采购申请/订单", "确认收货", "来票与付款发起"], "data": ["erp_purchase_*", "srm_*"], "scope": "requestUserId/supplierOwner 归属"},
    {"role": "采购开发/供应商管理员", "modules": ["SRM"], "operations": ["准入审批流转", "招标比价组织", "绩效评价"], "data": ["srm_supplier_apply", "srm_tender_*"], "scope": "BPM 多部门会签(采购/质量/财务)"},
    {"role": "计划员", "modules": ["MES"], "operations": ["MPS 与工单", "工艺路线维护", "AI 预测参考"], "data": ["mes_pro_*"], "scope": "车间/部门数据范围"},
    {"role": "操作工/班组长", "modules": ["MES"], "operations": ["任务接收", "报工提交(受工序顺序约束)", "安灯"], "data": ["mes_pro_feedback", "mes_pro_task"], "scope": "任务指派人可见"},
    {"role": "仓管员", "modules": ["MES-WM"], "operations": ["15 类出入库单据执行", "调拨", "盘点", "条码装箱"], "data": ["mes_wm_*"], "scope": "仓库维度;WMS 可按仓库配置出入库/调拨/盘点是否走 BPM"},
    {"role": "质检员", "modules": ["MES-QC"], "operations": ["IQC/IPQC/OQC/RQC 检验", "NCR 评审处置"], "data": ["mes_qc_*"], "scope": "inspectorUserId 归属"},
    {"role": "设备员/维修工", "modules": ["MES-DV"], "operations": ["点检保养", "维修工单", "工装领用"], "data": ["mes_dv_*", "mes_tm_*"], "scope": "chargeUserId 归属"},
    {"role": "客服/售后工程师", "modules": ["售后"], "operations": ["工单受理派工", "维修", "退货申请"], "data": ["after_sale_*"], "scope": "行级数据权限四视图:我负责/我参与/下属负责/全部(aftersales:view-all)"},
    {"role": "财务", "modules": ["ERP", "CRM"], "operations": ["收款单", "付款单", "开票审核", "结算账户"], "data": ["erp_finance_*", "crm_invoice", "crm_receivable"], "scope": "financeUserId 归属"},
    {"role": "HR", "modules": ["HRM"], "operations": ["员工档案入转调离", "考勤规则排班", "薪酬核算发放", "离职交接"], "data": ["hrm_*"], "scope": "部门范围 dataScope"},
    {"role": "管理层", "modules": ["BI"], "operations": ["查看采购销售/仓库/生产设备/质量/人力五大主题大屏"], "data": ["bi_dashboard"], "scope": "只读"}
  ]
}</script>
<pre style="display:none" class="mmd-src" data-mmd="01-business-mindmap">
mindmap
  root((MOM 工厂数字化平台))
    基础主数据 MDM
      物料与SKU
      物料分类
      计量单位与品牌
      仓库主数据
    销售管理 CRM
      线索
      客户与联系人
      商机与阶段
      报价单
      销售合同
      开票与回款
      销售目标
      数据权限与公海
    供应商管理 SRM
      供应商档案
      准入审批
      资质证书
      招标与比价
      绩效评价
    进销存与财务 ERP
      采购申请
      采购订单
      采购来票
      销售订单
      付款单
      收款单
      结算账户
    生产管理 MES
      主生产计划 MPS
      生产工单
      生产任务
      生产报工
      工艺路线与工序
      工单BOM
      研发设计项目
      安灯
    仓储管理 MES-WM
      仓库库区库位
      到货通知
      采购入库
      生产领料与退料
      生产入库
      销售出库与退货
      转移调拨
      盘点
      库存台账与事务
      批次SN条码装箱
    质量管理 MES-QC
      IQC 来料检验
      IPQC 过程检验
      OQC 出货检验
      RQC 退货检验
      NCR 不合格品
      质检方案与指标缺陷
    智能质检报告 QC-REPORT
      报告模板与多版本
      可视化设计器
      组件绑定与判定规则
      HTML 渲染引擎
      报告出件与编号
      数据快照冻结
    设备与排班
      设备台账
      点检与保养
      维修工单
      工装夹具
      班组班次与排班
    售后服务
      售后工单
      维修记录
      退货申请
      数据权限
    人力资源 HRM
      员工档案
      请假加班调岗离职
      离职交接映射
      考勤排班汇总
      薪酬核算与发放
    协同审批 BPM
      Flowable 引擎
      业务状态回调监听
    AI 智能
      发票OCR识别
      报价单OCR识别
      质检结果判定
      物料短缺预测
      生产时长与风险预测
      交付预测
      RAG 知识库
    BI 与管理驾驶舱
      SQL 配置式大屏
      采购销售库存生产质量人力主题
    系统底座
      认证与RBAC
      数据权限
      字典
      附件中心
      定时任务与消息
</pre>
<pre style="display:none" class="mmd-src" data-mmd="02-sales-flow">
flowchart TD
  A[线索 crm_clue] -->|转化·仅一次| B[客户 crm_customer]
  B --> C[联系人 crm_contact]
  B --> D[商机 crm_business]
  D -->|自定义阶段推进| E{商机结束}
  E -->|赢单| F[报价单 QT·草稿0→已转合同10]
  E -->|输单或无效| X[结束]
  F -->|转合同·带入客户产品折扣| G[合同 HT·草稿0→审批中10]
  D -->|直接建合同| G
  G -->|BPM审批通过20| H[生成 ERP 销售订单 XSDD]
  H -->|提交BPM| I[销售订单审批·审批中15→已审核20]
  I -->|明细需生产·自动创建| J[MES 主生产计划 MPS]
  I --> K[发货通知单]
  K -->|审核通过| L[销售出库单·OQC→拣货→发运→出库完成]
  L -->|回写出库数量与状态| M[销售订单 部分出库2/全部出库3]
  G --> N[回款计划·按期数分期]
  G -->|提交BPM| O[开票 KP·审批中10→通过20·累计不超合同额]
  O -->|回款前必须先开票| P[回款 HK·创建即审批中10→手动审核20]
  P -->|校验合同剩余额与开票剩余额| N
</pre>
<pre style="display:none" class="mmd-src" data-mmd="03-purchase-flow">
flowchart TD
  S0[SRM 准入申请 AP·待提交0→审批中10→已通过40] --> S1[供应商档案 srm_supplier]
  S1 --> S2[资质证书管理]
  S1 --> S3[绩效评价·质量交付价格服务四维]
  S4[SRM 招标比价·发布→投标→开标→评标→定标] -->|定标审批通过生成订单| C3
  C1[采购申请 CGSQ·草稿0→审批中10] -->|提交BPM| C2{审批}
  C2 -->|驳回30→可重置回草稿| C1
  C2 -->|通过20且有供应商·自动生成| C3[采购订单 CGDD·审批中15→已审核20]
  C2 -->|通过20无供应商| C4[手动指定供应商生成订单]
  C4 --> C3
  C3 -->|确认收货| C5[到货通知单·草稿0→待质检2→待入库3→完成4]
  C5 -->|物料需检验·自动创建| C6[IQC 来料检验]
  C6 -->|合格1或特采2 可入库| C7[采购入库单·草稿0→待上架2→待执行3→完成4]
  C6 -->|不合格退货3| C8[供应商退货·待拣货→待执行→完成·库存扣减]
  C6 -->|不合格报废4| C9[NCR 不合格品处置]
  C7 -->|回写 inCount 与 inStatus 未入库0部分1全部2| C3
  C7 -->|回写申请明细 inCount| C1
  C3 -->|订单总价控制| C10[采购来票 FPD·累计金额≤订单总价]
  C10 -->|付款单必须关联来票| C11[付款单 FKD·审批中15→已审核20·累计付款≤来票金额]
</pre>
<pre style="display:none" class="mmd-src" data-mmd="04-production-flow">
flowchart TD
  P0[销售订单明细 needProduction=1] -->|审批通过自动创建| P1[MPS 主生产计划·草稿0→已下发1]
  P1 -->|下发或合并下发| P2[生产工单·草稿0→已确认1]
  P2 -->|按工艺路线工序自动生成| P3[生产任务×N·预备0→生产中1→部分完成2→完成4·可暂停9]
  P3 --> P4[生产领料 或 线边虚拟库备料]
  P4 --> P5[报工提交·草稿0]
  P5 -->|校验:上一道工序未报满则拦截| P5
  P5 -->|启用BPM则提交审批| P6{报工审批}
  P6 -->|驳回| P5
  P6 -->|通过且倒冲工序| P7[按工单BOM自动生成物料消耗·扣线边虚拟库FIFO允许负库存]
  P6 -->|通过且质检工序| P8[产出行待检→IPQC 过程检验]
  P6 -->|通过且非质检关键工序| P9[产品产出直接完工入库]
  P8 -->|检验合格| P10[拆合格与不合格行入库]
  P8 -->|不合格| P11[NCR 不合格品]
  P9 --> P12[进度回写·仅最后一道工序报工才更新工单已生产数量]
  P10 --> P12
  P12 -->|已生产数量≥计划数量·自动| P13[工单完成2]
  P12 -->|累计| P14[MPS 回写已生产数量并判断完成2]
  P14 -->|全部完成| P15[发布 ProductionFinishedEvent→回写销售订单生产状态]
</pre>
<pre style="display:none" class="mmd-src" data-mmd="05-quality-flow">
flowchart TD
  T1[到货通知单 或 外协入库单] --> A1[IQC 来料检验·草稿0→完成4]
  T2[报工质检工序通过后产出行] --> A2[IPQC 过程检验·草稿0→完成4]
  T3[销售出库单提交] --> A3[OQC 出货检验·草稿0→完成4]
  T4[生产退料单 或 销售退货单 或 售后退货] --> A4[RQC 退货检验·草稿0→完成4]
  A1 --> R{检验判定 MesQcCheckResultEnum}
  A2 --> R
  A3 --> R
  A4 --> R
  R -->|1 合格| Q1[允许入库·回写来源单据推进状态]
  R -->|2 特采| Q2[允许入库·并生成NCR留痕]
  R -->|3 不合格退货| Q3[生成NCR·走供应商退货或销售退货]
  R -->|4 不合格报废| Q4[生成NCR·走报废出库]
  A2 -->|合格数量| Q5[报工转完成·产出拆行入库]
  A3 -->|完成| Q6[销售出库单推进待拣货]
  A4 -->|完成| Q7[退货单推进上架或入库·售后回调结论]
  N1[NCR 待评审0] -->|评审| N2[已评审6]
  N2 -->|处置方式:退货1报废2返工3让步接收4降级使用5| N3[已处置7]
  N3 -->|关闭| N4[已关闭8]
  Q8[支撑数据:质检方案·检验指标·缺陷库·指标结果] --- A1
  Q8H["检验指标的层级可在质检指标页维护·条目类型 所属分组 公式 排序号·只允许两层·删分组级联删子项"] --- Q8
  A1 -->|出件 generate-from-qc| GATE{出件六道校验·按业务优先级只报第一处}
  A2 -->|出件 generate-from-qc| GATE
  A3 -->|出件 generate-from-qc| GATE
  A4 -->|出件 generate-from-qc| GATE
  GATE -->|000 类型非法| GE0[105_000 qcType 不在 1~4]
  GATE -->|001 单据不存在| GE1[105_001]
  GATE -->|002 未完成检验| GE2[105_002·带当前状态中文名]
  GATE -->|003 未填判定| GE3[105_003·列出四个可选判定]
  GATE -->|005 模板类型不符| GE5[105_005·两边类型中文名都给·前端按 reportType 预过滤]
  GATE -->|006 无可用检验项| GE6[105_006]
  GATE -->|通过·只允许同类型已发布模板| RP[智能质检报告平台 qcreport]
  RP --> RPT[报告模板 qc_report_template·启用0停用1]
  RPT --> RPTV[模板版本 qc_report_template_version·草稿0已发布1已停用2·当前版本不可停用 101_010]
  RPTVSAVE[设计器保存 create 或 update] -->|写入侧闸门·规则101_006 与画布安全101_009 不合格一律不落库| RPTV
  RPTVSAVE -.->|只卡新写入·存量脏画布不回溯核查| CVNOTE[画布校验覆盖三处注入面·tagName 属性名 整段CSS]
  RPTV -->|按已发布版本渲染| RPI[报告实例 qc_report_instance·编号 QR+yyyyMMdd+4位流水·按天独立]
  RPI --> SNAP[冻结 data_snapshot·判定后数据含 PASS FAIL 与合格率]
  RPI --> RHTML[render_html 完整 HTML 文档·出站已剥离事件属性与危险协议]
  RPI --> RREGEN[重新生成 regenerate·冻结快照+同一模板版本重渲·数据与编号不变·并作废已归档PDF]
  RPI --> RPDF[导出PDF 后端调Chromium打印已存HTML·归档 system_storage_attachment·recordType=qc_report_instance]
  RPI --> RUI[报告实例页 /qc/report-instance·菜单挂质量管理 parent_id=5500]
  RUI -->|权限码| RPERM["qc-report:instance:query 查询·:export 导出PDF·:delete 删除·:create 通用出件·:generate 质检单出件(menu 1075416)"]
  RUI -->|反查 businessType=mes_qc_iqc 等表名 + businessId| RBACK[同一张质检单可出多份报告·历史留痕需要·不做重复拦截]
  RUI --> RPREVIEW[详情弹窗·iframe sandbox空属性渲染 render_html·数据快照页签展示冻结 data_snapshot]
  A1 -.->|前端入口·行操作「出报告」仅 status=已完成可见| UIREP[出报告弹窗·IQC IPQC OQC RQC 四页共用]
  A2 -.->|同上| UIREP
  A3 -.->|同上| UIREP
  A4 -.->|同上| UIREP
  UIREP -->|只列 reportType 与本单一致·启用·当前版本已发布且画布非空·避免选中必被拒的组合| UIPICK[用户选模板]
  UIPICK -->|POST generate-from-qc| GATE
  UIREP -->|结果就地展示 reportNo itemCount| UIRES["undecidableCount>0 蓝色信息条(多为过程参数无判定规则·黄色会几乎每单误报)·warnings 与 errors 逐条展示·不落库事后看不到"]
  UIRES -->|查看报告列表| RUI
  RUI -->|路由 query 带入 businessType+businessId 并预填搜索| RBACK
  GATE -->|MesQcReportApi.getQcReportData| MESMAP[MES 四层取数归一·单头 / 判定依据行 max min threshold / 样品 indicator_result / 实测值 result_detail]
  MESMAP --> RCTX[报告上下文 report+inspectionItems·由后端映射器产出·前端不再自己拼]
  RCTX --> RCITEM[检验项=样品×指标交叉展开·全指标进不过滤·多样品时样品号折进 remark]
  RCTX --> RCQC[携带单据原判定 qcResult 数·qcResultText 中文·与引擎判定并存互不覆盖]
  MESMAP -->|分组项 item_type=2 与它的子项按 parent_id 还原两层·归属不看 type 也不看行序| RCTXG
  RCTXG["分组还原·组头行背组名与 formula_text 公式·组内第一行背 span=该组总行数·同组其余行 span=1 且 hidden 让位·只合并检验项目一列"] --- RCTX
  MESMAP -.->|分组项本单没有属于它的子项 / 组头本单没有行由后端补一行| RCWARN
  MESMAP -.->|指标已删 / 未录实测值(组头锚点行按定义无值·不报) / 样品超 3 个·进 warnings| RCWARN
  RCWARN[warnings 软提示·不落库·事后看不到需自行留痕] --- RCTX
  RCITEM --- RCTX
  RCQC --- RCTX
  RCTX --> RPI
  RCTX --> RUNDEC["undecidableCount 没有判定结论的项数=快照里 result 为空串的项·含无判定规则与待判定两种·不计入合格率分母与报告结论·生成时弹提示不回填"]
  RPT -->|进入设计器并带 templateId·权限 qc-report:template:ai-import| AIIMP[AI导入 qc-report/ai-import/draft]
  AISRC["源文件 扫描件照片·电子版PDF·Word(.docx) Excel(.xlsx)·txt csv"] -->|上传走 system Storage API 取 blobId·绑为 qc_report_template 附件| AIIMP
  AISRC -.->|同一模板重复导入按替换处理·先删旧附件再绑新的·连同 blob 行与磁盘文件一起清| AIIMP
  AISRC -.->|docx 的 Word 页眉页脚读取并以 页眉 页脚 标记并入识别内容·页眉在正文前页脚在正文后·同时进 warnings·扫描件照片不受影响| AIIMP
  AIIMP -->|识别·只产草稿不落库| AIRD[模板草稿 扁平组件+属性清单]
  AIHINT[积木清单每项带 hint 选型说明·来自前端注册表 aiHint·组件选型的唯一真相来源] -.->|选型以 hint 为准·有专门组件就不退用通用组件凑数| AIIMP
  AIIMP -->|表格末行的落款签署行属落款不属数据行·与原件页脚合并且人名日期留空手填·不得自造绑定键| AIRD
  AIIMP -.->|原件列比默认多或表头分两层或样品字段不同时·写进组件的 columns headerSpans fields 三个文本属性覆盖·不换组件| AIRD
  AIKEY[报告可绑定键白名单·由后端 ReportFields 反射生成·不手写] -.->|只禁编造不给可选集合模型只能猜·故全量枚举| AIIMP
  AIRD -->|人工在设计器确认·装配器编译进画布后保存| RPTV
  AIRD -.->|画布上的 ReportHeader ReportFooter 是正文里的抬头落款·与 PDF 每页重复的版式页眉页脚不是一回事| RPTV
  AIIMP -.->|表头某列自己既是列名又是上格·原件里是一格纵向合并跨住上下两层、下层那格在提取文本里写着↑同上| AIRD
  AIIMP -.->|该段标题与列名一字不差才认成纵向合并格、出 rowspan=2 一格且下层跳过该列·不一致就被当成另一层分组标题、结论二字上下各印一遍| AIRD
  RPTVSAVE -.->|设计器画布不跑绑定·组名格的 hidden 占位符会被浏览器当成真 hidden 让整行左移、末列挤成竖排细条| CVNOTE
  RPTVSAVE -.->|自定列不带宽度声明·列宽只能由最小内容宽度倒推·而值是占位符这类不含空格的长串·整表会被撑出纸张、末列挤成竖条| CVWIDTH
  CVWIDTH["故自定列的单元格带 overflow-wrap:anywhere 允许长串折行·默认列有手工宽度声明不加·实测加了反而把检验项目子项挤到 30 余像素、行高翻几倍"] --- RPTVSAVE
</pre>
<pre style="display:none" class="mmd-src" data-mmd="06-warehouse-flow">
flowchart LR
  subgraph INB [入库·事务IN·库存加]
    I1[采购入库]
    I2[生产入库单]
    I3[报工产出自动入库]
    I4[销售退货入库]
    I5[外协入库]
    I6[杂项入库]
  end
  subgraph OUTB [出库·事务OUT·库存减]
    O1[销售出库]
    O2[生产领料]
    O3[物料消耗倒冲·允许负库存]
    O4[外协发料]
    O5[生产退料回仓]
    O6[供应商退货]
    O7[杂项出库·调整或报废]
  end
  W[(库存台账 mes_wm_material_stock 物料×仓库×库区×库位×批次×供应商)]
  INB -->|getOrCreate 加数量| W
  OUTB -->|校验可用量后扣减| W
  W -->|占用预留 reservedQuantity| RES[库存占用 销售出库·领料·外协·杂项·调拨]
  MV[转移调拨·内部或外部] -->|成对事务 MOVE_OUT+MOVE_IN 在途| W
  ST[盘点 方案→任务→明细行→结果] -->|盘盈 ADJUST_IN·盘亏 ADJUST_OUT·可冻结库存| W
  W --> TX[事务流水 mes_wm_transaction 只读全量留痕]
  BT[批次 mes_wm_batch·SN码·条码·装箱嵌套] --- W
  WIP[[线边虚拟库 WIP_VIRTUAL_WAREHOUSE·懒初始化]] --- O3
  FR[四级冻结:仓库·库区·库位·库存记录] --- W
</pre>
<pre style="display:none" class="mmd-src" data-mmd="07-after-sales-flow">
flowchart TD
  F1[客户反馈·后台人工录入工单·关联客户联系人销售订单合同] --> K1[售后工单·草稿0]
  K1 -->|assignTicket 分配处理人| K2[处理中10·问题判定:一般1维修2退货3·严重度0-3]
  K2 -->|维修类| R1[维修记录·待处理0→维修中10→已完成20→已关闭30·现场返厂远程]
  R1 -->|completeRepair| K4[已完结50]
  K2 -->|退货类创建退货申请| T1[退货申请·草稿0]
  T1 -->|approveReturn 审核通过| T2[已审核20·自动创建MES销售退货单]
  T2 --> T3[MES 销售退货·草稿→待检验RQC→待上架→待入库→完成]
  T3 -->|质检结论回调 onReturnQualityFinished 合格特采退货报废| T4[已质检40]
  T3 -->|入库完成回调 onReturnInboundFinished| T5[已入库50]
  T5 -->|退款完成回调 onRefundCompleted 记录实际退款额| T6[已退款60]
  T6 --> T7[已关闭70]
  T2 -.->|状态流转中| T8[审核中10·预留未启用]
  K2 -->|退货链路联动工单| K3[待入库30→待退款40]
  K3 --> K4
  K2 -->|resolveTicket| K4
  K4 -->|closeTicket| K5[已关闭60]
  K1 -->|cancelTicket| K9[已取消99]
  K2 -->|cancelTicket| K9
  PM[数据权限 bizType+bizId+userId+级别 负责人只读读写·我负责我参与下属全部四视图] --- K1
</pre>
<pre style="display:none" class="mmd-src" data-mmd="08-module-relation">
flowchart LR
  MDM[MDM 主数据 物料单位仓库品牌分类] --> MES[MES 生产·仓储·质量·设备]
  MDM --> ERP[ERP 采购·销售·财务]
  MDM --> CRM
  CRM[CRM 线索客户商机报价合同回款] -->|合同生成销售订单| ERP
  SRM[SRM 供应商准入资质证书招标绩效] -->|定标生成采购订单| ERP
  ERP -->|确认收货生成到货通知| MES
  ERP -->|销售订单审批生成MPS| MES
  MES -->|入库出库回写单据进度| ERP
  MES -->|ProductionFinishedEvent| ERP
  MES -->|退货质检入库回调| AS[售后工单维修退货]
  CRM -->|客户主数据| AS
  HRM[HRM 员工入转调离交接考勤薪酬] -.->|expandUserIds 数据可见性扩展·接口已就绪待各模块接入| CRM
  BPM[BPM Flowable 审批引擎] -.->|状态事件回调·13个监听器| ERP
  BPM -.-> CRM
  BPM -.-> SRM
  BPM -.-> MES
  BPM -.-> HRM
  AI[AI 平台 通义千问+Milvus] -.->|发票OCR| ERP
  AI -.->|报价OCR| CRM
  AI -.->|质检判定与生产预测| MES
  MES -.->|质检单上下文·本轮由调用方传入 待 MesQcReportApi 打通| QCR[智能质检报告 qcreport 模板版本实例快照]
  QCR -.->|PDF 归档·后续轮次| STG
  MES --> BI[BI 管理驾驶舱 SQL配置大屏]
  ERP --> BI
  CRM --> BI
  HRM --> BI
  SYS[系统底座 认证·RBAC·字典·附件中心·定时任务] --- MDM
  SYS --- MES
  STG[附件中心 storage-blob+attachment 全模块统一挂附件] --- ERP
</pre>
<pre style="display:none" class="mmd-src" data-mmd="09-data-flow">
flowchart LR
  subgraph S1 [销售前端 CRM]
    CL[线索] --> CU[客户]
    CU --> BU[商机]
    BU --> QU[报价单]
    QU --> CT[合同]
    CT --> IV[开票]
    IV --> RK[回款]
    CT --> PL[回款计划]
  end
  subgraph S2 [执行链 ERP+MES]
    SO[销售订单] --> MP[MPS]
    MP --> WO[工单]
    WO --> TK[任务]
    TK --> FB[报工]
    FB --> PP[产品产出]
    PR[采购申请] --> PO[采购订单]
    PO --> AN[到货通知]
    AN --> IR[采购入库]
  end
  subgraph S3 [仓储与财务]
    ST[库存台账]
    PS[销售出库]
    RC[收款单]
    PI[采购来票] --> PA[付款单]
  end
  CT -->|generateSaleOrder 带入客户产品折扣定金·回写orderId| SO
  SO -->|审批通过带入 saleOrderId 行ID 数量 客户 交期| MP
  PO -->|确认收货带入订单行物料供应商数量| AN
  AN -->|IQC完成后生成·带入合格行| IR
  FB -->|BOM倒冲扣减| ST
  PP -->|IN事务入库| ST
  IR -->|IN事务入库·回写inCount| PO
  PS -->|OUT事务出库·回写outCount| SO
  FB -->|最后一道工序回写已生产数量| WO
  FB -->|ProductionFinishedEvent 回写生产状态| SO
  IV -->|回款强制先开票| RK
  RC -->|关联CRM客户校验| CU
  PA -->|关联来票与供应商| PI
  subgraph S4 [智能质检报告 qcreport]
    RPT[报告模板] --> RPTV[模板版本]
    RPTVSAVE[设计器保存 create 或 update] -->|写入侧闸门 规则101_006 画布安全101_009 不合格不落库| RPTV
    RPTVSAVE -.->|只卡新写入 存量脏画布不回溯核查| CVNOTE[画布校验覆盖 tagName 属性名 整段CSS 三处注入面]
    RPTV --> RPI[报告实例]
    RPI --> SNAP[数据快照冻结]
    RPI --> RHTML[HTML 渲染产物]
    RPI --> RPDF[PDF 产物]
    AISRC[源文件 扫描件照片·电子版PDF·Word Excel·txt csv] -->|上传走 system Storage API 取 blobId 并绑为模板附件| AIRD[AI 识别草稿]
    AIRD -->|人工在设计器确认后保存| RPTV
  end
  QCDOC[质检单 IQC IPQC OQC RQC] -->|generate-from-qc·带 qcType qcId templateId| QCGATE{五道校验 类型 存在 已完成 已判定 模板类型 有检验项}
  QCGATE -->|任一不过·按业务优先级只报第一处| QCERR[105_000~105_006]
  QCGATE -->|通过| MESQCAPI[MesQcReportApi 四层取数·单头 判定依据行 样品 实测值]
  MESQCAPI -->|纯函数映射器归一 含原判定 qcResult qcResultText| RPI
  MESQCAPI -.->|分组标题跳过 指标已删 未录实测值 样品超3| QCWARN[warnings 软提示·不落库]
  QCWARN -.-> RPI
  RPI -.->|undecidableCount=快照 result 为空串的项·生成时弹提示| QCFE
  RPI -.->|businessType=mes_qc_iqc 等表名 + businessId 反查·一单可出多份| QCFE
  RPT -.->|report_type 数字字符串须等于 qcType·前端据此过滤模板列表| QCGATE
  RPTV -->|模板停用后不再出新件·历史实例不受影响·当前版本不可停用 101_010| RPI
  RPT -->|进入设计器带 templateId 调 AI 导入| AIRD
  RPI -->|列表 详情 预览 打印| QCFE["前端报告页面 /qc/report-instance 已落地·iframe 渲染 render_html + 快照页签 + 导出PDF"]
  RPDF -->|归档 附件中心 recordType=qc_report_instance| PDFARCH[system_storage_attachment]
  AISRC -.->|归属 附件中心 recordType=qc_report_template| PDFARCH
  AISRC -.->|同一模板重复导入按替换处理·先删旧附件·连同 blob 行与磁盘文件一起清| PDFARCH
  QCFE -.->|权限码 qc-report:instance:query/export/delete/create 已入 system_menu| SYS1[system_menu]
  QCGATE -.->|权限码 qc-report:instance:generate 已入 system_menu id=1075416| SYS1[system_menu]
  QCDOC -.->|前端入口 行操作「出报告」仅 status=已完成可见·四页共用同一弹窗| UIREP[出报告弹窗·只列同类型 启用 且有生效版本的模板]
  UIREP -->|选模板后 POST generate-from-qc| QCGATE
  UIREP -.->|结果就地展示 reportNo itemCount 与 undecidableCount 告警| QCFE
  QCFE -.->|进入时带 businessType+businessId 路由 query·预填搜索表单的「业务单据」字段| UIREP
  RPT -.->|权限码 qc-report:template:ai-import 已入 system_menu| SYS1
</pre>
<pre style="display:none" class="mmd-src" data-mmd="10-business-object">
erDiagram
  crm_customer ||--o{ crm_business : "拥有商机"
  crm_business ||--o{ crm_sale_quotation : "形成报价"
  crm_sale_quotation |o--o| crm_contract : "转为合同"
  crm_contract ||--o| erp_sale_order : "生成销售订单"
  crm_contract ||--o{ crm_receivable_plan : "分期计划"
  crm_contract ||--o{ crm_invoice : "开票"
  crm_invoice ||--o{ crm_receivable : "凭票回款"
  erp_sale_order ||--o{ mes_pro_mps : "需生产行触发"
  mes_pro_mps ||--o{ mes_pro_work_order : "下发工单"
  mes_pro_work_order ||--o{ mes_pro_task : "按工序拆任务"
  mes_pro_task ||--o{ mes_pro_feedback : "报工"
  mes_pro_work_order ||--o{ mes_pro_work_order_bom : "工序投料BOM"
  erp_purchase_request ||--o{ erp_purchase_order : "生成采购订单"
  erp_purchase_order ||--o| mes_wm_arrival_notice : "确认收货"
  mes_wm_arrival_notice ||--o| mes_qc_iqc : "触发IQC"
  mes_wm_arrival_notice ||--o{ mes_wm_item_receipt : "生成采购入库"
  erp_sale_order ||--o{ mes_wm_product_sales : "销售出库"
  mes_wm_product_sales ||--o| mes_qc_oqc : "触发OQC"
  mes_pro_feedback ||--o| mes_qc_ipqc : "质检工序触发IPQC"
  mes_pro_feedback ||--o{ mes_wm_product_produce : "产出入库"
  mes_pro_feedback ||--o{ mes_wm_item_consume : "BOM倒冲消耗"
  mes_qc_iqc ||--o| mes_qc_ncr : "不合格生成NCR"
  mes_wm_item_receipt ||--o{ mes_wm_material_stock : "库存增加"
  mes_wm_material_stock ||--o{ mes_wm_transaction : "事务流水"
  mes_wm_material_stock }o--|| mes_wm_batch : "按批次"
  after_sale_ticket ||--o{ after_sale_return : "退货申请"
  after_sale_return ||--o| mes_wm_return_sales : "生成MES退货单"
  mdm_item ||--o{ erp_sale_order_items : "销售明细"
  mdm_item ||--o{ erp_purchase_order_items : "采购明细"
  mdm_item ||--o{ mes_wm_material_stock : "库存物料"
  srm_supplier ||--o{ erp_purchase_order : "供货"
  srm_supplier ||--o{ mes_wm_arrival_notice : "到货来源"
  erp_purchase_order ||--o{ erp_purchase_invoice : "来票"
  erp_purchase_invoice ||--o{ erp_finance_payment : "付款"
  hrm_employee ||--o| hrm_user_handover : "离职交接映射"
  qc_report_template ||--o{ qc_report_template_version : "多版本"
  qc_report_template_version ||--o{ qc_report_instance : "冻结出件版本"
</pre>
<pre style="display:none" class="mmd-src" data-mmd="11-ai-business-flow">
flowchart TD
  U1[采购员上传发票文件 blobId] --> O1{文件类型}
  O1 -->|图片 png/jpg/gif/bmp| O2[chatWithImage 多模态视觉模型]
  O1 -->|PDF| O3[PDFBox 抽取文本 → chat]
  O1 -->|txt/csv| O4[直读文本 → chat]
  O2 --> O5[JSON 发票号 抬头 供应商 金额 税率 日期]
  O3 --> O5
  O4 --> O5
  O5 --> O6[预填采购来票表单·人工确认]
  Q1[销售上传报价单 PDF/Word/Excel/图片] --> Q2[POI/PDFBox/视觉识别]
  Q2 --> Q3[JSON 报价头+产品明细行] --> Q4[预填报价单表单]
  J1[质检单头+指标结果+缺陷记录] --> J2[业务侧组装Prompt → chat]
  J2 --> J3[MdmItemApi 物料名·SrmSupplierApi 供应商名·CrmCustomerApi 客户名 拼入上下文]
  J3 --> J4[建议结果:合格/特采/退货/报废+理由+要点]
  J4 --> J5[质检员参考判定·AI不可用时提示人工判定]
  R1[工单BOM+库存可用量+已投料] --> R2[物料短缺预测·风险等级与缺口清单]
  R3[工序标准工时+设备每小时产量+传送倍率] --> R4[生产时长预测]
  R5[IPQC缺陷率+设备保养点检+物料可用率+关键工序] --> R6[生产风险预测]
  R7[进度+剩余天数+任务完成状态+客户交期] --> R8[交付预测·能否按时+置信度+延误因素]
  W1[质检员上传既有检验报告文件 blobId] --> W2{扩展名与内容判定}
  W2 -->|png/jpg/bmp/gif/webp| W3[原字节走 chatWithImage]
  W2 -->|PDF 有文本层| W4[PDFBox 抽取文本 → chat]
  W2 -->|PDF 扫描版| W5[PDFRenderer 逐页转PNG → 每页 chatWithImage]
  W2 -->|docx/xlsx| W6["POI 抽取·表格归一成稳定网格(gridSpan 补空占位 / vMerge 续格标 ↑同上)"]
  W2 -->|txt/csv| W7[直读文本 → chat]
  W2 -->|doc/xls| W8[拒绝·提示另存为 docx/xlsx]
  W3 --> W9[多页逐页识别]
  W4 --> W9
  W5 --> W9
  W6 --> W9
  W7 --> W9
  W9 --> W10["按(type,props)去重合并→扁平组件草稿+summary+warnings"]
  W10 --> W11[弹窗预览·人工确认后装进设计器画布]
  W11 --> W12[人工调整→保存为模板版本·这是唯一落库点]
  WCL[组件积木清单由前端从活注册表生成并随请求上传] --- W9
  WSAFE[只产草稿不落库·未注册type在装配阶段被跳过·永远产不出任意HTML] --- W10
  KB1[知识库文档上传URL] --> KB2[POI/Tika提取文本] --> KB3[切片约800tokens→向量化→Milvus]
  KB3 --> KB4[分段检索接口 topK+相似度阈值]
  KB4 -.-> KB5[暂未接入业务问答流程·待确认]
  MODE[模型层:通义千问为主·预留DeepSeek/OpenAI/Ollama未实现] --- O2
  NOTE[全项目无Function Calling·AI只输出结构化JSON由业务侧解析] --- J2
</pre>
 
<script type="module">
const DATA = {};
async function loadJson(key){
  try{
    const r = await fetch('data/' + (key==='business'?'business':key) + '.json', {cache:'no-store'});
    if(r.ok) return await r.json();
  }catch(e){}
  return JSON.parse(document.getElementById('data-'+key).textContent);
}
function esc(s){return String(s ?? '').replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));}
const mermaid = (await import('https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs')).default;
mermaid.initialize({startOnLoad:false, theme:'dark', securityLevel:'loose',
  themeVariables:{fontFamily:'"Segoe UI","Microsoft YaHei",sans-serif',fontSize:'13px'},
  flowchart:{useMaxWidth:true, htmlLabels:true}});
 
const mmdSrc = {};
document.querySelectorAll('pre.mmd-src').forEach(p=>{ mmdSrc[p.dataset.mmd]=p.textContent.trim(); });
 
const flowColor = {sales:'var(--c-sale)',purchase:'var(--c-erp)',production:'var(--c-prod)',quality:'var(--c-qc)',warehouse:'var(--c-wm)',aftersales:'var(--c-as)',ai:'var(--c-ai)'};
 
async function boot(){
  DATA.business = await loadJson('business');
  DATA.modules  = await loadJson('modules');
  DATA.objects  = await loadJson('objects');
  DATA.flows    = await loadJson('flows');
  DATA.roles    = await loadJson('roles');
  const b = DATA.business.project, s = DATA.business.stats;
  document.getElementById('hProject').textContent = b.name + ' · 业务全景';
  document.getElementById('hSub').textContent = b.type + ' | ' + b.mainSystem;
  document.getElementById('footer').innerHTML = DATA.business.analysisBasis + ' · 生成于 ' + DATA.business.generatedAt + ' · 维护请走技能 project-business-analysis';
  renderOverview(); renderFlows(); renderObjects(); renderRoles(); renderAI(); renderPending();
  bindNav(); bindSearch(); bindFigToolbar();
  showPage('overview');
}
 
function renderOverview(){
  const b = DATA.business.project, s = DATA.business.stats;
  const answers = DATA.business.businessAnswers;
  let html = `
  <h2 class="pt">${esc(b.name)}</h2>
  <p class="desc">${esc(b.description)}</p>
  <div class="banner">
    <div class="small muted" style="margin-bottom:4px">核心业务主线</div>
    <div class="chain"><b>主线</b> ${esc(b.coreChain)}</div>
  </div>
  <div class="grid stats">
    <div class="stat"><b>${s.businessModules}</b><span>业务模块</span></div>
    <div class="stat"><b>${s.coreObjects}</b><span>核心业务对象</span></div>
    <div class="stat"><b>${s.documentFlows}</b><span>端到端业务流程</span></div>
    <div class="stat"><b>${s.approvalListeners}</b><span>BPM 审批监听器</span></div>
    <div class="stat"><b>${s.aiCapabilities}</b><span>AI 能力</span></div>
    <div class="stat"><b>${s.wmBillTypes}</b><span>仓储出入库单据类型</span></div>
  </div>
  <h3 class="sec">业务模块</h3>
  <div class="grid cards">`;
  const targets = {crm:'flow-sales',erp:'flow-purchase',pro:'flow-production',wm:'flow-warehouse',qc:'flow-quality',aftersales:'flow-aftersales',ai:'ai',srm:'flow-purchase',mdm:'objects',dv:'objects',hrm:'objects',bpm:'relation'};
  const accs = {mdm:'var(--c-base)',crm:'var(--c-sale)',srm:'var(--c-sup)',erp:'var(--c-erp)',pro:'var(--c-prod)',wm:'var(--c-wm)',qc:'var(--c-qc)',dv:'var(--c-dv)',aftersales:'var(--c-as)',hrm:'var(--c-hrm)',bpm:'var(--c-bpm)',ai:'var(--c-ai)'};
  DATA.modules.modules.forEach(m=>{
    html += `<div class="card" style="--acc:${accs[m.key]||'#2c5cff'}" data-goto="${targets[m.key]||'panorama'}">
      <h3>${esc(m.name)}<span class="tag">${esc(m.tag)}</span></h3>
      <p>${esc(m.positioning)} — ${esc(m.problem)}</p>
      <div class="objs">核心对象:${esc(m.objects.slice(0,6).join('、'))}${m.objects.length>6?' 等':''}</div>
      <div class="objs">上游 ${esc(m.upstream.join('、')||'—')} → 下游 ${esc(m.downstream.join('、')||'—')}</div>
    </div>`;
  });
  html += `</div><h3 class="sec">业务十问(准确性自检)</h3><div class="grid cards">`;
  answers.forEach(([q,a])=>{ html += `<div class="card" style="cursor:default"><h3 style="font-size:13.5px">${esc(q)}</h3><p style="color:#b9c8dc">${esc(a)}</p></div>`; });
  html += `</div>`;
  document.getElementById('overview').innerHTML = html;
  document.querySelectorAll('#overview .card[data-goto]').forEach(c=>c.addEventListener('click',()=>showPage(c.dataset.goto)));
}
 
function flowFigHtml(f, name){
  return `<div class="fig" style="--acc:${flowColor[f.id]||'#2c5cff'}">
      <div class="bar"><span class="name">${esc(name||f.name)} · ${esc(f.mermaid)}</span>
        <div class="btns"><button data-z="-">-</button><button data-z="+">+</button><button data-z="0">重置</button><button data-fs>全屏</button></div></div>
      <div class="canvas"><div class="stage mermaid-wrap"><pre class="mermaid" data-mmd="${f.mermaid.replace(/^mermaid\//,'').replace(/\.mmd$/,'')}"></pre></div></div>
    </div>`;
}
function flowStepsHtml(f){
  return `<h3 class="sec">步骤与角色</h3>
    <table class="steps" style="--acc:${flowColor[f.id]||'#7ea6e8'}"><tr><th>阶段</th><th>动作(含真实状态流转)</th><th>角色</th></tr>
    ${f.steps.map(st=>`<tr><td class="stage">${esc(st.stage)}</td><td>${esc(st.action)}</td><td class="role">${esc(st.roles.join('、'))}</td></tr>`).join('')}
    </table>`;
}
function renderFlows(){
  DATA.flows.flows.forEach(f=>{
    if(f.id==='ai') return;
    const sec = document.getElementById('flow-'+f.id);
    if(!sec) return;
    sec.innerHTML = `<h2 class="pt">${esc(f.name)}</h2><p class="desc">${esc(f.summary)}</p>${flowFigHtml(f)}${flowStepsHtml(f)}`;
  });
}
 
function renderObjects(){
  const groups = {};
  DATA.objects.objects.forEach(o=>{ (groups[o.module]=groups[o.module]||[]).push(o); });
  let html = `<h3 class="sec">对象清单(${DATA.objects.objects.length})</h3>
  <table class="data"><tr><th style="width:120px">对象</th><th style="width:110px">所属模块</th><th>作用</th><th style="width:190px">表名</th></tr>`;
  DATA.objects.objects.forEach((o,i)=>{
    html += `<tr data-obj="${i}"><td><b style="color:#fff">${esc(o.name)}</b></td><td class="muted">${esc(o.module)}</td><td>${esc(o.doc)}</td><td class="small muted">${esc(o.table||'—')}</td></tr>`;
  });
  html += `</table>`;
  document.getElementById('objGrid').innerHTML = html;
  document.querySelectorAll('#objGrid tr[data-obj]').forEach(tr=>tr.addEventListener('click',()=>{
    const o = DATA.objects.objects[+tr.dataset.obj];
    document.getElementById('objDetail').innerHTML = `
      <h4>${esc(o.name)} <span class="muted small">· ${esc(o.module)}${o.table?' · 表 '+esc(o.table):''}</span></h4>
      <div class="kv"><b>作用</b>${esc(o.doc)}</div>
      <div class="kv"><b>上游</b>${esc((o.upstream&&o.upstream.length)?o.upstream.join('、'):'—')}</div>
      <div class="kv"><b>下游</b>${esc((o.downstream&&o.downstream.length)?o.downstream.join('、'):'—')}</div>`;
    document.getElementById('objDetail').scrollIntoView({behavior:'smooth',block:'nearest'});
  }));
}
 
function renderRoles(){
  const rs = DATA.roles;
  let html = `<h2 class="pt">角色与权限</h2><p class="desc">${esc(rs.note)}</p>
  <h3 class="sec">业务角色 → 可操作业务 → 产生数据</h3>
  <table class="data"><tr><th style="width:150px">角色</th><th style="width:130px">模块</th><th>操作</th><th style="width:180px">数据范围/机制</th></tr>
  ${rs.businessRoles.map(r=>`<tr><td><b style="color:#fff">${esc(r.role)}</b></td><td class="muted">${esc(r.modules.join('、'))}</td><td>${esc(r.operations.join(';'))}</td><td class="small">${esc(r.scope)}</td></tr>`).join('')}
  </table>
  <h3 class="sec">底座能力</h3>
  <div class="grid cards">${DATA.modules.platform.capabilities.map(c=>`<div class="card" style="cursor:default"><p style="color:#b9c8dc">${esc(c)}</p></div>`).join('')}</div>
  <p class="small muted" style="margin-top:10px">未启用模块:${esc(DATA.modules.platform.unused.join(';'))}</p>`;
  document.getElementById('roles').innerHTML = html;
}
 
function renderAI(){
  const aiFlow = DATA.flows.flows.find(f=>f.id==='ai');
  document.getElementById('ai').insertAdjacentHTML('afterbegin',
    (aiFlow? flowFigHtml(aiFlow) + flowStepsHtml(aiFlow) : '') );
  document.getElementById('aiGrid').innerHTML = DATA.business.aiCapabilities.map(a=>`
    <div class="card" style="--acc:var(--c-ai);cursor:default">
      <h3>${esc(a.name)}<span class="tag">AI</span></h3>
      <p>${esc(a.flow)}</p>
      ${a.callsApis&&a.callsApis.length?`<div class="objs">调用:${esc(a.callsApis.join(' · '))}</div>`:''}
    </div>`).join('');
}
 
function renderPending(){
  document.getElementById('pendingList').innerHTML = DATA.business.pendingConfirm.map(p=>`<li>${esc(p)}</li>`).join('');
}
 
// 渲染排队:同一时刻只跑一个 mermaid.run,避免快速切换导航时图表在隐藏容器里布局(产生 NaN transform)
let renderQueue = Promise.resolve();
function showPage(id){
  document.querySelectorAll('nav a').forEach(a=>a.classList.toggle('active', a.dataset.t===id));
  document.querySelectorAll('section.page').forEach(s=>s.classList.toggle('on', s.id===id));
  const sec = document.getElementById(id);
  const todo = sec ? [...sec.querySelectorAll('pre.mermaid[data-mmd]')].filter(p=>!p.dataset.done) : [];
  if(todo.length){
    renderQueue = renderQueue.then(async()=>{
      if(!sec.classList.contains('on')) return; // 用户已切走,下次进入再渲染
      todo.forEach(p=>{ if(mmdSrc[p.dataset.mmd]) p.textContent = mmdSrc[p.dataset.mmd]; p.removeAttribute('data-processed'); });
      try{ await mermaid.run({nodes: todo}); }
      catch(e){ todo.forEach(p=>p.textContent = 'Mermaid 渲染失败:'+e.message); return; }
      if(sec.classList.contains('on')) todo.forEach(p=>p.dataset.done='1');
    });
  }
  window.scrollTo(0,0);
}
function bindNav(){
  document.querySelectorAll('nav a').forEach(a=>a.addEventListener('click',()=>showPage(a.dataset.t)));
  document.addEventListener('click',e=>{
    const card=e.target.closest('.card[data-goto]');
    if(card) showPage(card.dataset.goto);
  });
}
function bindFigToolbar(){
  document.addEventListener('click',e=>{
    const btn=e.target.closest('.fig button');
    if(!btn) return;
    const fig=btn.closest('.fig'), stage=fig.querySelector('.stage');
    let z=parseFloat(stage.dataset.z||'1');
    if(btn.dataset.z==='+'||btn.dataset.z==='-') z=Math.min(3,Math.max(.4, z + (btn.dataset.z==='+'?.2:-.2)));
    else if(btn.dataset.z==='0') z=1;
    stage.dataset.z=z; stage.style.transform='scale('+z+')';
    if(btn.hasAttribute('data-fs')){
      if(document.fullscreenElement) document.exitFullscreen();
      else fig.requestFullscreen();
    }
  });
}
function bindSearch(){
  const input=document.getElementById('globalSearch'), box=document.getElementById('searchResult');
  const items=[];
  DATA.objects.objects.forEach(o=>items.push({type:'业务对象',name:o.name,meta:o.module+' · '+o.doc,go:()=>{showPage('objects');const idx=DATA.objects.objects.indexOf(o);const tr=document.querySelector('#objGrid tr[data-obj="'+idx+'"]');if(tr)tr.click();}}));
  DATA.flows.flows.forEach(f=>items.push({type:'业务流程',name:f.name,meta:f.summary.slice(0,60)+'…',go:()=>showPage('flow-'+f.id)}));
  DATA.modules.modules.forEach(m=>items.push({type:'业务模块',name:m.name,meta:m.positioning,go:()=>showPage('overview')}));
  DATA.roles.businessRoles.forEach(r=>items.push({type:'角色',name:r.role,meta:r.modules.join('、'),go:()=>showPage('roles')}));
  input.addEventListener('input',()=>{
    const q=input.value.trim().toLowerCase();
    if(!q){box.style.display='none';return;}
    const hit=items.filter(i=>(i.name+i.meta).toLowerCase().includes(q)).slice(0,15);
    box.innerHTML = hit.length? hit.map((h,i)=>`<div class="sr-item" data-i="${i}"><div>${esc(h.name)} <span class="sr-type">${esc(h.type)}</span></div><div class="sr-meta">${esc(h.meta)}</div></div>`).join('') : '<div class="sr-item"><span class="muted">无匹配结果</span></div>';
    box.style.display='block';
    box.querySelectorAll('.sr-item[data-i]').forEach(el=>el.addEventListener('click',()=>{hit[+el.dataset.i].go();box.style.display='none';input.value='';}));
  });
  document.addEventListener('click',e=>{ if(!e.target.closest('#globalSearchWrap')) box.style.display='none'; });
}
await boot();
</script>
</body>
</html>