tuqin
2 天以前 83dea93d02925e162ad88954b7d0ed97dd8a442a
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
<!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": 12,
    "coreObjects": 46,
    "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": "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": "生产退料/销售退货/售后退货触发,结论回调售后", "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": "排班 班组 班次 日历"}
  ]
}</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 当前仅台账不触发返工单。",
     "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": ["质量工程师"]}]},
    {"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": "文档→切片→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 不合格品
      质检方案与指标缺陷
    设备与排班
      设备台账
      点检与保养
      维修工单
      工装夹具
      班组班次与排班
    售后服务
      售后工单
      维修记录
      退货申请
      数据权限
    人力资源 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
</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 --> 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
</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 : "离职交接映射"
</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[交付预测·能否按时+置信度+延误因素]
  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>